Skip to content

Blocks

View Markdownllms.txt

Blocks organize the content of a page. There are two forms:

FormSyntaxUse
Container::: name {attributes} … :::Blocks with content. A ::: alone on a line closes the last open block.
Single line:: name value {attributes}Blocks without content, such as icons and spacers.

Every block accepts the style attributes. Container blocks can be nested freely, and indentation is optional.

BlockFormChildrenOwn attributes
columnsContainerEach child is a columnwidths
stackContainerStacked vertically
rowContainerSide by side, horizontallywrap
gridContainerEach child is a cellcols
boxContainerStacked inside the box
stepsContainerRevealed one at a time
notesContainerPlain text of the notes
chartContainer or one lineA table with the data, or data=$listtype, legend, stacked, values, colors, data, label, series
tableOne lineNone; data comes from data=$listdata, columns
if and elseContainerThe content shown based on the condition
forContainerThe content repeated for each item
slotContainerContent of a named slot
iconSingle lineNone; the value is the icon name
spacerSingle lineNone; the value is the size
dividerSingle lineNone
inputSingle lineNonebind, placeholder, on-submit
soundSingle lineNone; the value is the audio addressname, autoplay, loop, volume

icon, spacer and divider do not accept content (R109). On the other built-in blocks, text after the name is ignored (R110); use attributes in braces.

Places its children side by side. Each direct child is a column: a paragraph, an image or, to group several elements in one column, a ::: stack.

AttributeValuesDefault
widthsProportions separated by spaces, one per column: widths="2 1"Equal columns
gapSpace between columnsmd (32 px)
valignVertical alignment of the columnscenter
::: columns {widths="2 1" gap=xl}
::: stack {gap=sm}
## Expansion plan
Two new regions by December,
with the same support team.
:::
::: box {.card align=center}
:: icon map-pin {color=accent}
2 regions
:::
:::

Stacks its children vertically. It is the block used to group several elements inside a column or a cell.

AttributeUseDefault
gapSpace between childrenmd (32 px)
alignHorizontal alignment of the childrenThey take the full width
valignVertical alignment of the childrentop
::: stack {gap=xs align=center}
Chapter 1 {.kicker}
# Where it all began
A story in three acts {.muted}
:::

Places its children in a horizontal line, each at the size of its own content. Useful for icons, badges and short lists of items.

AttributeValuesDefault
wrapBoolean: wraps the items onto more lines when they do not fitOff
gapSpace between items16 px
alignHorizontal distribution: left, center, rightleft
valignVertical alignment of the itemscenter
::: row {gap=md align=center}
:: icon star {size=lg color=yellow}
:: icon star {size=lg color=yellow}
:: icon star {size=lg color=yellow}
4.8 out of 5 from 1,200 reviews {size=xl}
:::

Grid with a fixed number of columns. Each child takes one cell, filling rows from left to right.

AttributeValuesDefault
colsNumber of columns, from 1 to 12Number of children, up to 3
gapSpace between cellsmd (32 px)
valignVertical alignment of the cellsStretched to the same height
::: grid {cols=3 gap=lg}
::: box {.card}
### Fast
Preview on every keystroke.
:::
::: box {.card}
### Consistent
Reusable themes and styles.
:::
::: box {.card}
### Versioned
History of every change.
:::
:::

A box that stacks its children vertically and takes a background, border, corners and spacing. Combine it with the .card style (bg=surface radius=lg pad=lg shadow=md) or build the look with attributes.

AttributeUseDefault
gapSpace between children20 px
bg, border, radius, pad, shadowLook of the boxNo background, no border
::: columns {gap=lg}
::: box {.card}
### With `.card`
Background, corners and shadow included.
:::
::: box {border="3 accent" radius=md pad=lg}
### With attributes
Just a border and spacing.
:::
:::

Reveals its children one at a time while the document is shown: each child is a step. If a child is a list, each item of the list becomes a step. In a static rendering of the page, everything shows at once.

It accepts the same attributes as stack. To control the order by hand, use {step=N} on any block or span. See Reveal.

## Three reasons
::: steps {gap=sm}
- Less time formatting
- More time on content
- Consistent documents
:::

Notes for whoever shows the document, such as speaker notes in a presentation. The content is never drawn on the page; the program that shows the document decides where to display it.

  • The text is kept as is, without interpreting formatting or blocks.
  • Several notes blocks on the same page are joined, separated by a blank line.
  • Attributes on the ::: notes line are ignored.
