Install
npm install @screenjson/ui
A reusable wrapper
import { useEffect, useRef } from 'react';
import ScreenJSONUI, { type ScreenJSONDocument } from '@screenjson/ui';
type Props = {
src?: string;
document?: ScreenJSONDocument;
theme?: 'light' | 'dark';
className?: string;
};
export function ScreenplayViewer({ src, document, theme = 'light', className }: Props) {
const ref = useRef<HTMLDivElement | null>(null);
const instance = useRef<ScreenJSONUI | null>(null);
useEffect(() => {
if (!ref.current) return;
instance.current = new ScreenJSONUI({
element: ref.current,
src, document, theme, virtual: true,
});
return () => instance.current?.destroy?.();
}, [src, document, theme]);
return <div ref={ref} className={className} />;
}
Use it
<ScreenplayViewer src="/screenplay.json" theme="dark" className="h-screen" />
Or with an inline object:
import doc from './screenplay.json';
<ScreenplayViewer document={doc} />
Loading state
Because the viewer takes over its container, put a loader in a parent wrapper until your document fetch settles:
{doc ? <ScreenplayViewer document={doc} /> : <Spinner />}
SSR notes
The viewer is a DOM-first component — render it only on the client:
- In Next.js: use
dynamic(() => import('./ScreenplayViewer'), { ssr: false }). - In Remix: gate on a
useHydrated()check.