Hooks and components for consuming remirror with your fave framework React.
Overall
score
36%
Evaluation — 36%
↑ 1.09xAgent success when using this tile
JSON-to-React rendering system for displaying editor content as React components with customizable handlers.
Main component for rendering Remirror JSON content as React components.
/**
* Main recursive JSON-to-React renderer for displaying editor content
*/
interface RemirrorRenderer extends React.Component<RemirrorRendererProps> {}
interface RemirrorRendererProps {
/** Remirror JSON document to render */
json: RemirrorJSON;
/** Custom type mapping for nodes and marks */
typeMap?: Record<string, ComponentType>;
/** Custom mark mapping */
markMap?: MarkMap;
/** Additional props to pass to rendered components */
componentProps?: Record<string, any>;
/** Error boundary component */
errorBoundary?: ComponentType<{ error: Error; children: React.ReactNode }>;
}
interface RemirrorJSON {
/** Document type */
type: 'doc';
/** Document content nodes */
content?: RemirrorJSONNode[];
/** Document attributes */
attrs?: Record<string, any>;
}
interface RemirrorJSONNode {
/** Node type */
type: string;
/** Node content */
content?: RemirrorJSONNode[];
/** Node attributes */
attrs?: Record<string, any>;
/** Node marks */
marks?: RemirrorJSONMark[];
/** Text content (for text nodes) */
text?: string;
}
interface RemirrorJSONMark {
/** Mark type */
type: string;
/** Mark attributes */
attrs?: Record<string, any>;
}Usage Example:
import React from 'react';
import { RemirrorRenderer } from '@remirror/react';
// Sample Remirror JSON content
const sampleContent = {
type: 'doc',
content: [
{
type: 'paragraph',
content: [
{
type: 'text',
text: 'Hello ',
},
{
type: 'text',
text: 'world',
marks: [{ type: 'bold' }],
},
{
type: 'text',
text: '!',
},
],
},
],
};
function ContentViewer() {
return (
<div>
<h2>Rendered Content:</h2>
<RemirrorRenderer json={sampleContent} />
</div>
);
}Document root renderer component for complete documents.
/**
* Document root renderer component for complete document rendering
*/
interface Doc extends React.Component<DocProps> {}
interface DocProps {
/** Remirror JSON document */
json: RemirrorJSON;
/** Document-level attributes */
attributes?: Record<string, any>;
/** Custom document wrapper component */
wrapper?: ComponentType<{ children: React.ReactNode }>;
}Specialized components for rendering different types of content.
/**
* Handler for rendering callout blocks
*/
interface Callout extends React.Component<CalloutProps> {}
interface CalloutProps {
/** Callout type/variant */
type?: 'info' | 'warning' | 'error' | 'success';
/** Callout title */
title?: string;
/** Callout content */
children: React.ReactNode;
/** Custom icon */
icon?: React.ReactNode;
}
/**
* Handler for rendering code blocks with syntax highlighting
*/
interface CodeBlock extends React.Component<CodeBlockProps> {}
interface CodeBlockProps {
/** Programming language for syntax highlighting */
language?: string;
/** Code content */
code: string;
/** Whether to show line numbers */
showLineNumbers?: boolean;
/** Custom theme for syntax highlighting */
theme?: string;
}
/**
* Handler for rendering heading elements
*/
interface Heading extends React.Component<HeadingProps> {}
interface HeadingProps {
/** Heading level (1-6) */
level: 1 | 2 | 3 | 4 | 5 | 6;
/** Heading content */
children: React.ReactNode;
/** Custom ID for anchor links */
id?: string;
/** Additional CSS classes */
className?: string;
}
/**
* Handler for rendering text content with marks
*/
interface TextHandler extends React.Component<TextHandlerProps> {}
interface TextHandlerProps {
/** Text content */
text: string;
/** Applied marks */
marks?: RemirrorJSONMark[];
/** Custom mark renderers */
markRenderers?: Record<string, ComponentType>;
}Usage Example:
import React from 'react';
import {
RemirrorRenderer,
Callout,
CodeBlock,
Heading
} from '@remirror/react';
function CustomContentRenderer() {
const customTypeMap = {
callout: ({ type, title, children }) => (
<Callout type={type} title={title}>
{children}
</Callout>
),
codeBlock: ({ language, code }) => (
<CodeBlock
language={language}
code={code}
showLineNumbers={true}
theme="dark"
/>
),
heading: ({ level, children, id }) => (
<Heading level={level} id={id}>
{children}
</Heading>
),
};
const content = {
type: 'doc',
content: [
{
type: 'heading',
attrs: { level: 1 },
content: [{ type: 'text', text: 'Welcome' }],
},
{
type: 'callout',
attrs: { type: 'info', title: 'Note' },
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: 'This is important!' }],
},
],
},
],
};
return (
<RemirrorRenderer
json={content}
typeMap={customTypeMap}
/>
);
}Factory functions for creating specialized content handlers.
/**
* Factory for creating iframe handlers
* @param options - Iframe configuration options
* @returns Iframe handler component
*/
function createIFrameHandler(
options: IFrameHandlerOptions
): ComponentType<IFrameProps>;
interface IFrameHandlerOptions {
/** Allowed domains for iframes */
allowedDomains?: string[];
/** Default iframe attributes */
defaultAttributes?: Record<string, string>;
/** Security settings */
sandbox?: string[];
/** Error fallback component */
errorFallback?: ComponentType;
}
interface IFrameProps {
/** Iframe source URL */
src: string;
/** Iframe title */
title?: string;
/** Iframe dimensions */
width?: number | string;
height?: number | string;
/** Additional attributes */
attributes?: Record<string, string>;
}
/**
* Factory for creating link handlers
* @param options - Link configuration options
* @returns Link handler component
*/
function createLinkHandler(
options: LinkHandlerOptions
): ComponentType<LinkProps>;
interface LinkHandlerOptions {
/** Whether to open external links in new tab */
openExternalInNewTab?: boolean;
/** Custom link click handler */
onClick?: (href: string, event: React.MouseEvent) => void;
/** Link validation function */
validateLink?: (href: string) => boolean;
/** Custom link styling */
className?: string;
}
interface LinkProps {
/** Link destination */
href: string;
/** Link text content */
children: React.ReactNode;
/** Link title attribute */
title?: string;
/** Whether link is external */
external?: boolean;
}Usage Example:
import React from 'react';
import {
RemirrorRenderer,
createIFrameHandler,
createLinkHandler
} from '@remirror/react';
function SafeContentRenderer() {
const safeIFrameHandler = createIFrameHandler({
allowedDomains: ['youtube.com', 'vimeo.com'],
sandbox: ['allow-scripts', 'allow-same-origin'],
errorFallback: () => <div>Iframe not allowed</div>,
});
const customLinkHandler = createLinkHandler({
openExternalInNewTab: true,
onClick: (href, event) => {
console.log('Link clicked:', href);
},
validateLink: (href) => !href.includes('malicious'),
});
const typeMap = {
iframe: safeIFrameHandler,
link: customLinkHandler,
};
const content = {
type: 'doc',
content: [
{
type: 'paragraph',
content: [
{
type: 'text',
text: 'Check out this video: ',
},
{
type: 'link',
attrs: { href: 'https://youtube.com/watch?v=example' },
content: [{ type: 'text', text: 'YouTube Video' }],
},
],
},
],
};
return (
<RemirrorRenderer
json={content}
typeMap={typeMap}
/>
);
}/**
* Mapping of marks to React components for rendering
*/
type MarkMap = Record<string, ComponentType<MarkProps>>;
interface MarkProps {
/** Mark attributes */
attrs?: Record<string, any>;
/** Content to wrap with the mark */
children: React.ReactNode;
/** Mark type name */
markType: string;
}
/**
* Create a custom mark renderer
* @param markType - The mark type to handle
* @param component - React component to render the mark
* @returns Mark renderer function
*/
function createMarkRenderer(
markType: string,
component: ComponentType<MarkProps>
): (props: MarkProps) => React.ReactNode;/**
* Context for renderer components to access parent renderer state
*/
interface RendererContext {
/** Current document being rendered */
document: RemirrorJSON;
/** Current rendering path */
path: number[];
/** Type mappings */
typeMap: Record<string, ComponentType>;
/** Mark mappings */
markMap: MarkMap;
/** Renderer options */
options: RendererOptions;
}
interface RendererOptions {
/** Whether to sanitize HTML attributes */
sanitizeAttributes?: boolean;
/** Maximum nesting depth */
maxDepth?: number;
/** Error handling mode */
errorMode?: 'throw' | 'render' | 'ignore';
}
/**
* Hook to access renderer context
* @returns Current renderer context
*/
function useRendererContext(): RendererContext;/**
* Optimized renderer for large documents
*/
interface OptimizedRenderer extends React.Component<OptimizedRendererProps> {}
interface OptimizedRendererProps extends RemirrorRendererProps {
/** Whether to use virtual scrolling */
virtualScrolling?: boolean;
/** Chunk size for rendering */
chunkSize?: number;
/** Whether to lazy load content */
lazyLoad?: boolean;
/** Intersection observer options for lazy loading */
observerOptions?: IntersectionObserverInit;
}
/**
* Memoized content renderer for better performance
* @param props - Renderer props
* @returns Memoized renderer component
*/
const MemoizedRenderer: React.MemoExoticComponent<
React.ComponentType<RemirrorRendererProps>
>;Usage Example:
import React from 'react';
import {
OptimizedRenderer,
MemoizedRenderer,
useRendererContext
} from '@remirror/react';
function LargeDocumentRenderer({ json }) {
return (
<OptimizedRenderer
json={json}
virtualScrolling={true}
chunkSize={50}
lazyLoad={true}
observerOptions={{
threshold: 0.1,
rootMargin: '50px',
}}
/>
);
}
function CustomNodeRenderer({ children }) {
const context = useRendererContext();
const isNested = context.path.length > 3;
return (
<div className={isNested ? 'nested-content' : 'top-level-content'}>
{children}
</div>
);
}docs
evals
scenario-1
scenario-2
scenario-3
scenario-4
scenario-5
scenario-6
scenario-7
scenario-8
scenario-9
scenario-10