Skip to content

Layout Blocks ​

Editu includes Gutenberg-style layout primitives for building structured page layouts inside the editor. These blocks let you create sections with backgrounds, multi-column grids, spacing, dividers, and call-to-action buttons — all with semantic token-based styling.

Overview ​

BlockTypeDescription
groupContainerWrapper with padding, background, and border-radius tokens
columns + columnContainerHorizontal multi-column grid with drag-to-resize
spacerAtomVertical whitespace sized by height token
dividerAtomHorizontal rule with style and thickness tokens
buttonAtomCTA link with label, href, variant, and target

Container blocks hold child blocks (block+). Atom blocks are leaf nodes with no children.

Installation ​

Layout blocks are standalone Tiptap extensions — they are not part of the features config. Register them as extensions directly or through the plugin system.

Direct Registration ​

tsx
import { useEdituEditor } from '@editu/react';
import {
  EdituGroupReact,
  EdituColumnsReact,
  EdituColumnReact,
  EdituSpacerReact,
  EdituDividerReact,
  EdituButtonReact,
} from '@editu/react';

const editor = useEdituEditor({
  extensions: [
    EdituGroupReact,
    EdituColumnsReact,
    EdituColumnReact,
    EdituSpacerReact,
    EdituDividerReact,
    EdituButtonReact,
  ],
});

The *React variants include interactive NodeViews (resize handles, click-to-edit labels, selection borders). If you don't need React NodeViews, use the framework-agnostic extensions from @editu/core:

typescript
import {
  EdituGroup,
  EdituColumns,
  EdituColumn,
  EdituSpacer,
  EdituDivider,
  EdituButton,
} from '@editu/core';

Via Plugin System ​

typescript
import type { EdituPlugin } from '@editu/core';
import {
  EdituGroupReact,
  EdituColumnsReact,
  EdituColumnReact,
  EdituSpacerReact,
  EdituDividerReact,
  EdituButtonReact,
} from '@editu/react';

const layoutPlugin: EdituPlugin = {
  name: 'editu-layout',
  version: '1.0.0',
  description: 'Gutenberg-style layout primitives',
  extensions: [
    EdituGroupReact,
    EdituColumnsReact,
    EdituColumnReact,
    EdituSpacerReact,
    EdituDividerReact,
    EdituButtonReact,
  ],
};

See Plugins for the full plugin API.


Group ​

A wrapper block with token-based padding, background, and border-radius.

Attributes ​

AttributeTypeDefaultValues
paddingEdituGroupPaddingToken"none""none" "xs" "sm" "md" "lg" "xl"
backgroundEdituGroupBackgroundToken"none""none" "muted" "subtle" "accent" "warning"
borderRadiusEdituGroupRadiusToken"none""none" "sm" "md" "lg" "xl" "full"

Commands ​

typescript
// Wrap selection in a group
editor.commands.setGroup({ padding: 'md', background: 'subtle' });

// Toggle group wrapper
editor.commands.toggleGroup({ padding: 'lg' });

// Update attributes of current group
editor.commands.updateGroupAttributes({ background: 'accent' });

// Lift content out of group
editor.commands.unsetGroup();

Columns + Column ​

Horizontal multi-column layout. The columns wrapper enforces a minimum of 2 child column nodes. Each column stores a width fraction (0..1) controlling its flex basis.

Columns Attributes ​

AttributeTypeDefaultValues
gapEdituColumnsGapToken"md""none" "xs" "sm" "md" "lg"

Column Attributes ​

AttributeTypeDefaultConstraints
widthnumber0.5Min: 0.1, Max: 0.9. Sibling widths should sum to ~1.

Commands ​

typescript
// Insert a 2-column layout
editor.commands.setColumns(2);

// Insert a 3-column layout
editor.commands.setColumns(3);

// Add a column to the current columns wrapper
editor.commands.addColumn();

// Remove the current column (no-op if < 3 columns)
editor.commands.removeColumn();

// Update a column's width at a specific document position
editor.commands.updateColumnWidth(pos, 0.6);

The React NodeView (EdituColumnsNodeView) adds drag-to-resize handles between columns. Drag a handle to redistribute widths between adjacent columns.


Spacer ​

A vertical whitespace atom block sized by a semantic height token.

Attributes ​

AttributeTypeDefaultValues
heightEdituSpacerHeightToken"md""xs" "sm" "md" "lg" "xl"

Commands ​

typescript
// Insert a spacer with default height
editor.commands.setSpacer();

// Insert a spacer with a specific height
editor.commands.setSpacer('lg');

// Update height of current spacer
editor.commands.updateSpacerHeight('xl');

Divider ​

A horizontal rule with style and thickness tokens. Falls back to standard --- markdown when using default attributes.

Attributes ​

AttributeTypeDefaultValues
styleEdituDividerStyle"solid""solid" "dashed" "dotted"
thicknessEdituDividerThickness"regular""thin" "regular" "thick"

Commands ​

typescript
// Insert a divider
editor.commands.setDivider();

// Insert a dashed divider
editor.commands.setDivider({ style: 'dashed', thickness: 'thin' });

// Update attributes of current divider
editor.commands.updateDividerAttributes({ style: 'dotted' });

Button ​

A CTA link atom with label, href, variant, and target. The label is stored in the schema as an attribute (atoms are leaves with no inline content).

Attributes ​

AttributeTypeDefaultValues
labelstring"Button"Any text
hrefstring"#"Any URL
variantEdituButtonVariant"primary""primary" "secondary" "ghost"
targetEdituButtonTarget"_self""_self" "_blank"

Commands ​

typescript
// Insert a button
editor.commands.setButton({ label: 'Get Started', href: '/docs' });

// Insert with variant
editor.commands.setButton({
  label: 'Learn More',
  href: 'https://example.com',
  variant: 'secondary',
  target: '_blank',
});

// Update attributes of current button
editor.commands.updateButtonAttributes({ variant: 'ghost' });

The React NodeView (EdituButtonNodeView) renders a click-to-edit label editor via updateAttributes.


Token Registry ​

Layout blocks use semantic tokens instead of raw CSS classes. The token registries in @editu/core/tokens map token keys to Tailwind utility classes:

RegistryToken TypeExample Mapping
EDITU_SPACING_TOKENSPadding/height"md" → "p-4"
EDITU_BACKGROUND_TOKENSBackground"muted" → "bg-neutral-100"
EDITU_RADIUS_TOKENSBorder radius"lg" → "rounded-lg"
EDITU_HEIGHT_TOKENSSpacer height"lg" → "h-16"
EDITU_DIVIDER_STYLE_TOKENSDivider style"dashed" → "border-dashed"
EDITU_DIVIDER_THICKNESS_TOKENSDivider thickness"thick" → "border-t-4"
EDITU_BUTTON_VARIANT_TOKENSButton variant"primary" → "bg-blue-600 text-white hover:bg-blue-700"

Resolving Tokens ​

Each registry exports a resolver function:

typescript
import {
  resolveEdituSpacing,
  resolveEdituBackground,
  resolveEdituButtonVariant,
} from '@editu/core/tokens';

resolveEdituSpacing('md');         // "p-4"
resolveEdituBackground('accent');  // "bg-blue-50"
resolveEdituButtonVariant('ghost'); // "bg-transparent text-blue-600 hover:bg-blue-50"

The React NodeViews call these resolvers internally to apply Tailwind classes. If you build a custom NodeView or render layout blocks outside the editor, use the resolver functions to map tokens to classes.


Markdown Round-Trip ​

Layout blocks serialize to raw HTML with data-editu-* attributes, since they have no standard Markdown equivalent:

html
<!-- Group -->
<div data-editu-group data-padding="md" data-background="subtle" data-border-radius="lg">

Content inside the group...

</div>

<!-- Columns -->
<div data-editu-columns data-gap="md">
<div data-editu-column data-width="0.5">Left column</div>
<div data-editu-column data-width="0.5">Right column</div>
</div>

<!-- Spacer -->
<div data-editu-spacer data-height="lg"></div>

<!-- Divider (default: standard ---) -->
---

<!-- Divider (custom style) -->
<hr data-editu-divider data-style="dashed" data-thickness="thin" />

<!-- Button -->
<a data-editu-button href="/docs" data-variant="primary" target="_self" data-label="Get Started">Get Started</a>

TIP

The divider block with default attributes (solid + regular) serializes as standard Markdown --- for maximum compatibility.


Next Steps ​

  • Output Modes — How layout blocks export to Markdown, JSON, and HTML (Tailwind token mapping)
  • Custom Blocks — Build your own block from scratch (hands-on tutorial)
  • Plugins — Package layout blocks as a reusable plugin
  • Theming — Customize token-to-class mappings via CSS variables
  • Configuration — Editor setup and extension registration

Released under the MIT License.