-
Notifications
You must be signed in to change notification settings - Fork 2
Viewer
RichTextViewer is the read-only Fabric renderer for HTML and ProseMirror JSON. It prepares and measures native layout directly; it does not create an editable document handle. The viewer is New Architecture-only and requires a host with a finite positive width.
Supply exactly one of contentJSON or contentHTML. JSON may be a DocumentJSON object or an already serialized JSON string. Use the same schema that produced custom content.
import { RichTextViewer, type DocumentJSON } from '@apollohg/react-native-rich-text-editor';
const content: DocumentJSON = {
type: 'doc',
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: 'Read-only content' }],
},
],
};
export function NotePreview() {
return (
<RichTextViewer
contentJSON={content}
style={{ width: '100%' }}
onPressLink={({ href }) => openTrustedLink(href)}
onError={(error) => reportViewerError(error)}
/>
);
}Use contentHTML for an HTML source instead:
<RichTextViewer contentHTML='<p>Read-only <strong>HTML</strong>.</p>' />The TypeScript props deliberately make the two source choices exclusive. Keep the JSON object identity stable when its content has not changed so the wrapper can reuse its serialized representation.
The viewer measures to its prepared native layout. Give it a finite width through its parent or normal React Native style; do not provide a manual height, premeasure content, maintain a height cache, or use the removed containerWidth and content-height callback APIs.
In a FlatList, render the viewer as the row's natural-size content and use stable item keys. Let the list and Fabric request the native measurement at the real row width. A viewer can be remeasured when its width, source, theme, image state, or fontEnvironmentRevision changes; that is the supported path for rotation and dynamic-type changes.
collapseTrailingEmptyParagraphs defaults to true. It removes every trailing empty paragraph. A document containing only empty paragraphs collapses to zero visual height. Set it to false only when those blocks are intentional visible spacing.
The final rendered element does not add its trailing block or list spacing to the viewer height.
enableLinkTaps defaults to true, but a link becomes actionable only when onPressLink is supplied. Without that callback, link text remains readable static text and does not expose a tappable accessibility action. Set enableLinkTaps={false} to suppress interaction even when a callback exists:
<RichTextViewer
contentJSON={content}
enableLinkTaps
onPressLink={({ href, text }) => {
auditLinkTap({ href, text });
openTrustedLink(href);
}}
/>For mentions, the viewer adds the standard mention schema node itself. Configure behavior with createMentionsAddon() in the addons array. prefix controls a rendered prefix override, while trigger is available when the document's mention convention needs to be declared. A mention becomes actionable only when createMentionsAddon({ onPress }) is supplied. The callback receives the native document position, label, and parsed node attributes.
import { createMentionsAddon } from '@apollohg/react-native-rich-text-editor';
<RichTextViewer
contentJSON={content}
addons={[
createMentionsAddon({
prefix: '@',
theme: { node: { color: '#124e78', backgroundColor: '#dcefff' } },
onPress: ({ docPos, label, attrs }) => {
openMention({ docPos, label, userId: String(attrs.userId) });
},
}),
]}
/>The mention addon’s theme.node supplies the viewer's base mention style. A mentionTheme attribute already stored on an individual mention overrides that base appearance for the mention. If native data sends malformed mention attributes, onPress is skipped and onError receives non-fatal INVALID_MENTION_ATTRIBUTES.
renderImages defaults to true. Set it to false for text-only or low-bandwidth views; image blocks remain part of layout but no image resources are requested. allowBase64Images defaults to false and controls data-image admission in supported HTML parsing paths. It does not gate JSON image sources; native loading limits still apply to either source. imageLoadingPolicy applies bounded fetch, queue, timeout, byte, decode-size, and concurrency rules; Production Limits and Errors lists its defaults and hard ceilings.
<RichTextViewer
contentJSON={content}
renderImages={false}
fontEnvironmentRevision={fontRevision}
imageLoadingPolicy={{
maxSourceBytes: 4 * 1024 * 1024,
maxConcurrentRequests: 2,
maxPendingRequests: 16,
maxDecodedBytes: 16 * 1024 * 1024,
}}
onError={(error) => {
if (error.fatal) showDocumentFallback(error.message);
else reportViewerWarning(error.code);
}}
/>Increment fontEnvironmentRevision when the app changes an external font environment that the viewer cannot observe itself. A new revision invalidates prepared layout using the same content and width.
Prepared layouts are also separated by effective light/dark appearance and accessibility contrast. On iOS, remote image pixels are retained for the visible viewport and refreshed as a direct UIKit or Fabric viewer moves through an ancestor scroll view.
The native accessibility tree follows document and inline order. Headings expose heading traits, images expose their alt text, and actionable links and mentions use their shaped local geometry. A replacement layout cannot activate stale interaction targets.
onError receives { domain, code, message, fatal }. Fatal errors describe a source/configuration/layout generation that cannot render; replace or correct that input. Non-fatal resource-load errors leave the textual document usable and are appropriate for logging, placeholder UI, or a later rerender. Viewer error events are not document-handle exceptions; handle them through this callback.
Pass atoms={[cardDefinition]} to mount React components in the measured native layout. The viewer adds their node specs to its schema automatically. Unregistered custom void nodes retain native fallback rendering. Prose always stays read-only.
Atom readOnly defaults to true; atomsInteractive defaults to true independently, so cards can support playback or local expansion without document writes. To persist attribute changes, supply both readOnly={false} and onUpdateAtomAttrs, then replace the source with your saved content:
<RichTextViewer
contentJSON={content}
atoms={atomDefinitions}
readOnly={false}
onUpdateAtomAttrs={async ({ atomId, nodeType, docPos, attrs, partial }) => {
const next = await saveAtomChange({ atomId, nodeType, docPos, attrs, partial });
setContent(next);
}}
/>This callback completes an application-owned persistence request; the viewer does not mutate a document or maintain undo history. Its resolved promise does not guarantee updated content has rendered. Declare an atom idAttribute for durable identity across source replacements and use atomId for persistence; docPos belongs to the displayed snapshot. Requests for one atom run serially and stale queued requests are rejected after source or layout configuration changes. Errors thrown by your handler reach the atom’s returned promise and updateError.
Use atomViewport={{ y, height, overscan }} to opt into unmounting offscreen React atom renderers, with coordinates relative to viewer content. Native document layout remains allocated. Focused, pending, and setActive(true) cards stay mounted; unpinned local component state can reset when scrolled away. See Custom Atom Nodes for identity, recovery, and update semantics.
The viewer uses the same flat EditorStyleSheet.create() theme as the editor. For example, set text: { color, fontSize }, h1: { fontSize }, or image: { borderRadius }. Individual style slots accept arrays and conditional entries. The separate addons array accepts definitions such as createMentionsAddon() and the optional code-highlighting addon. See Styling, Addons, and Code Syntax Highlighting.
| Prop | Default | Use |
|---|---|---|
schema |
defaultSchema, with mention support composed |
Provide the schema for custom roots, nodes, and marks; registered atom definitions are composed automatically. |
theme |
native defaults | Flat document style slots; see EditorTheme Reference. |
atoms |
none | React custom block renderers. |
readOnly |
true |
Prevent persisted atom updates; prose is always read-only. |
atomsInteractive |
true |
Enable atom controls independently of mutation permission. |
atomViewport |
none | Opt into React atom virtualization. |
onUpdateAtomAttrs |
none | Persist requested atom changes and supply updated content. |
collapseTrailingEmptyParagraphs |
true |
Remove trailing empty paragraphs and collapse an all-empty document. |
enableLinkTaps |
true |
Permit link interaction when onPressLink is also supplied. |
renderImages |
true |
Enable image resource loading and rendering. |
fontEnvironmentRevision |
0 |
Bump to invalidate layout after an external font-environment change. |
addons |
none | Addon array for mentions and optional code highlighting. |
For the full prop and event type signatures, see RichTextViewer Reference.
React Native Rich Text Editor · Documentation · Migration Guide