# Results
We grew 38% this quarter.
::: notes
Pause after the number.
Ask if anyone has questions.
:::

Draws a chart from a Markdown table inside the block. The first column holds the labels; each following column is a series, and its header gives the series name. Cells accept numbers such as 42, 3.5, 3,5 and 12%.

AttributeValuesDefault
typebar, line, area, pie, donutbar
legendBooleanOn with more than one series or for pie/donut
stackedBoolean: stacks the seriesOff
valuesBoolean: shows the valuesOff
colorsColors separated by spaces, one per series: colors="accent blue"Theme palette
::: chart {type=bar values}
| Month | 2025 | 2026 |
| --- | ---: | ---: |
| Jan | 32 | 41 |
| Feb | 28 | 45 |
| Mar | 35 | 52 |
:::

With data=$list, the data comes from a @data table and the block can be a single line: :: chart {data=$sales label=month series="revenue cost"}.

More examples in Charts.

Builds a table from a list of records. columns picks the fields and their order; columns with only numbers are right-aligned.

@data team
| name | role | years |
| --- | --- | --- |
| Ana | CTO | 7 |
| Bruno | Design | 3 |
@end
:: table {data=$team columns="name years"}

For a hand-written table, use the Markdown syntax | A | B |.

::: if condition shows the content when the condition is true. Right after it can come ::: else if condition and ::: else. The chosen content goes into the parent block, with no extra box.

@let version = short
::: if $version == short
Summary in one sentence.
:::
::: else
Full version, with every detail.
:::

The if=condition attribute does the same for a single element. With @state, the choice happens while the document is shown; see Interactivity.

::: for item in $list repeats the content for each item, and the generated blocks go into the parent block. ::: for item, i in $list also gives the position (from 1) and ::: for i in 1..5 repeats over a range.

::: row {gap=md}
::: for n in 1..5
:: icon star {color="$($n <= 4 ? accent : muted)"}
:::
:::

Markdown lists generated by a for are merged into a single list. See Variables, data and repetition.

Fills a named slot of a component. It can only be used directly inside the use of a container component (R416 anywhere else). The slot name goes after slot.

@component compare {before after}
::: columns {gap=xl}
::: box {.card}
### $before
$content
:::
::: box {.card}
### $after
$side-b
:::
:::
@end
::: compare {before=Spreadsheets after="Live dashboard"}
Export, paste and format by hand.
::: slot side-b
The data arrives on its own.
:::
:::

See Components for the details of $content and named slots.

Draws an icon from the built-in library. The name goes after icon; the full list is in Icons.

AttributeUseDefault
sizeIcon size: xs…7xl scale or pixels96 px
colorStroke colorText color
::: row {gap=xl align=center}
:: icon rocket {size=3xl color=accent}
:: icon lightbulb {size=3xl color=yellow}
:: icon chart-line {size=3xl color=blue}
:::

Empty space between two blocks. The value is a size from the spacing scale (none to 3xl) or pixels from 0 to 600. With no value, it is md (32 px).

# Before the space
:: spacer 3xl
After 160 px {.muted}

Horizontal divider line. It accepts style attributes, such as w to limit its width and opacity.

## Section
:: divider {w=40%}
Text after the line {.muted}

Text field bound to a @state. What the person types goes straight into the variable, so the text around it changes right away. Bound to a number @state, the field only takes numbers.

AttributeUseDefault
bindThe variable that holds the value, such as bind=$name (required)
placeholderExample text shown while the field is emptyNone
on-submitActions when Enter is pressed, go includedNone
@state name = ""
## What is your name?
:: input {bind=$name placeholder="Your name"}
Hello, $name! {if="$name != \"\""}

Typing in the field does not change the page. In a static rendering, the field shows its initial value. See Text input.

A sound on the page. It is not drawn on the page: it plays with autoplay when the page opens, or when a play action asks for it. Every sound stops when you leave the page, and nothing plays in a static rendering.

AttributeUseDefault
nameName used by play and stop, such as name=doorNone
autoplayPlays as soon as the page opensOff
loopRepeats foreverOff
volumeFrom 0 to 1, or a percentage1
:: sound https://example.com/rain.mp3 {name=rain loop volume=40%}
:: sound https://example.com/door.mp3 {name=door}
# The door
[Open]{click="play door"} · [Silence]{click="stop rain"}

The address starts with https://. See Sound.