# Read-only viewer
> Lock the editor for preview. Selection, zoom, and export still work.
Source: https://docs.docmosaic.com/docs/examples/read-only
`Editor.Root readOnly` flips the editor into viewer mode. Drag, drop, resize, file upload, and every mutating keybinding (`Delete`, `mod+z`, arrow nudge) are suppressed. Selection, zoom, preview, print, and PDF download stay live - read-only is about mutation, not navigation.
Use it for embedding a finished contract for review, showing a "preview before commit" step, or rendering a snapshot beside an editable canvas in a compare view.
## Code
```tsx
'use client';
import { Editor } from '@docmosaic/react';
import { type Document } from '@docmosaic/core';
import '@docmosaic/react/styles.css';
interface DocumentViewerProps {
/** Pre-built snapshot to display. */
document: Document;
}
export default function DocumentViewer({ document }: DocumentViewerProps) {
return (
{/* Add/Undo/Redo buttons render `null` automatically in readOnly mode. */}
);
}
```
The toolbar's mutating buttons (`AddImageButton`, `AddTextButton`, `DrawButton`, `UndoButton`, `RedoButton`) hide themselves when the root is `readOnly`. You don't need to conditionally render them.
For a side-by-side "current vs reference" view, mix an editable canvas with
`Editor.StaticCanvas` - same root, two surfaces, one frozen. See the [read-only
recipe](/docs/recipes/read-only) for the pattern.
## Detecting read-only in custom primitives
If you're writing your own toolbar button, read the flag from the editor context:
```tsx
import { useEditor } from '@docmosaic/react';
function CustomAddButton() {
const { actions, readOnly } = useEditor();
if (readOnly) return null;
return ;
}
```
## Related
- [Read-only recipe](/docs/recipes/read-only) - full behaviour matrix
- [Editor.StaticCanvas](/docs/primitives/static-canvas) - canvas-level read-only
- [Editor.Root](/docs/primitives/root) - the `readOnly` prop reference