Readonly mode
Render a document without editing, what still works in a readonly view, and how to switch between readonly and editable.
A readonly view renders the same block tree as an editable one, with the same plugins, snippets and styles, but refuses every edit. Use it to display documents, to lock an editor while saving, or to show a document to people without write access.
<script lang="ts">
import { Edytor } from 'edytor';
let { value } = $props();
</script>
<Edytor readonly {value} />
There is no separate renderer: readonly is the editable editor with contenteditable="false" on its root and aria-readonly="true". It is also the way to server-render a document.
What still works
- Selecting text with the mouse. The selection is tracked as in an editable view:
edytor.selection.valueandonSelectionChangefollow it. - Copying. Mod+C writes the same clipboard formats as an editable view (Edytor’s own format, HTML and plain text). See Clipboard.
- Keys the browser handles: arrows, Home/End, PageUp/PageDown, Escape, Mod+A and Mod+C keep their native behavior.
- Live updates. The view re-renders when the document changes: collaborators’ edits, and facade operations your code runs on the document.
- Controls inside blocks (links, buttons and inputs a snippet renders) stay interactive.
What is turned off
- Typing, Backspace, Delete, Enter and Tab are blocked.
- Hotkeys don’t run, neither the built-in ones (undo, select-all ladder, nesting) nor the plugins’ (Mod+B, …).
- Cut, paste and drop are ignored.
- Every handle command is refused: after a call,
edytor.dispatcher.last.statusis'refused'. That includesblock.setData, assigningblock.typeandatom.setData, so a control’s document write needs no readonly check. The refusal covers only the write: a control that does something else first, such as uploading a file or calling your server, must checkedytor.readonlyitself. The image plugin shows a passive placeholder in a readonly view for this reason.canMoveBlocksanswersfalse. - Block handles (the
+and the grip) are hidden and dragging is disabled, so the block menu cannot open. The slash menu and the selection toolbar stay closed, and to-do checkboxes do not toggle. - A
syncprop is not attached. To show collaborative content read-only, pass adocumentthat has its sync attached (see Collaboration).
Facade operations are document writes and are not affected by the view’s readonly: code can still change the document, and every view shows the change.
When a document that collaborators emptied is shown, a readonly view displays an empty paragraph without writing one.
Switching at runtime
readonly is one of the few props that follow updates. Toggling it keeps the same instance, document and selection:
<script lang="ts">
import { Edytor } from 'edytor';
let editing = $state(false);
</script>
<button onclick={() => (editing = !editing)}>{editing ? 'Done' : 'Edit'}</button>
<Edytor readonly={!editing} />
edytor.readonly reflects the prop; change the prop rather than the instance field. Block handles appear and disappear with it.
A view created readonly never attaches its sync, even after you switch it to editable. If a view can become editable, create the document yourself and pass it as document.
Read-only documents
Separately from the view’s readonly, a document can be read-only: for example when it received content it could not admit. Commands then refuse in every view of it. document.writable tells you which state it is in; see Collaboration.