DOCUMENTATION

Toggle

Last updated May 2026
Advanced Block
All plans

A collapsible section with a clickable chevron. The toggle header is a full rich-text editor — plain text or any of three heading levels. Any block type can be nested inside as a child, including other toggles. The open/closed state syncs to collaborators in real time via Yjs.

Markdown shortcuts

Type thisConverts to
>Toggle

Variants

Four variants share the same collapse mechanic but use different header typography:

VariantSlash commandHeader style
Toggle/toggle1rem · normal weight
Toggle Heading 1/toggle heading 12.25rem · bold · tight tracking
Toggle Heading 2/toggle heading 21.875rem · bold · tight tracking
Toggle Heading 3/toggle heading 31.5rem · semibold
All four variants — open state
Toggle — base text
Child content here
Toggle Heading 1
Child content here
Toggle Heading 2
Child content here
Toggle Heading 3
Child content here
The heading class is applied directly to the Tiptap ProseMirror contenteditable element — not a wrapper div. This ensures heading sizes render correctly in the editor canvas. Earlier versions applied the class to a wrapper, which caused headings to appear at base text size.

Opening and closing

Open vs closed state

Open — chevron points down

Introduction
This content is visible.
So is this.

Closed — chevron points right

Introduction
Click chevron
Toggles open/closed state. The chevron rotates 90° when open, returns to pointing right when closed. Transition is 200ms ease-out.
onMouseDown
The chevron uses onMouseDown rather than onClick so the editor does not lose focus (and the text cursor does not jump) when you collapse a toggle you are actively editing.

The open/closed state is stored in metadata.toggleOpen and written to the Yjs document immediately on toggle. Collaborators see the state change in real time.

Thread line

When a toggle is open, its children are indented and a thin vertical line runs down the left side — the “thread line”. It visually groups the children under their parent and makes nesting depth immediately readable.

Thread line — nested toggles
Chapter 1
Section 1.1
Paragraph content.
Another paragraph.
Section 1.2

The thread line is 1px wide, border-radius: 9999px, and color-adapts: rgba(255,255,255,0.15) on dark backgrounds,#e5e7eb on light ones.

Child blocks

Any block type can be a child — paragraphs, headings, lists, to-dos, callouts, images, databases, commerce blocks, and other toggles. Children are identified by a parentToggleIdfield on the block that stores the toggle's ID.

Mixed child block types
Meeting notes
Discussed Q3 roadmap priorities.
Ship the new onboarding flow by Friday
Review design mockups with the team
Follow up with eng on API timeline
+ Add block

Adding child blocks

Enter (last child)
Pressing Enter on the last child creates a new paragraph block inside the toggle, immediately after the current child.
Enter (empty child)
Pressing Enter on an empty child block at the end of the toggle exits the toggle — a new block is created after the toggle in the main document.
+ Add block button
A faint "+ Add block" button appears at the bottom of the open toggle area when you hover. Clicking it appends a new paragraph child at the end.
/ inside toggle
Type / on any empty child paragraph to open the slash command palette. All block types are available — the new block is created as a child of this toggle.
Drag into toggle
Drag any block from the main document over a toggle header. The toggle auto-opens after 400ms if it was closed. Drop to adopt the block as a child.

Drag auto-open

When dragging a block, the system tracks which toggle header the cursor is hovering over. If you hold over a closed toggle for 400ms, it opens automatically so you can drop into it without manually opening it first.

If you move the cursor away before the 400ms timer fires, the timer is cancelled and the toggle stays closed. The timer also resets if you hover a different toggle. Toggles that are ancestors of the dragged block are excluded from auto-open targets — you cannot accidentally drop a toggle into its own descendant.

Auto-open works at any nesting depth. You can drag a block into a closed toggle inside another closed toggle — hover the outer one to open it, then hover the inner one to open that, then drop.

Extracting blocks from a toggle

Shift+Tab
On any child block, Shift+Tab extracts it from the toggle and places it immediately after the last descendant of the toggle in the main document.
Extract button
A curved-arrow icon (↩) appears on hover to the left of any child block. Clicking it extracts that block to the top level.
Drag out
Drag a child block past the bottom edge of the toggle's content area to move it into the main document.
Extraction placement is precise — the block is inserted after the last descendant of the toggle, not after the toggle header itself. If the toggle contains nested toggles with their own children, the extracted block appears after all of them. This preserves the visual reading order.

Reordering children

Child blocks can be reordered by dragging within the toggle. The drop line and drop zone logic is scoped to the toggle's child list — dragging a child to the very top places it before the first sibling, not before the toggle header. Dragging a child to the bottom places it after the last sibling before the “Add block” button.

Rects for toggle drop zones are refreshed every 50ms during a drag to account for toggles that open or reflow mid-drag.

Nested toggles

Toggles can be nested inside other toggles to any depth. Each level gets its own thread line and chevron. Opening and closing is independent per toggle — collapsing a parent hides all descendants regardless of whether they are open or closed at their own level. Their individual open/closed states are preserved and restored when the parent is re-opened.

Three levels of nesting
Part I — Foundations
Chapter 1 — Introduction
1.1 Background
The history of the problem.
Prior approaches and their limitations.
1.2 Scope
Chapter 2 — Methodology

Publishing behaviour

On published pages, toggles render via the ReadOnlyToggle client component. The initial open/closed state is whatever was saved in the editor. Visitors can click the chevron to expand or collapse — toggles are fully interactive on published pages, not static.

The toggle state on the published page is local to the visitor's session — changes a visitor makes do not persist or sync back to the document.

Metadata reference

toggleOpen
Boolean on the toggle block. true = open, false = closed. Updated by clicking the chevron. Synced via Yjs to all collaborators.
parentToggleId
Set on child blocks. Stores the ID of the parent toggle. Used to scope child block trees and drive the toggle drop zone registration.
textColor
Optional text color for the header text. Applied to the ProseMirror element.