Skip to content

feat(examples): container block examples - #3140

Draft
YousefED wants to merge 2 commits into
container-blocks/unifiedfrom
container-blocks/tabs-example
Draft

YousefED wants to merge 2 commits into
container-blocks/unifiedfrom
container-blocks/tabs-example

Conversation

@YousefED

@YousefED YousefED commented Sep 29, 2026 •

Copy link
Copy Markdown
Collaborator

This PR adds examples that use the container block API. Each example shows a block that holds other blocks.

Examples

Tabs (06-custom-schema/14-tabs-block)

A tabs container holds tab panels. Each panel holds any block. The schema keeps a panel inside a tab set.

  • The open tab is kept for each reader, outside the document. It is not an undo step, and it does not go to other users.
  • When the caret moves into a hidden panel, that panel opens.
  • Click the open tab to show a menu. Use the menu to rename, move or delete the tab.
  • Drag a tab to move it. The example uses dnd-kit.

Stepper (06-custom-schema/15-stepper-block)

A stepper container holds step children. A step is placeable: "namedOnly", so a step can only be inside a stepper. Each step holds any block.

  • The step numbers come from a CSS counter. They stay correct when the user adds, moves, removes or undoes a step.
  • Add step adds a step below the last step and puts the caret in its title.
  • Enter on an empty block at the end of a step starts the next step. Enter on the empty title of a new step leaves the stepper.
  • Use the side menu to move or delete a step.

Known limitations:

  • The title of a step is not enforced. A step has no text of its own. Its title is its first child, a heading. The user can change that heading to a different block or delete it. A real title needs a block with its own text that can only be inside a stepper. The container API cannot do this yet: placeable: "namedOnly" needs a container (a block without content), and children.allow can only name containers. A possible fix (own node types for blocks with content and owned children) is discussed in this proposal. It is out of scope for this PR.
  • A step with an empty paragraph as its title is removed. The container repair removes a child that holds only an empty paragraph (see the first known issue below). A new step starts with an empty heading, because a heading is the correct block for a title, semantically and visually. An empty heading does not count as empty, so the repair keeps a new step. But if the user changes the title to an empty paragraph, the repair removes the step.

Drag and drop of blocks in a container (core)

The stepper found three problems when the user drags a block that is in a container. This PR fixes them:

  • A drop created a new parent block. At the start of a drag, the side menu parsed the dragged blocks again from HTML, into a list of top-level blocks. A block that can only be inside a parent (for example a step) got a new parent. Thus a drop created a new stepper. Now dragStart gives ProseMirror the dragged nodes directly.
  • The drop cursor was not visible. The node view of a step has display: contents, so it has no box. The drop cursor now measures the first child of such a node view.
  • The drag preview of a step was empty. The preview now finds the dragged block through the wrapper elements of a node view.

The drag and drop end-to-end tests pass (dragdrop and draghandle, Chromium). A drag between two editors does the same as before.

Toggle heading

To be added.

Known issues

An empty panel is deleted with its title. The container repair looks only at the content of a child. A panel that holds only an empty paragraph is "empty", so the repair deletes it. The repair ignores the props of the panel, so the title is also lost. The repair deletes all empty panels, not only the panel that changed. If fewer panels than min stay, the complete tab set is removed. Examples:

  • Tabs A (text), B (empty), C (empty). Delete B. C is also deleted.
  • Tabs A (text), B (empty). Delete A. The complete tab set is deleted.

A block cannot stop this. The children config has only allow and min.

Suggested fix: let the block decide if a child is empty. Only the author of a block knows if its props hold information (for example the title of a tab, or the width of a column). A simpler alternative is a third option in the children config, for example children: { allow, min, keepEmpty: true }, which stops the repair from removing empty children.

The side menu does not work well for blocks in a panel. The side menu shows to the left of a block. In a panel, it covers the chrome of the panel. This is the same problem as the side menu in columns. It was reported in this comment on #3059.

