The Markdown content to render.
| Type | Default Value | Platform |
|---|---|---|
string |
Required | Both |
Style configuration for Markdown elements. See the Style Properties Reference for a detailed overview of all available style properties.
| Type | Default Value | Platform |
|---|---|---|
MarkdownStyle |
{} |
Both |
Style for the container view.
| Type | Default Value | Platform |
|---|---|---|
ViewStyle |
- | Both |
Callback when a link is pressed. Access URL via event.url.
| Type | Default Value | Platform |
|---|---|---|
(event: LinkPressEvent) => void |
- | Both |
Note: For handling long-press gestures on links, see
onLinkLongPress. On iOS, providingonLinkLongPressautomatically disables the system link preview.
Example:
<EnrichedMarkdownText
markdown="Check out [React Native](https://reactnative.dev)!"
onLinkPress={({ url }) => {
Alert.alert('Link pressed', url);
Linking.openURL(url);
}}
/>Callback when a link is long pressed. Access URL via event.url. On iOS, automatically disables the system link preview.
| Type | Default Value | Platform |
|---|---|---|
(event: LinkLongPressEvent) => void |
- | Both |
Example:
<EnrichedMarkdownText
markdown="Check out [React Native](https://reactnative.dev)!"
onLinkLongPress={({ url }) => {
Alert.alert('Link long pressed', url);
}}
/>Callback when a task list checkbox is tapped. Receives index (0-based), checked (new state after toggling), and text (item text).
| Type | Default Value | Platform |
|---|---|---|
(event: TaskListItemPressEvent) => void |
- | Both |
Controls the native link preview on long press (iOS only). Automatically set to false when onLinkLongPress is provided.
| Type | Default Value | Platform |
|---|---|---|
boolean |
true |
iOS |
By default, long-pressing a link on iOS shows the native system link preview. When you provide onLinkLongPress, the system preview is automatically disabled so your handler can fire instead.
You can also control this behavior explicitly without providing a handler:
// Disable system link preview without providing a handler
<EnrichedMarkdownText
markdown={content}
enableLinkPreview={false}
/>Whether text can be selected.
| Type | Default Value | Platform |
|---|---|---|
boolean |
true |
Both |
Color of the text selection highlight. On iOS, this also affects the caret and selection handle colors (they share a single tint). On macOS, only the selection background is affected. On Android, use selectionHandleColor to override the handle color independently.
| Type | Default Value | Platform |
|---|---|---|
ColorValue |
- | Both, macOS, Web |
Color of the selection handles (drag anchors). No-op on Android API levels below 29.
| Type | Default Value | Platform |
|---|---|---|
ColorValue |
- | Android |
Configuration for md4c parser extension flags.
| Type | Default Value | Platform |
|---|---|---|
Md4cFlags |
{ underline: false, superscript: false, subscript: false, latexMath: true } |
Both |
Properties:
underline: Whentrue, treats_text_as underline instead of emphasis. When enabled, only*text*works for italic emphasis.superscript: Whentrue, parses^text^as superscript. Visual appearance can be tuned with thesuperscriptstyle prop — see Superscript-specific.subscript: Whentrue, parses~text~as subscript. When disabled, single and double tildes remain strikethrough markers. Visual appearance can be tuned with thesubscriptstyle prop — see Subscript-specific.latexMath: Whentrue, parses$...$and$$...$$as LaTeX math spans.
Example:
// Default: _text_ is treated as italic
<EnrichedMarkdownText
markdown="This is _italic_ text"
/>
// With underline enabled: _text_ is underlined, *text* is italic
<EnrichedMarkdownText
markdown="This is _underlined_ and *italic* text"
md4cFlags={{ underline: true }}
/>Whether fonts should scale to respect Text Size accessibility settings.
| Type | Default Value | Platform |
|---|---|---|
boolean |
true |
Both |
Maximum font scale multiplier when allowFontScaling is enabled.
| Type | Default Value | Platform |
|---|---|---|
number |
undefined |
Both |
Whether to preserve the bottom margin of the last block element.
| Type | Default Value | Platform |
|---|---|---|
boolean |
false |
Both |
Markdown flavor. Set to 'github' to enable GitHub Flavored Markdown table support.
| Type | Default Value | Platform |
|---|---|---|
'commonmark' | 'github' |
'commonmark' |
Both |
Note:
'commonmark': All Markdown content is rendered as a single TextView. Selecting text will select all content in the view.'github': The Markdown AST is split into segments. Consecutive text blocks (paragraphs, headings, lists, etc.) are grouped into separate TextView segments, while tables are rendered as separate table views. This allows for granular text selection within each segment and enables interactive table features (horizontal scrolling, context menus). Text selection cannot span across segments.
When true, newly appended content fades in during streaming updates. Only the tail (new characters beyond the previous content) is animated. Recommended for LLM streaming use cases.
| Type | Default Value | Platform |
|---|---|---|
boolean |
false |
Both |
Configuration for streaming behavior. Currently controls how incomplete tables are handled during streaming with flavor="github".
| Type | Default Value | Platform |
|---|---|---|
{ tableMode: string } |
{ tableMode: 'progressive' } |
Both |
Controls how incomplete (still-streaming) tables are rendered:
'progressive'(default): The table is rendered row-by-row as content arrives. Requires at least a header row and separator line before anything is shown. Incomplete trailing rows (missing closing|or fewer columns than the header) are trimmed. New rows fade in with animation whenstreamingAnimationis also enabled.'hidden': The entire table is hidden until it is complete (followed by a blank line). This prevents visual jank from partially formed tables.
<EnrichedMarkdownText
markdown={streamingMarkdown}
flavor="github"
streamingAnimation
streamingConfig={{ tableMode: 'hidden' }}
/>Controls how spoiler text (||hidden text||) is displayed before being revealed.
| Type | Default Value | Platform |
|---|---|---|
'particles' | 'solid' |
'particles' |
Both |
'particles': Animated particle overlay (CAEmitterLayer on iOS, Choreographer-driven Canvas particles on Android).'solid': Opaque rectangle covering the text (Discord-style).
Both modes support tap-to-reveal.
Custom items to add to the text selection context menu. Items appear before the system actions (Copy, etc.). Items with visible: false are hidden from the menu.
iOS: Requires iOS 16+. On earlier versions the prop is ignored.
| Type | Default Value | Platform |
|---|---|---|
ContextMenuItem[] |
- | Both |
ContextMenuItem shape:
interface ContextMenuItem {
/** Label shown in the context menu. */
text: string;
/**
* SF Symbol name for the icon shown next to the item label.
* Supported on iOS and macOS. Ignored on Android.
* Example: 'sparkles', 'translate', 'doc.text'
*/
icon?: string;
/** Called when the item is tapped. */
onPress: (event: {
/** The selected text at the time of the press. */
text: string;
/** Absolute character range of the selection within the full content. */
selection: { start: number; end: number };
}) => void;
/** When false, the item is not shown in the menu. Defaults to true. */
visible?: boolean;
}Example:
<EnrichedMarkdownText
markdown={content}
contextMenuItems={[
{
text: 'Summarize with AI',
onPress: ({ text }) => {
console.log('Selected:', text);
},
},
{
text: 'Translate',
onPress: ({ text }) => {
translate(text);
},
},
]}
/>Controls built-in actions added to the native text selection menu. Custom app-provided actions are controlled separately with contextMenuItems.
| Type | Default Value | Platform |
|---|---|---|
SelectionMenuConfig |
{ copyAsMarkdown: true, copyImageUrl: true } |
iOS, Android, macOS |
SelectionMenuConfig shape:
interface SelectionMenuConfig {
/** Shows the built-in "Copy as Markdown" action for text selections. */
copyAsMarkdown?: boolean;
/** Shows the built-in "Copy Image URL" action when selected content contains images. */
copyImageUrl?: boolean;
}Example:
<EnrichedMarkdownText
markdown={content}
selectionMenuConfig={{
copyAsMarkdown: false,
copyImageUrl: false,
}}
/>Note: When using
flavor="github",selection.startandselection.endare relative to the text segment the selection is in, not the full markdown string. Withflavor="commonmark"(default) they are always absolute within the full rendered text.
Initial Markdown content for the input. The Markdown is parsed and formatting is applied on mount.
| Type | Default Value | Platform |
|---|---|---|
string |
- | Both |
Placeholder text displayed when the input is empty.
| Type | Default Value | Platform |
|---|---|---|
string |
- | Both |
Color of the placeholder text.
| Type | Default Value | Platform |
|---|---|---|
ColorValue |
- | Both |
Whether the input is editable.
| Type | Default Value | Platform |
|---|---|---|
boolean |
true |
Both |
Whether the input should be focused on mount.
| Type | Default Value | Platform |
|---|---|---|
boolean |
false |
Both |
Whether the input is scrollable when content exceeds the visible area.
| Type | Default Value | Platform |
|---|---|---|
boolean |
true |
Both |
Auto-capitalization behavior.
| Type | Default Value | Platform |
|---|---|---|
string |
'sentences' |
Both |
Whether the input supports multiple lines.
| Type | Default Value | Platform |
|---|---|---|
boolean |
true |
Both |
Color of the text cursor.
| Type | Default Value | Platform |
|---|---|---|
ColorValue |
- | Both |
Color of the text selection highlight.
| Type | Default Value | Platform |
|---|---|---|
ColorValue |
- | Both |
Style configuration for formatted text in the input.
| Type | Default Value | Platform |
|---|---|---|
MarkdownTextInputStyle |
{} |
Both |
Properties:
strong.color— text color for bold text (defaults to the input's text color).em.color— text color for italic text (defaults to the input's text color).link.color— text color for links (defaults to#2563EB).link.underline— whether links are underlined (defaults totrue).link.backgroundColor— background color for links (defaults totransparent).linkVariants— per-URL-pattern style overrides. Each key is a regex tested against the link URL. See Mentions — Link Variants.spoiler.color— text color for spoiler text.spoiler.backgroundColor— background color for spoiler text.
List of trigger strings that start a mention flow (e.g. ['@', '#']). See Mentions.
| Type | Default Value | Platform |
|---|---|---|
string[] |
[] |
Both |
Style for the input view. Accepts ViewStyle and TextStyle properties (e.g., fontSize, color, padding).
| Type | Default Value | Platform |
|---|---|---|
ViewStyle | TextStyle |
- | Both |
Fires when the plain text content changes. Returns the text without Markdown syntax.
| Type | Default Value | Platform |
|---|---|---|
(text: string) => void |
- | Both |
Fires when the Markdown representation changes. Returns the full Markdown string. Only active when the callback is provided — omitting it skips the serialization for better performance.
| Type | Default Value | Platform |
|---|---|---|
(markdown: string) => void |
- | Both |
Fires when the text selection changes.
| Type | Default Value | Platform |
|---|---|---|
(selection: { start: number; end: number }) => void |
- | Both |
Fires when the active style state changes. The payload provides a nested object for each style with an isActive property.
| Type | Default Value | Platform |
|---|---|---|
(state: StyleState) => void |
- | Both |
StyleState shape:
interface StyleState {
bold: { isActive: boolean };
italic: { isActive: boolean };
underline: { isActive: boolean };
strikethrough: { isActive: boolean };
spoiler: { isActive: boolean };
link: { isActive: boolean };
}Fires when the caret's pixel position changes (typing, selection change, content reflow). The rect is relative to the input's top-left corner, in density-independent pixels. The native side diffs the rect before emitting, so redundant events are suppressed.
| Type | Default Value | Platform |
|---|---|---|
(rect: CaretRect) => void |
- | Both |
CaretRect shape:
interface CaretRect {
x: number;
y: number;
width: number;
height: number;
}All values are in density-independent pixels, relative to the input's top-left corner.
Example:
<EnrichedMarkdownTextInput
scrollEnabled={false}
onCaretRectChange={(rect) => {
console.log('Caret at:', rect.x, rect.y);
}}
/>Fires when the input gains focus.
| Type | Default Value | Platform |
|---|---|---|
() => void |
- | Both |
Fires when the input loses focus.
| Type | Default Value | Platform |
|---|---|---|
() => void |
- | Both |
Fires when a new mention flow starts. See Mentions.
| Type | Default Value | Platform |
|---|---|---|
(event: { indicator: string }) => void |
- | Both |
Fires on every keystroke while a mention flow is active.
| Type | Default Value | Platform |
|---|---|---|
(event: { indicator: string; text: string }) => void |
- | Both |
Fires when the active mention flow ends.
| Type | Default Value | Platform |
|---|---|---|
(event: { indicator: string }) => void |
- | Both |
Custom items to add to the text selection context menu. Items appear before the system actions (Copy, Cut, etc.). Items with visible: false are hidden from the menu.
iOS: Requires iOS 16+. On earlier versions the prop is ignored.
| Type | Default Value | Platform |
|---|---|---|
ContextMenuItem[] |
- | Both |
ContextMenuItem shape:
interface ContextMenuItem {
/** Label shown in the context menu. */
text: string;
/**
* SF Symbol name for the icon shown next to the item label.
* Supported on iOS and macOS. Ignored on Android.
* Example: 'sparkles', 'translate', 'doc.text'
*/
icon?: string;
/** Called when the item is tapped. */
onPress: (event: {
/** The selected text at the time of the press. */
text: string;
/** Absolute character range of the selection within the full content. */
selection: { start: number; end: number };
/** Active formatting styles at the time of the press. */
styleState: {
bold: { isActive: boolean };
italic: { isActive: boolean };
underline: { isActive: boolean };
strikethrough: { isActive: boolean };
spoiler: { isActive: boolean };
link: { isActive: boolean };
};
}) => void;
/** When false, the item is not shown in the menu. Defaults to true. */
visible?: boolean;
}Example:
<EnrichedMarkdownTextInput
contextMenuItems={[
{
text: 'Summarize with AI',
onPress: ({ text, styleState }) => {
console.log('Selected:', text, 'Bold:', styleState.bold.isActive);
},
},
]}
/>All methods are called imperatively on the ref (ref.current?.methodName()).
Focuses the input.
Blurs the input.
Sets the input content from a Markdown string. Parses the Markdown and applies formatting.
Returns a Promise that resolves with the current Markdown content. The async nature is due to the native bridge — the request is sent to the native side and the result is returned via an event.
Returns a Promise that resolves with the current caret's pixel position relative to the input. Useful for one-off queries; for continuous tracking, prefer onCaretRectChange.
Sets the text selection range.
Toggles bold on the current selection. When no text is selected, the style is queued and applied to the next characters typed.
Toggles italic on the current selection or cursor.
Toggles underline on the current selection or cursor.
Toggles strikethrough on the current selection or cursor.
Toggles spoiler on the current selection or cursor.
Applies a link URL to the currently selected text.
Inserts a link with the given text and URL at the current cursor position. Useful when there is no text selection.
Removes the link from the current selection.
Programmatically triggers a mention flow by inserting the indicator character at the current cursor position. The indicator must be listed in the mentionIndicators prop. Useful for toolbar buttons.
Replaces the active mention token with a formatted link. Only works when a mention flow is active. The mention is serialized as [displayText](url) in Markdown output.
For full documentation on the mention system — setup, events, styling, and best practices — see Mentions.