-
Notifications
You must be signed in to change notification settings - Fork 2
NativeProseViewer Reference
NativeProseViewer renders read-only native rich text from either ProseMirror document JSON or HTML. It uses the same rendering stack as the editor, minus selection, text input, and toolbar state.
import { NativeProseViewer } from '@apollohg/react-native-prose-editor';
<NativeProseViewer contentJSON={documentJson} />;
<NativeProseViewer contentHTML="<p>Hello from HTML</p>" />;Unlike NativeRichTextEditor, the viewer is read-only. Pass exactly one of contentJSON or contentHTML — the props are mutually exclusive.
interface NativeProseViewerProps {
contentJSON?: DocumentJSON | string;
contentHTML?: string;
contentRevision?: string | number;
contentJSONRevision?: string | number;
schema?: SchemaDefinition;
theme?: EditorTheme;
style?: StyleProp<ViewStyle>;
allowBase64Images?: boolean;
collapseTrailingEmptyParagraphs?: boolean;
enableLinkTaps?: boolean;
contentId?: string;
containerWidth?: number;
mentionPrefix?:
| string
| ((mention: NativeProseViewerMentionRenderContext) => string | null | undefined);
resolveMentionTheme?: (
mention: NativeProseViewerMentionRenderContext
) => EditorMentionTheme | null | undefined;
onPressLink?: (event: NativeProseViewerLinkPressEvent) => void;
onPressMention?: (event: NativeProseViewerMentionPressEvent) => void;
}| Prop | Type | Default | Description |
|---|---|---|---|
contentJSON |
DocumentJSON | string |
— | Document JSON to render. A string value must be serialized ProseMirror JSON, not HTML. Mutually exclusive with contentHTML. |
contentHTML |
string |
— | HTML rendered through the editor's native HTML parser. Mutually exclusive with contentJSON. |
contentRevision |
string | number |
— | Revision hint paired with contentJSON or contentHTML. Bump it to force a fresh render cycle even when the input value reference hasn't changed. |
contentJSONRevision |
string | number |
— | Deprecated alias for contentRevision. If both are set, contentRevision wins. |
schema |
SchemaDefinition |
tiptapSchema |
Schema used to normalize and render the document. |
theme |
EditorTheme |
— | Theme object for text, lists, mentions, and other rendering tokens. See EditorTheme Reference. |
style |
StyleProp<ViewStyle> |
— | Style applied to the native viewer surface (width, margin, border, background, etc.). |
allowBase64Images |
boolean |
false |
Opt-in support for data:image/... sources. Mirrors the editor's image behavior. |
collapseTrailingEmptyParagraphs |
boolean |
true |
Drops trailing top-level empty paragraphs from the render output. The source contentJSON is not modified. |
enableLinkTaps |
boolean |
true |
Makes rendered link text tappable. With no onPressLink, taps open the URL through the platform default handler. |
contentId |
string |
— | Stable identifier for this content (e.g. message ID). Paired with containerWidth, the viewer pre-measures and caches its height so it doesn't flash at zero height on mount. See Eliminating Height Flash in Lists. |
containerWidth |
number |
— | Container width in points. Used with contentId for height pre-measurement. |
mentionPrefix |
string | ((mention) => string | null | undefined) |
— | Prefix prepended to the rendered mention label. Skipped when the label already starts with it. |
resolveMentionTheme |
(mention) => EditorMentionTheme | null | undefined |
— | Per-mention theme override, resolved from the mention node's attrs and document position. |
onPressLink |
(event: NativeProseViewerLinkPressEvent) => void |
— | Called when the user taps a rendered link. Providing this handler suppresses the platform default open behavior — the callback owns the tap. |
onPressMention |
(event: NativeProseViewerMentionPressEvent) => void |
— | Called when the user taps a rendered mention node. |
- Pass exactly one of
contentJSONorcontentHTML. -
contentJSONaccepts aDocumentJSONobject or a serialized JSON string. Whole-document inputs normalize{ type: 'doc', content: [] }to a schema-valid empty document for the active schema. -
contentHTMLaccepts an HTML string parsed by the native HTML parser before rendering. - Pair the input with
contentRevisionto force a re-render without changing the value reference. - Trailing empty paragraphs are dropped from the render output by default. Set
collapseTrailingEmptyParagraphs={false}to keep them. - Link taps are on by default.
enableLinkTaps={false}disables them entirely (no platform open, noonPressLink). - Mention support is merged into the render schema, so mention nodes render and
onPressMentionfires for taps. -
mentionPrefix,resolveMentionTheme, and theattrsononPressMentionresolve from the source JSON. WithcontentHTML, mention taps still fire butattrsis empty — there is no source JSON to enrich from. -
onPressMentionreceives the label after anymentionPrefixhas been applied. - Malformed JSON strings fall back to an empty render and log an error.
<NativeProseViewer
contentHTML={`
<p>Hello <strong>world</strong></p>
<p><a href="https://example.com">Example link</a></p>
`}
/>The viewer measures its rendered native content and grows to match that height. There is no internal scrolling mode.
If the viewer mounts before its final width is known, it discards the stale measurement and remeasures once the layout width changes. This matters for message previews, modals, and other containers that settle their width late.
Wrap the viewer in your screen's ScrollView, FlatList, or other container when the document should scroll as part of a larger layout.
In a FlatList, each viewer briefly renders at zero height before native measurement finishes. With many items (e.g. a chat screen) this collapses and re-expands the whole list. Pass contentId and containerWidth to fix this:
const [containerWidth, setContainerWidth] = useState<number | null>(null);
<FlatList
onLayout={(e) => setContainerWidth(e.nativeEvent.layout.width)}
data={messages}
renderItem={({ item }) => (
<NativeProseViewer
contentJSON={item.content}
contentId={item.id}
containerWidth={containerWidth ?? undefined}
/>
)}
/>;With both props set, the viewer measures content height synchronously via native text layout before rendering, and caches the result. Recycled items reuse the cached height on remount.
Call clearHeightCache() when leaving the screen to free cached heights:
import { clearHeightCache } from '@apollohg/react-native-prose-editor';
useEffect(() => {
return () => clearHeightCache();
}, []);interface NativeProseViewerLinkPressEvent {
href: string;
text: string;
}| Field | Type | Meaning |
|---|---|---|
href |
string |
URL carried by the tapped rendered link mark. |
text |
string |
Visible text the user tapped on. |
<NativeProseViewer
contentJSON={documentJson}
onPressLink={({ href, text }) => {
analytics.track('viewer_link_tap', { href, text });
openInAppBrowser(href);
}}
/>interface NativeProseViewerMentionPressEvent {
docPos: number;
label: string;
attrs: Record<string, unknown>;
}interface NativeProseViewerMentionRenderContext {
docPos: number;
label: string;
attrs: Record<string, unknown>;
}| Field | Type | Meaning |
|---|---|---|
docPos |
number |
Document position of the pressed mention node. |
label |
string |
Mention label resolved for the pressed node. |
attrs |
Record<string, unknown> |
Mention attrs from the original document JSON — IDs, user metadata, or any custom payload you stored on the node. |
<NativeProseViewer
contentJSON={documentJson}
onPressMention={({ attrs, label }) => {
openProfile({
id: String(attrs.id ?? ''),
label,
});
}}
/>;<NativeProseViewer
contentJSON={documentJson}
mentionPrefix={({ attrs }) => (attrs.kind === 'user' ? '@' : '#')}
resolveMentionTheme={({ attrs }) =>
attrs.id === 'vip-1'
? {
textColor: '#fff7ed',
backgroundColor: '#c2410c',
fontWeight: '700',
}
: undefined
}
/>Per-mention overrides merge over the base theme.mentions tokens, so you can style specific nodes without duplicating the shared tokens.
Copyright © 2026 Apollo Health Group Pty. Ltd.