react-native-enriched-markdown: Markdown Rendering Without the WebView Tax
Rendering Markdown in a React Native app has always involved tradeoffs. You either reach for a WebView (and accept the performance hit, the styling headaches, and the broken native interactions) or you use a JavaScript-based renderer that approximates native text but misses the finer details like proper text selection, accessibility, and platform-native features. react-native-enriched-markdown takes a different path entirely. Built by Software Mansion, the team behind react-native-reanimated and react-native-gesture-handler, it parses Markdown with a native C library (md4c) and renders it as genuine native text components. No WebView. No compromises.
If you are building a chat app, a documentation viewer, a note-taking tool, or anything that displays Markdown content on mobile, this library gives you native performance and native behavior out of the box.
What Makes It Tick
The standout feature is the parsing layer. Instead of parsing Markdown in JavaScript at runtime, react-native-enriched-markdown delegates to md4c, a fast CommonMark-compliant C parser. The result is parsed on the native side and rendered as actual React Native text components, which means you get everything the platform offers for free:
- Native text selection and copy, including a "Copy as Markdown" option in the context menu
- Full accessibility with VoiceOver on iOS and TalkBack on Android, including custom rotors and semantic traits
- RTL support for text, lists, blockquotes, tables, and task lists
- Platform interactions like Translate, Look Up, Search Web, and Share
- CommonMark and GFM support, including tables, task lists, autolinks, and strikethrough
- LaTeX math rendering for both block and inline equations
- Native image handling with Copy and Save to Camera Roll on iOS
One important caveat: this library requires React Native's New Architecture (Fabric). It supports RN 0.81 through 0.84. If your project is still on the old Bridge architecture, you will need to migrate first.
Getting Started
Install with your preferred package manager:
npm install react-native-enriched-markdown
yarn add react-native-enriched-markdown
For Expo projects, use the Expo CLI and run a prebuild:
npx expo install react-native-enriched-markdown
npx expo prebuild
Note that this library requires native code and will not work in Expo Go. You need a development build or a bare workflow.
On iOS, run pod install after adding the package.
Your First Rendered Markdown
The API surface is refreshingly small. There is one component, and it does exactly what you expect:
import { EnrichedMarkdownText } from "react-native-enriched-markdown";
function ArticleView() {
const content = `
# Welcome
This is **bold** and this is *italic*.
- First item
- Second item
- Third item
> A blockquote for emphasis.
`;
return <EnrichedMarkdownText markdown={content} />;
}
That is all it takes. The component parses the Markdown string and renders every element as native text. No configuration required for the basic case.
Handling Links and Interactions
Real apps need to respond to user interactions. Links are the most common case, and the component provides dedicated handlers:
import { EnrichedMarkdownText } from "react-native-enriched-markdown";
import { Linking } from "react-native";
function DocViewer({ markdownContent }: { markdownContent: string }) {
const handleLinkPress = ({ url }: { url: string }) => {
if (url.startsWith("http")) {
Linking.openURL(url);
}
};
const handleLinkLongPress = ({ url }: { url: string }) => {
// Show a custom share sheet or copy URL
console.log("Long pressed link:", url);
};
return (
<EnrichedMarkdownText
markdown={markdownContent}
onLinkPress={handleLinkPress}
onLinkLongPress={handleLinkLongPress}
/>
);
}
The onLinkPress and onLinkLongPress callbacks give you full control over navigation behavior without fighting the rendering layer.
Going Further with GFM and Styling
Tables, Task Lists, and GitHub Flavor
By default, the component uses CommonMark parsing. To unlock GitHub Flavored Markdown features like tables, task lists, autolinks, and strikethrough, set the flavor prop:
import { EnrichedMarkdownText } from "react-native-enriched-markdown";
function TaskBoard() {
const markdown = `
## Sprint Tasks
| Task | Status | Owner |
|------|--------|-------|
| Auth flow | Done | Alice |
| Dark mode | In progress | Bob |
### Checklist
- [x] Set up CI pipeline
- [x] Write unit tests
- [ ] Deploy to staging
- [ ] Final QA pass
Visit https://example.com for details.
~~This feature was removed.~~
`;
const handleTaskPress = ({
index,
checked,
text,
}: {
index: number;
checked: boolean;
text: string;
}) => {
console.log(`Task ${index}: "${text}" is now ${checked ? "checked" : "unchecked"}`);
};
return (
<EnrichedMarkdownText
markdown={markdown}
flavor="github"
onTaskListItemPress={handleTaskPress}
/>
);
}
Task list checkboxes are interactive. The onTaskListItemPress callback fires with the item index, its checked state, and the text content, so you can sync checkbox state with your backend or local storage.
Custom Styling
Every Markdown element can be styled through the markdownStyle prop. The styling API covers headings, paragraphs, code blocks, tables, math blocks, and more:
import { EnrichedMarkdownText } from "react-native-enriched-markdown";
function StyledNotes({ content }: { content: string }) {
return (
<EnrichedMarkdownText
markdown={content}
flavor="github"
markdownStyle={{
heading1: {
fontSize: 28,
fontWeight: "800",
color: "#1a1a2e",
},
heading2: {
fontSize: 22,
fontWeight: "700",
color: "#16213e",
},
paragraph: {
fontSize: 16,
lineHeight: 26,
color: "#333",
},
codeBlock: {
backgroundColor: "#f5f5f5",
fontSize: 14,
fontFamily: "JetBrainsMono-Regular",
},
inlineCode: {
backgroundColor: "#e8e8e8",
fontFamily: "JetBrainsMono-Regular",
color: "#d63384",
},
blockquote: {
borderColor: "#6c63ff",
backgroundColor: "#f0efff",
},
table: {
borderColor: "#dee2e6",
borderRadius: 8,
headerBackgroundColor: "#f8f9fa",
},
link: {
color: "#0066cc",
},
}}
/>
);
}
Table styling is particularly thorough, with properties for border color, border radius, header backgrounds, cell padding, and alternating row colors. This level of control is something you simply cannot get when Markdown lives inside a WebView without writing custom CSS and bridging it back.
LaTeX Math for Technical Content
If your app deals with scientific or mathematical content, react-native-enriched-markdown supports LaTeX math out of the box. Block equations use double dollar signs with the GFM flavor, while inline math uses single dollar signs in any flavor:
import { EnrichedMarkdownText } from "react-native-enriched-markdown";
function MathLesson() {
const content = `
## Quadratic Formula
The solutions to $ax^2 + bx + c = 0$ are given by:
$$
x = \\frac{-b \\pm \\sqrt{b^2 - 4ac}}{2a}
$$
Where $a \\neq 0$ and the discriminant $b^2 - 4ac$ determines the nature of the roots.
`;
return (
<EnrichedMarkdownText
markdown={content}
flavor="github"
markdownStyle={{
math: {
fontSize: 18,
color: "#2d2d2d",
},
}}
/>
);
}
This is a feature that none of the other popular React Native Markdown libraries offer without bolting on additional dependencies.
Things to Keep in Mind
This library is young and opinionated in its requirements. Here is what you should know before adopting it:
The New Architecture requirement is non-negotiable. If your project still uses the old Bridge architecture, you cannot use this library. Given that React Native has been pushing teams toward Fabric for some time, this is a forward-looking bet, but it does limit adoption today.
There is no web support yet. The library targets iOS and Android only. Web support via react-native-web is on the roadmap, as is macOS support, but neither is available in the current release.
A few known issues exist in v0.3.0, including occasional table content clipping during scroll and minor text measurement quirks. The maintainers are actively fixing these, with nightly builds available at version 0.4.0-nightly for those who want to test the latest patches.
Wrapping Up
react-native-enriched-markdown solves a real problem in the React Native ecosystem. By moving Markdown parsing to a native C library and rendering everything as genuine native text, it delivers the kind of experience that WebView-based solutions and JS-parsed alternatives simply cannot match. Text selection works the way users expect. Accessibility is built in rather than bolted on. Platform features like Translate and Share just work.
With Software Mansion behind it, active development pushing out releases every few weeks, and a growing feature set that already includes GFM tables, interactive task lists, LaTeX math, and full RTL support, this is a library worth watching closely. If your project is on the New Architecture, it is worth using right now.