Layout
By default every block spans the content pane. Set a measure to get a readable text column instead: paragraphs, headings, lists, quotes, code and frontmatter are capped at that width and centred in the pane, while each table and drawing chooses its own width.
<MarkdownEditor value={value} onChange={setValue} measure="48rem" />
The prop is sugar for the CSS custom property --zui-text-editor-measure,
which is the actual contract. Set it in a stylesheet on .zui-text-editor
(or any ancestor) instead of passing the prop:
.zui-text-editor {
--zui-text-editor-measure: 48rem;
}
The pane itself is never capped; full-width blocks stop short of the outline sidebar; the placeholder and fold chevrons follow the column.
Set measure (or the variable) and delete any external max-width /
margin-inline overrides on .zui-text-editor-content > *; the library
owns that layout.
The example is narrower than a real page, so the measure is set to 28rem
here; toggle it off to see every block span the pane:
Block width
Every table and drawing has a BlockWidth, picked from the floating table
toolbar or the right end of the drawing toolbar:
BlockWidth | Layout | Markdown |
|---|---|---|
full | The content pane, edge to edge (never under the outline sidebar). The default | Omitted |
text | The text column: edges align with the paragraphs. Identical to full until a measure is set | <!-- width: text --> / "width":"text" |
content | Shrinks to its columns / shapes, left-aligned with the text, never wider than the column | <!-- width: content --> / "width":"content" |
Absence of a marker always means full, in every app.
Insertion defaults
defaultBlockWidth only changes what the toolbar, insertTable() and
insertDrawing() write into new blocks. That value is written
explicitly, even when it is full, so the document reads the same in an
app with other defaults; a width named in the source
(<!-- width: full -->, "width":"full") is preserved on round trip.
<MarkdownEditor
measure="48rem"
defaultBlockWidth={{ table: 'text', drawing: 'text' }}
value={value}
onChange={setValue}
/>
Headless: useMarkdownEditor().blockWidth / setBlockWidth act on the
block containing the selection: the focused drawing, or else the table
the caret is in. BLOCK_WIDTHS lists the values and isBlockWidth() is
the type guard.
How the CSS works
The layout lives in zero-specificity :where() rules, so a single class
rule of yours overrides it. .zui-text-editor-main is a container and
derives two custom properties:
| Property | Meaning |
|---|---|
--zui-text-editor-gutter | The pane's horizontal padding: 2rem without a measure, otherwise whatever centres the column |
--zui-text-editor-bleed | How far a full-width block extends past the column: 0 without a measure |
Each top-level block reads --zui-text-editor-block-bleed, so one rule
changes any block kind:
/* Code blocks span the pane like tables do */
.zui-code { --zui-text-editor-block-bleed: var(--zui-text-editor-bleed); }
/* Every table stays inside the text column */
.zui-table { --zui-text-editor-block-bleed: 0px; }
Block classes: .zui-paragraph, .zui-heading (+ .zui-heading-1 …
.zui-heading-6), .zui-list (+ .zui-list-ordered /
.zui-list-unordered, .zui-checklist), .zui-quote, .zui-code,
.zui-frontmatter, .zui-table, .zui-drawing. A drawing at text width
also carries .zui-drawing-canvas.is-text-width.