🤖 Generated with Claude Code

Add a tabs example. A `tabs` container holds `tab` panels, and each panel
holds any block. The open tab is kept for each reader, outside the document.
The open tab of a panel opens a menu to rename, move or delete it. Tabs can
be dragged to reorder them.
@vercel

vercel Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
blocknote Ready Ready Preview Sep 29, 2026 3:10pm UTC
blocknote-website Ready Ready Preview Sep 29, 2026 3:10pm UTC

Request Review

@coderabbitai

coderabbitai Bot commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@pkg-pr-new

pkg-pr-new Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

@blocknote/ariakit

npm i https://pkg.pr.new/@blocknote/ariakit@3140

@blocknote/code-block

npm i https://pkg.pr.new/@blocknote/code-block@3140

@blocknote/core

npm i https://pkg.pr.new/@blocknote/core@3140

@blocknote/diagram-block

npm i https://pkg.pr.new/@blocknote/diagram-block@3140

@blocknote/mantine

npm i https://pkg.pr.new/@blocknote/mantine@3140

@blocknote/math-block

npm i https://pkg.pr.new/@blocknote/math-block@3140

@blocknote/react

npm i https://pkg.pr.new/@blocknote/react@3140

@blocknote/server-util

npm i https://pkg.pr.new/@blocknote/server-util@3140

@blocknote/shadcn

npm i https://pkg.pr.new/@blocknote/shadcn@3140

@blocknote/xl-ai

npm i https://pkg.pr.new/@blocknote/xl-ai@3140

@blocknote/xl-docx-exporter

npm i https://pkg.pr.new/@blocknote/xl-docx-exporter@3140

@blocknote/xl-email-exporter

npm i https://pkg.pr.new/@blocknote/xl-email-exporter@3140

@blocknote/xl-multi-column

npm i https://pkg.pr.new/@blocknote/xl-multi-column@3140

@blocknote/xl-odt-exporter

npm i https://pkg.pr.new/@blocknote/xl-odt-exporter@3140

@blocknote/xl-pdf-exporter

npm i https://pkg.pr.new/@blocknote/xl-pdf-exporter@3140

@blocknote/xl-typst-exporter

npm i https://pkg.pr.new/@blocknote/xl-typst-exporter@3140

commit: 64a1530

@github-actions

github-actions Bot commented Sep 29, 2026 •

Copy link
Copy Markdown
PR Preview Action v1.8.1

QR code for preview link

🚀 View preview at
https://TypeCellOS.github.io/BlockNote/pr-preview/pr-3140/

Built to branch gh-pages at 2026-09-29 15:21 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

Add a stepper example built on container blocks. `stepper` holds only
`step` children, and `step` is `placeable: "namedOnly"`. The numbers are a
CSS counter. "Add step" and Enter on an empty last block start a new step,
and reordering or deleting a step uses the side menu.

Known limitations:
- The step title is not enforced. A step has no text of its own; its title
  is its first child, a heading, which the user can change or delete. A
  block with its own text cannot be `placeable: "namedOnly"` (that needs a
  container), and `children.allow` can only name containers.
- A step whose title is an empty paragraph is removed by the container
  repair, so new steps start with an empty heading.

Drag and drop fixes for blocks inside a container (core):
- dragStart sets `view.dragging` to the selected nodes. Before, the side
  menu parsed them back from `blocknote/html` into a `blockGroup`, which
  wrapped a `namedOnly` block in a new parent, so dropping a step created a
  new stepper.
- The drop cursor measures the first child of a `display: contents` node
  view. Before, it drew a 0px line for steps.
- The drag preview finds the dragged block through a node view's wrapper
  elements, and clears `display: contents` on the clone. Before, the
  preview of a step was empty.

This branch was successfully deployed

2 active deployments
Preview – blocknote-website — 64a15308 Deployed Sep 29, 2026 by vercel[bot]
Preview – blocknote — 64a15308 Deployed Sep 29, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant