:::contentbit
Concepts

Block syntax

The complete directive syntax — fences, props, child blocks, and rows.

Blocks

Blocks use fenced directive syntax. A block opens with three (or more) colons plus a kebab-case name, and closes with a line containing only colons:

:::block-name{prop="value" count=3 enabled=true}
Block body
:::

Rules:

  • block names are lowercase kebab-case
  • props are optional
  • a block closes with ::: on its own trimmed line
  • nested blocks are allowed only when the parent block permits them
  • unknown blocks produce diagnostics — they are never silently ignored
  • block delimiters inside fenced code blocks (``` or ~~~) are literal text
  • a closing fence matches the innermost open block; use a longer fence (::::) on the outer block to disambiguate deep nesting

Props

Props use a constrained grammar — safe for generated content and portable across renderers:

{title="Quick Reference" count=3 variant="compact" featured=true}

Supported values:

  • quoted strings (title="Hello \"world\"")
  • numbers (count=3, ratio=-1.5)
  • booleans (featured=true), with bare-key shorthand (featured means featured=true)
  • bare identifiers for enums (variant=compact)

Not supported, by design: JavaScript expressions, object literals, arrays, function references, JSX.

Child blocks

Child blocks use two-colon syntax and close implicitly at the next sibling or the parent close:

:::tabs
::tab{title="Fast"}
Use this when time matters.
::tab{title="Cheap"}
Use this when budget matters.
:::

Three-colon blocks can nest inside child bodies; they must be balanced before the child ends.

source
:::tabs
::tab{title="Fast"}
Use this when time matters.
::tab{title="Cheap"}
Use this when budget matters.
:::
rendered

Use this when time matters.

Pipe rows

Many blocks take rows of pipe-separated cells:

:::key-metrics
- 42% | Conversion lift
- 18ms | Median parse time
:::

Each block defines its own columns and limits, so error messages name the exact expectation. Escape a literal pipe inside a cell as \|.

source
:::key-metrics
- 42% | Conversion lift
- 18ms | Median parse time
:::
rendered
42%
Conversion lift
18ms
Median parse time

When the rows don't match the block's column count, validation fails before any render — and <Live> shows the same file:line:col diagnostic your build would:

source
:::key-metrics
- 42% | Conversion lift | extra column
:::
rendered
example.md:2:1 error CB_ROW_COLUMNS
:::key-metrics rows require 2 columns (value | label). Found 3.
hint: Format: - value | label
example.md:1:1 error CB_ROW_COUNT
:::key-metrics needs at least 2 rows, found 0.

Markdown bodies

Blocks like callout accept regular Markdown content:

:::callout{type="tip" title="Worth knowing"}
You can use **Markdown** inside this block.
:::

The parser preserves the body verbatim — your app's Markdown pipeline renders it.

Raw HTML

Raw HTML is disabled by default everywhere. The static HTML renderer escapes all user content; if your project needs raw HTML, opt in at the renderer level and own sanitization.

On this page