Page components
A fenced code block whose language starts with @ is a call to a component. Everything below is generated from the components themselves, so it cannot go stale.
@audio
renders: server
An audio player over a file uploaded to this site. Controls on, nothing autoplays.
Server rendered.
Example
```@audio src:/f/k3Fq9ZrX2mB7vT1wLp8sYa/episodio.mp3 title:"Episódio 1"
```
Arguments
-
srcpath Required - Path of the file on this site, usually an upload of the page. Starts with a single / — "//host/x" is another site, not a path.
-
titlestring - A short title shown under the player.
-
preloadenum Default: metadata - How much the browser fetches before play: none, metadata or auto. Allowed: none, metadata, auto
-
members_ofstring - A group, by name or id: only its members (and whoever edits the page) see this block; everybody else sees a line saying so, with the group's door. Nothing of the block reaches them — not on the page, not in its Markdown, not through the MCP, the search or their calendar feed (an @event is on its members' and editors' feeds only).
-
consentstring - A flag the reader must have allowed before this block shows (`consent:videos`; several, separated by spaces). It has to be one a `@consent` on this site offers.
Body
This component takes no body.
@button
renders: server
A link drawn as a button: what the reader should do next. Works in pages and in e-mails.
Server rendered.
Example
```@button to:/pricing
See the plans
```
Arguments
-
tostring Required - Where it goes: a path of this site (/@ana/menu) or a web address starting with https://.
-
members_ofstring - A group, by name or id: only its members (and whoever edits the page) see this block; everybody else sees a line saying so, with the group's door. Nothing of the block reaches them — not on the page, not in its Markdown, not through the MCP, the search or their calendar feed (an @event is on its members' and editors' feeds only).
-
consentstring - A flag the reader must have allowed before this block shows (`consent:videos`; several, separated by spaces). It has to be one a `@consent` on this site offers.
Body
Free text. The label on the button.
@components
renders: server
The reference for every fence a page may call, generated from the components' own declarations.
Server rendered.
Example
```@components
```
Arguments
-
onlyenum Default: all - Which half to list: `server`, `client`, or `all` (the default). Allowed: all, server, client
-
members_ofstring - A group, by name or id: only its members (and whoever edits the page) see this block; everybody else sees a line saying so, with the group's door. Nothing of the block reaches them — not on the page, not in its Markdown, not through the MCP, the search or their calendar feed (an @event is on its members' and editors' feeds only).
-
consentstring - A flag the reader must have allowed before this block shows (`consent:videos`; several, separated by spaces). It has to be one a `@consent` on this site offers.
Body
This component takes no body.
@consent
renders: server
The reader's yes or no, one line per purpose (flags | label | description | required), remembered on this site as flags the reader owns. One purpose is two buttons; several are switches with accept all, reject all and save. Put it inside a :::banner for a cookie notice.
Server rendered.
Example
```@consent title:"Sua privacidade" link:/privacidade
essential | Essenciais | Mantêm o site funcionando. | required
videos | Vídeos do YouTube | Carrega o player do Google, que usa cookies.
```
Arguments
-
titlestring - A heading above the purposes.
-
linkstring - Where the full policy is: a page of this site (/privacidade) or a web address starting with https://.
-
acceptstring - The words on the button that says yes to everything. Default: Accept all.
-
rejectstring - The words on the button that says no to everything but the required. Default: Reject all.
-
savestring - The words on the button that keeps the switches as they are. Default: Save choices.
-
members_ofstring - A group, by name or id: only its members (and whoever edits the page) see this block; everybody else sees a line saying so, with the group's door. Nothing of the block reaches them — not on the page, not in its Markdown, not through the MCP, the search or their calendar feed (an @event is on its members' and editors' feeds only).
-
consentstring - A flag the reader must have allowed before this block shows (`consent:videos`; several, separated by spaces). It has to be one a `@consent` on this site offers.
Body
One instruction per line. One purpose per line: the flags it sets (space-separated), a `|`, the label, a `|`, what it means; `| required` at the end for one that is always on.
@contact
renders: server
A person or a place to reach: call, WhatsApp with a written message, e-mail, map — and a button that saves the contact to the phone.
Server rendered.
Example
```@contact name:"Vitória Imóveis" role:"Corretora" whatsapp:"+55 11 95550-0134" message:"Olá! Vi sua página." email:[email protected]
```
Arguments
-
namestring Required - Who this is.
-
rolestring - What they do, under the name.
-
orgstring - The company or the place.
-
phonestring - A telephone number, with the country code: "+55 11 5550-0134".
-
whatsappstring - The WhatsApp number, with the country code. It opens a conversation.
-
messagestring - What the WhatsApp conversation starts with, already written for the person.
-
emailstring - An e-mail address.
-
sitestring - A web address, starting with https://.
-
addressstring - Where it is. It opens the map.
-
saveboolean Default: true - Whether the "Save contact" button is shown.
-
members_ofstring - A group, by name or id: only its members (and whoever edits the page) see this block; everybody else sees a line saying so, with the group's door. Nothing of the block reaches them — not on the page, not in its Markdown, not through the MCP, the search or their calendar feed (an @event is on its members' and editors' feeds only).
-
consentstring - A flag the reader must have allowed before this block shows (`consent:videos`; several, separated by spaces). It has to be one a `@consent` on this site offers.
Body
This component takes no body.
@copy
renders: server
A value to take away — a Pix key, a coupon, a wifi password, a command — printed, with a button that copies it.
Server rendered.
Example
```@copy label:"Chave Pix" value:[email protected] note:"Any amount helps"
```
Arguments
-
valuestring - What is copied, up to 2,000 characters. Write it here when it is short, or in the body when it is long or has spaces and quotes.
-
labelstring - What the value is, printed above it.
-
notestring - One line under the value: until when it is valid, where to paste it.
-
kindenum Default: text - text for a key or a code a person reads; code for something pasted into a terminal, kept on its own lines. Allowed: text, code
-
members_ofstring - A group, by name or id: only its members (and whoever edits the page) see this block; everybody else sees a line saying so, with the group's door. Nothing of the block reaches them — not on the page, not in its Markdown, not through the MCP, the search or their calendar feed (an @event is on its members' and editors' feeds only).
-
consentstring - A flag the reader must have allowed before this block shows (`consent:videos`; several, separated by spaces). It has to be one a `@consent` on this site offers.
Body
Free text. The value, when it does not fit on the fence line: up to 2,000 characters. The body wins over `value`.
@countdown
renders: server
Counts down to a date and time, and says something else once it has come. A launch, a drop, doors opening, enrolment closing.
Server rendered.
Example
```@countdown to:2026-11-20T19:00-03:00 label:"Doors open" done:"We are open"
```
Arguments
-
tostring Required - The moment, as 2026-11-20 or 2026-11-20T19:00-03:00. With no offset it is read as UTC; a date alone is its first minute.
-
labelstring - What is being waited for, printed above the clock.
-
donestring - What the block says once the moment has passed. Without it the block says the moment has come.
-
showenum Default: full - full counts days, hours, minutes and seconds; days counts only days, for something weeks away. Allowed: full, days
-
members_ofstring - A group, by name or id: only its members (and whoever edits the page) see this block; everybody else sees a line saying so, with the group's door. Nothing of the block reaches them — not on the page, not in its Markdown, not through the MCP, the search or their calendar feed (an @event is on its members' and editors' feeds only).
-
consentstring - A flag the reader must have allowed before this block shows (`consent:videos`; several, separated by spaces). It has to be one a `@consent` on this site offers.
Body
This component takes no body.
@data
renders: server
Reads a collection of this space and renders it as a table, with filters, columns, metrics and pagination; filter_by and search give the reader tabs, menus and a search box that narrow it. view:board group:<select field> shows the same rows as a board, one column per option, and lets the space's writers move a card to another column. view:calendar date:<date or datetime field> places the rows on a month or a week, and lets the writers move an item to another day. view:checklist done:<boolean field> gives each row a checkbox the writers tick. view:timeline lays the rows out as the steps of a :::timeline, state:<field> giving each its marker and item:<component> drawing each with a component of the theme. view:field field:<field> (or fields:a,b,c) shows that field of the rows the @filter lines select — meant for one row, like a post's own page — as a control the writers change in place: a select, a checkbox, a date, a number, a text box. A filter may name the page the table is shown on — in a template, the page wearing it: `@filter pr eq page.slug` (the last step of its address), `page.name`, `page.parent` (the last step of the page above). A date filter may count from today, in the reader's time zone: `@filter due lte today`, `@filter updated_at lt -14d` (today, today+3d, -2w; on a datetime, the whole of that day: `lte today` runs to midnight tonight). `@count by:<select field>` counts the rows per option; `@sum field by:<select field>` and `@avg field by:` sum or average per option, the rows counted beside each, in one query. `label:"…"` on a metric line names it. view:metric draws only the metric lines, each a stat (the number large, its label under it) — a dashboard tile, and the stat of a `:::grid items:stat` item. `@column created_at format:age` prints how long ago ("3d", "2w"). `@column title link:pr,ticket` links the text to the first of those url fields that holds an address, and `label:` on a link column is the link's text. A public collection is public inside a space its reader may see; in a private space, a page published on its own (public, cut from the space's settings) shows a table of it to whoever opens that page, when everyone who may edit the page already writes the collection — the export and every other page stay private.
Server rendered.
Example
```@data collection:inscricoes sort:-created_at limit:10
@filter status eq aberto
@count
@column nome label:"Quem"
@column status format:badge
```
Arguments
-
collectionstring Required - The name of the collection inside this space, without the @space prefix: lowercase letters, digits and hyphens, 2 to 40 characters (coord-agents, never coord_agents — field names take underscores, collection names do not).
-
limitinteger Default: 25 - How many rows per page (1–100). Defaults to 25. A board, a checklist and a calendar's period are one page: they show at most this many rows in all, and say how many more there are. Allowed: 1 to 100
-
offsetinteger Default: 0 - How many rows to skip before the first page. Allowed: 0 to 100000
-
sortstring - A field to sort by; a leading minus reverses it (`-created_at`).
-
distinctstring - One row per value of this field: the first in the sort order, so `distinct:pr sort:-created_at` shows each pull request's latest review. The limit, the counts and the pages are over the rows kept; rows with no value are one value.
-
includelist - Reference fields to resolve, comma separated. Shown references are resolved anyway.
-
fieldslist - Which fields to show, comma separated. Defaults to every stored field plus created_at. With view:field, the fields shown as controls (`fields:status,due,done`), in that order.
-
scopeenum - viewer: each person sees only the rows they created. Allowed: viewer
-
emptystring - What to say when there is no row to show.
-
exportboolean Default: false - Adds CSV and JSON links for the whole filtered collection — the fence's filters, sort, scope and columns, but not its limit or offset.
-
updatedboolean Default: false - Prints, under the table, when a row of the collection was last added, changed or deleted, in the reader's clock and language.
-
page_paramstring Default: page - The query parameter this table pages on. Only for two tables on one page that both page (more rows than limit:): give them different ones. A table that never pages needs none.
-
filter_bylist - Fields the reader may filter by, comma separated: select or multi_select fields this table shows. Five options or fewer render as tabs, more as a menu. It only narrows what the fence's own @filter lets through.
-
searchlist - Text fields the reader may search, comma separated, from the ones this table shows: one box searches them all. A search is not cached.
-
titlestring - A line above the rows, {count} replaced by how many rows the reader's filters leave: title:"{count} imóveis disponíveis".
-
sortsstring - Orders the reader may choose, label:field pairs, comma separated, `-` before a field for descending (sorts:"Padrão:ordem,Valor maior:-valor,Valor menor:valor"): a menu above the rows; the fence's own sort: stays the order until the reader picks one.
-
asidestring - A short line under the reader's filters, in their column when controls:side (aside:"Não encontrou o imóvel desejado?"), with an optional button: aside_button: its words, aside_href: where it goes (an http(s) address or a /path).
-
aside_buttonstring - With aside:, the button's words.
-
aside_hrefstring - With aside:, where the button goes: an http(s) address or a /path of this site.
-
filter_minlist - Number fields this table shows that the reader may ask a minimum of, comma separated (filter_min:quartos,vagas): each is a row of buttons 1+ to 5+, and the chosen one leaves the rows with at least that many; choosing it again clears it.
-
filter_includelist - Exactly the select fields readers may filter by, shown on the table or not, comma separated (filter_include:tipo,cidade,bairro). Without filter_include or filter_except, filter_by takes only the fields the table shows.
-
filter_exceptlist - Readers may filter by every select field of the collection, shown or not, except these, comma separated (filter_except:nota,salario). Not together with filter_include.
-
controlsenum Default: top - Where the reader's filters and search stand: top (a row above the rows), side (a column beside them, every filter a menu, the button the column's width; above them on a phone), or only (the menus and the button and no rows: a search bar whose button opens to:, where a table with the same id: lists them). Allowed: top, side, only
-
applystring - The label of the button that applies the reader's menus and search (default: Apply).
-
labelsenum Default: above - Where each menu's name stands: above it, or inside (its first option says it, "Tipo de imóvel" for all of them, as a home's search bar draws them; the name above stays for a screen reader). Allowed: above, inside
-
idstring - The table's own name, lowercase letters, digits and dashes, starting with a letter (id:imoveis): its reader's choices travel under it in the address (?data-imoveis_filter_tipo=Casa), so a link, or a search bar on another page with the same id:, opens it filtered. One per page.
-
tostring - With controls:only, where the search bar's button goes (an http(s) address or a /path): the page whose table has the same id:.
-
pagingenum Default: simple - How the pages are offered when the rows run past limit:: simple (previous, page 2 of 9, next), or numbers (the pages near this one as numbered boxes, and arrows). Allowed: simple, numbers
-
viewenum Default: table - table: rows and columns (the default). board: one column per option of the `group` field, in the order the schema lists them, each row a card; the first @column is the card's title and the others are small lines under it. The space's writers can drag a card, or use its "Move to" menu, to set the field to another option; everybody else sees the board read-only. calendar: the rows on the days of a month (or a week, `period:week`) by their `date` field, in the viewer's time zone; writers drag an item to another day or use its "Move to date" form. checklist: each row a checkbox bound to the `done` field, labelled by the first @column, with a count; writers tick and untick, everybody else sees the boxes disabled. field: one field (`field:status`) or a few (`fields:status,due,done`) of each row the filters select, as controls the space's writers change in place — a select, checkboxes, tag chips, a checkbox, a date, a number, a text box, each saved at once; everybody else sees the values. Meant for a filter that selects one row (`@filter slug eq x-launch`); several rows are one line each, up to `limit`, titled by the first @column or the row's own name. cards: a grid of cards — the first `format:image` @column is each card's picture, run to the card's edges (a further `format:image` column sits on it, above the tags); the title is the @column with `link:` (else the first other one), on one line; @columns written before it are small lines above it (a code), the ones after it lines under it, cut at three; @columns with `icon:` share one line with their icons (`@column quartos icon:bed`); `format:badge` columns are small tags stacked on the picture, a `format:ribbon` column a band across its corner (sold); `over:` names the column written across its bottom (a price); `button:` adds a small button to the title's link; `layout:carousel` lays them in one row that scrolls sideways, with Previous/Next, holding the first `limit:` rows of the sort with no pages; the reader's filters, search, `sorts:` and pages are the table's. item: each row the filters select drawn whole by a component of the theme the page wears (`item:imovel`), its fields in the slots of the same names — the page of one row; in a template, `@filter codigo eq page.slug` makes one template the page of every row. metric: the @count, @sum, @avg, @min and @max lines and nothing else — no rows, no table — each a stat, the number large and its `label:` (or what it computes) under it; a line with `by:` is a stat per option under its label. Allowed: table, board, calendar, checklist, timeline, field, cards, item, metric
-
groupstring - With view:board, the select field whose options become the columns (`group:status`). Required for a board and refused without one. Rows with no value go to a last "No value" column, shown only when some row has none. The space's writers can drag a card (or use its "Move to" menu) to another column; a card dropped on another board of the same collection — on this page, in a side-by-side view, or in another window — takes the group field of the board it lands on. Everybody else sees the board read-only. With view:checklist, a select field whose options become sections (`group:room`), each with its own count; only sections with rows are shown. With view:timeline, a select field whose value heads each run of steps with the same one (`group:kind`), in the order the rows come.
-
orderstring - With view:board, a number field that keeps the order of the cards inside each column (`order:rank`): writers can drag a card above or below another, or use Move up and Move down, and one move writes one row. A card dropped into another column takes a number halfway between its new neighbours there (a fraction; when there is no room the column is numbered again); Move to puts it last among that column's numbered cards. The numbers are compared only inside a column, so the same number in two columns means nothing. Cards with no number yet come last, in the fence's sort. Without order the columns keep the fence's sort and cannot be reordered. With view:checklist, a number field that keeps the order of the rows (inside each section): writers drag a row by its grip, or use Move up and Move down.
-
datestring - With view:calendar, the date or datetime field each row is placed by (`date:due`). Required for a calendar. A datetime is placed on the day it falls on in the viewer's time zone (the one in their Settings, else the space owner's, else UTC), and shows its time. The space's writers can drag an item to another day, or use its "Move to date" form; a datetime keeps its time of day, unless dropped on an hour of a week (`period:week`), which sets that hour. Everybody else sees the calendar read-only. With view:timeline, a date or datetime field printed under each step's title (`date:at`). The order is the fence's sort.
-
endstring - With view:calendar, the field each row ends at, of the same kind as `date` (`end:until`). A row with an end lasts: on a datetime it shows its time range, over several days it is drawn on each of them, and one that began before the period shown is shown from its first day. Moving items is not offered while an end is bound.
-
rowsstring - With view:calendar, lays the period out as a rota: one row per value of this field (a select's options in their order, or a text field's values), the days as columns, and a last row for the rows that have none. Moving items is not offered on a rota.
-
markstring - With view:calendar rows:, a row this field is set on (true, or any option) is drawn as a label on its cell's ground — OFF, Sick — instead of as an item.
-
donestring - With view:checklist, the boolean field each row's checkbox shows and sets (`done:packed`). Required for a checklist. The space's writers tick and untick the boxes, which saves the field at once; everybody else sees them disabled. Not the @checklist block, which keeps ticks in the reader's browser.
-
tagsstring - With view:checklist, an open tags field: writers search existing tags or create one while working, with automatic colors. Several tags can describe each row without marking it done.
-
statestring - With view:timeline, the field each step's marker shows: a select whose options are done, current, upcoming, error and skipped, or one mapped to them with states:; or a boolean, done when true.
-
heightenum - With view:board or view:calendar, how tall a column (or a week's day) may grow before its cards scroll inside it: short, medium (the default, about two thirds of the screen), tall, screen, or auto (no bound: the column grows the page). A theme or a page changes the default with --nt-board-height. Allowed: auto, short, medium, tall, screen
-
columnslist - With view:board, which options of the `group` field become columns, in this order, comma separated (`columns:"todo,doing,review"`). Rows holding any other option, or none, are not on the board and take none of its `limit`. Without it, every option is a column, in the schema's order.
-
wipstring - With view:board, work-in-progress limits per column, as option=limit pairs separated by commas (`wip:"doing=3,review=2"`). The column's count shows as "n/limit", counted over every row the board's filters let through (not only the cards shown), and its header is marked when the count is over the limit. Moves are not refused.
-
periodenum - With view:calendar, month (the default: whole weeks) or week (seven days), each week from the day `week_start` names (Monday by default). Readers move to the previous or next period, or back to today, with links beside the title; only the rows of the period shown are read, up to `limit`. Allowed: month, week
-
hoursenum - With view:calendar period:week on a datetime, the hours drawn: auto (the default) from 8 to 18, reaching earlier or later when an item does; work, 8 to 18; full, the whole day. Each item sits at its time, as long as it lasts, beside the ones it overlaps; a narrow page lists them instead. Allowed: auto, work, full
-
week_startenum - With view:calendar, the day each week starts on: monday (the default, ISO 8601), sunday or saturday — the same for every reader of the page. Allowed: monday, sunday, saturday
-
startstring - With view:calendar, the day whose period the page opens on instead of today's: a date (`start:2026-10-13`) or a day counted from the reader's today as @filter counts it (`start:today+2d`, `start:-1w`), within ten years of today. Readers still move to the previous or next period, and "Today" takes them to today's.
-
statesstring - With view:timeline state:, how the field's values map to a step's states, as value=state pairs separated by commas: `states:"Entregue=done, Em trânsito=current, Falhou=error"`. A value it does not name, and one that is a state's own name, keep their own.
-
itemstring - With view:timeline, a component of the theme the page wears that draws each step (`item:passo`): the row's fields fill the component's slots of the same names, as text, and a list of the component (`list fotos: url`) one entry per value of the field of its name — each option of a multi_select or tags, each line of a text, its fields separated by `|`. The step's marker is still the row's state:. With view:item (where it is required), the component that draws each row the filters select, whole.
-
directionenum - With view:timeline, vertical (the default) runs down the page; horizontal runs across as a stepper and turns vertical when the page is narrow. Allowed: vertical, horizontal
-
fieldstring - With view:field, the field shown as a control the space's writers change in place (`field:status`): a select for a select, checkboxes for a multi_select, chips for tags, a checkbox for a boolean, a date (or date and time) input, a number input, a text box for text, long_text, email and url. A reference, a file, a computed field and created_at show their value. Everybody else sees the value. For several fields use `fields:status,due,done` instead (one or the other).
-
overstring - With view:cards, the @column written across the bottom of each card's picture, in white on a darkened band (a price, a date): `over:preco`.
-
ratioenum - With view:cards, the shape each card's picture is cropped to (4/3 when left out). Allowed: 4/3, 5/4, 9/7, 3/2, 1/1, 16/9, 3/4
-
per_rowenum - With view:cards, at most this many cards per row on a wide screen (as many as fit when left out); a phone gets one. Allowed: 2, 3, 4
-
gapenum - With view:cards, the room between the cards, a step of the theme's scale like a :::grid's space: (3 when left out; 2 is a listing's tight 16px). Allowed: 1, 2, 3, 4, 5
-
column_gapenum - With view:cards, the room between cards side by side, in px (column_gap:24); beside gap:, it wins for the columns. Allowed: 8, 12, 16, 24, 32, 40
-
row_gapenum - With view:cards, the room between rows of cards, in px (row_gap:12); beside gap:, it wins for the rows. Allowed: 8, 12, 16, 24, 32, 40
-
photo_heightenum - With view:cards, each picture this tall in px whatever the card's width (photo_height:254), cropped to fill; instead of ratio:. Allowed: 200, 220, 240, 254, 280, 300
-
insetenum - With view:cards, room inside the grid's left and right edges, in px (inset:12), as a grid whose cards carry half a gutter each is drawn. Allowed: 8, 12, 16, 24
-
layoutenum - With view:cards, `carousel` puts the cards in one row that scrolls sideways, each stop a card at the row's start: touch, trackpad, the arrow keys with the row focused, and Previous/Next buttons once a script runs; nothing moves by itself. `per_row:` is the most that show at once (cards keep a listing card's width, so a narrow screen shows fewer); `limit:` is how many it holds, the first ones in the sort, with no pages. grid (the default) wraps them in rows. Allowed: grid, carousel
-
buttonstring - With view:cards, a small button under each card's lines, to the title's link: `button:"Details"`, or with an icon of the set first, `button:"icon:plus Details"`.
-
members_ofstring - A group, by name or id: only its members (and whoever edits the page) see this block; everybody else sees a line saying so, with the group's door. Nothing of the block reaches them — not on the page, not in its Markdown, not through the MCP, the search or their calendar feed (an @event is on its members' and editors' feeds only).
-
consentstring - A flag the reader must have allowed before this block shows (`consent:videos`; several, separated by spaces). It has to be one a `@consent` on this site offers.
Body
One instruction per line. Optional children: `@filter field op value` (op: eq, ne, gt, gte, lt, lte, contains, contains_any, in, nin; `in` and `nin` take a,b; every line must hold; a field takes each op once, but `ne` may repeat, each line leaving out one more value: `@filter state ne done` + `@filter state ne dropped`), `@column field label:"…" format:… icon:…` (one field of this collection; `icon:` an icon of the set drawn before the value; a reference like `@column prova` prints the row it points at, and there are no dotted paths; `format:image` on a url or text field shows the picture as a thumbnail kept on this site, and a click opens it; a file of this site — a /f/<token>/<name> path, what an upload gives — shows itself, and on a url or text field `format:video` plays it in a small inline player and `format:file` links it for download under its name), and the metrics `@count`, `@sum field`, `@avg field`, `@min field`, `@max field`, each with an optional `label:"…"`; `by:<select field>` on `@count`, `@sum` and `@avg` gives one line per option, in the schema's order (`@sum valor by:categoria`).
Accepted children
@filter, @column, @count, @sum, @avg, @min, @max
@diff
renders: server
A patch as a review reads it — what `git diff` prints — one section per file, coloured by language, stacked or side by side. Select a line to annotate it.
Server rendered.
Example
~~~@diff title:"Greeting takes a mark"
--- a/greeting.rb
+++ b/greeting.rb
@@ -1,3 +1,3 @@
def hello(name)
- "Hello, #{name}"
+ "Hello, #{name}!"
end
~~~
Arguments
-
titlestring - A line above the files: what the change is.
-
members_ofstring - A group, by name or id: only its members (and whoever edits the page) see this block; everybody else sees a line saying so, with the group's door. Nothing of the block reaches them — not on the page, not in its Markdown, not through the MCP, the search or their calendar feed (an @event is on its members' and editors' feeds only).
-
consentstring - A flag the reader must have allowed before this block shows (`consent:videos`; several, separated by spaces). It has to be one a `@consent` on this site offers.
Body
Free text. The patch: the output of `git diff` (or any unified diff). Fence it with ~~~ so the backticks inside a patch stay text.
@event
renders: server
A moment to put in a calendar: the date and time, how long, where — printed, with a Google Calendar link and an .ics file for Apple and Outlook.
Server rendered.
Example
```@event to:2026-10-17T14:00-03:00 duration:60 title:"First meeting" where:https://meet.example/abc zone:America/Sao_Paulo
```
Arguments
-
tostring Required - When it starts, as 2026-10-17T14:00-03:00. With no offset it is read as UTC; a date alone is its first minute.
-
titlestring Required - What the calendar entry is called.
-
durationinteger Default: 60 - How long it lasts, in minutes (5 to 1440). Defaults to 60. Allowed: 5 to 1440
-
wherestring - Where it happens: a place, or the address of the call (https://…).
-
detailsstring - A line for the calendar entry's notes: what to read, what to bring.
-
zonestring - The time zone the moment is printed in, as the tz database names it (America/Sao_Paulo). Without it the moment is printed in UTC.
-
members_ofstring - A group, by name or id: only its members (and whoever edits the page) see this block; everybody else sees a line saying so, with the group's door. Nothing of the block reaches them — not on the page, not in its Markdown, not through the MCP, the search or their calendar feed (an @event is on its members' and editors' feeds only).
-
consentstring - A flag the reader must have allowed before this block shows (`consent:videos`; several, separated by spaces). It has to be one a `@consent` on this site offers.
Body
This component takes no body.
@flashcards
renders: server
A deck of cards to drill: a term and its meaning, a question and its answer, a word and its translation — or a self-test, with questions the reader answers and a score. One card per line, front | back; a line of three parts or more is a multiple-choice question. Turned by a click or the keyboard; printed in full, answers included, without a script.
Server rendered.
Example
```@flashcards label:"DNS do envio"
SPF | Diz quais servidores podem enviar em nome do domínio.
DKIM | Assina cada mensagem; o destinatário confere no DNS.
```
```@flashcards label:"Self-test"
Which port does a mail client submit on? | 587 :: The submission port, with STARTTLS. | 25 :: Port 25 is for servers talking to servers. | 80 | 443
Which record signs each message? | DKIM | SPF :: SPF names the servers; it signs nothing. | MX
```
Arguments
-
labelstring - A line above the deck saying what it drills.
-
members_ofstring - A group, by name or id: only its members (and whoever edits the page) see this block; everybody else sees a line saying so, with the group's door. Nothing of the block reaches them — not on the page, not in its Markdown, not through the MCP, the search or their calendar feed (an @event is on its members' and editors' feeds only).
-
consentstring - A flag the reader must have allowed before this block shows (`consent:videos`; several, separated by spaces). It has to be one a `@consent` on this site offers.
Body
One instruction per line. One card per line. `front | back` is a card that turns. `question | right answer | wrong | wrong …` is a multiple-choice question: the FIRST answer after the question is the right one, and the options are shown shuffled (the same order on every render, so it works printed and without a script). An option may say why after ` :: ` (a space, two colons, a space): `25 :: Port 25 is server to server.` — shown once the reader picks. The reader's picks and score stay in their browser; to keep each learner's answers on the server, use a @form with scope:viewer.
@form
renders: server
A form that writes a row into a collection of this space. Only renders for somebody the collection accepts.
Server rendered.
Example
```@form collection:inscricoes submit:"Quero entrar"
nome
email required
```
```@form collection:lista layout:inline submit:"Assinar"
email required
```
```@form collection:inscricoes mode:edit own:true
nome
email required
```
```@form collection:inscricoes preview:true
nome
email required
```
```@form collection:anuncios labels:inside button:full submit:"Enviar cadastro"
## 1. Owner
nome
telefone width:1/2
email width:1/2
## 2. The property
rua width:3/4
numero width:1/4
```
In the template a ```route draws each obituary with (`:slug to: obituario collection: obituarios`), its condolence wall:
```@form collection:condolencias submit:"Leave a condolence"
obituario from:params.slug
nome required
mensagem long_text
```
```@data collection:condolencias
@filter obituario eq params.slug
@column nome
@column mensagem
```
Arguments
-
collectionstring Required - The name of the collection inside this space, without the @space prefix: lowercase letters, digits and hyphens, 2 to 40 characters (coord-agents, never coord_agents — field names take underscores, collection names do not).
-
successstring - What to say after a row goes in. Defaults to a thank-you.
-
submitstring - The label of the button. Defaults to "Send".
-
scopeenum - viewer: require sign-in and attribute the row to the sender. Use scope:viewer on reads to show only that person's rows; collection visibility still controls other reads. Allowed: viewer
-
modeenum Default: create - create: a form that adds a row. edit: a form that changes one of the viewer's own rows; it needs own:true. To change any row's fields, a writer uses `@data view:field fields:…` (edits them inline) or the Collections screen. Allowed: create, edit
-
layoutenum Default: stacked - stacked: one field under the other, each with its label. inline: the fields and the button in one row — for a signup of one or two fields; the labels become the hints inside the fields and stay readable to a screen reader. Allowed: stacked, inline
-
labelsenum Default: above - above: each field's name over it. inside: the name is the hint written in the empty field, and a select opens on it — how a site's contact or listing form is drawn; a screen reader still reads the label. A checkbox keeps its label beside it. Allowed: above, inside
-
buttonenum Default: auto - full: the send button takes the form's whole width, as a long site form ends. Allowed: auto, full
-
shapeenum Default: default - pill: fully rounded fields and button, the fields on the ground of the band they stand on (a dark footer keeps them dark). With `submit:"icon:arrow-right"` the button is a round icon alone, its name still read to a screen reader. Allowed: default, pill
-
textenum Default: inherit - The size of the fields' and the button's words in px (text:14), whatever the text around the form; inherit keeps it. Allowed: inherit, 12, 13, 14, 15, 16
-
ownboolean Default: false - true: list the rows this viewer created, each with a link that opens it in the form. Signed-in people only.
-
previewboolean Default: false - true: the form as it would look — fields, labels, layout, the button's words — with the button disabled and a note that it sends nothing, shown to whoever may read the collection or send through it, even when the collection accepts nobody; anyone else gets the closed notice. No form element and no address to send to, so nothing is ever written. For the docs, a theme's or a template's preview, a mockup.
-
members_ofstring - A group, by name or id: only its members (and whoever edits the page) see this block; everybody else sees a line saying so, with the group's door. Nothing of the block reaches them — not on the page, not in its Markdown, not through the MCP, the search or their calendar feed (an @event is on its members' and editors' feeds only).
-
consentstring - A flag the reader must have allowed before this block shows (`consent:videos`; several, separated by spaces). It has to be one a `@consent` on this site offers.
Body
One instruction per line. One field per line, a subset of the collection's schema: `email required`, `nome`, `mensagem long_text`. Options must match the collection schema; change @schema first to override them. `width:1/2` on a line (1/4 1/3 1/2 2/3 3/4 full) puts fields side by side, on a phone one under the other. A line that starts with `#` is a section title inside the form (`## 2. The property`). A `file` field takes a picture (JPEG, PNG, WebP, GIF or HEIC, up to 10 MB), kept as the row's own file: only readers of the collection see it, and it counts against the space owner's storage. Empty body: every writable field, in schema order. `from:` on a line makes it a field THE PAGE FILLS, drawn as no input: `obituario from:params.slug` in the template a ```route draws each obituary with writes that row's slug into every condolence sent from its page (also `page.slug`, `page.name`, `page.parent`, as a @data filter reads them). The server sets the value from the page the form was drawn on, asked for again at the submit (the row still there and readable by the sender); whatever the browser sends for it is ignored, so nobody posts onto another row by editing the request. On a page that gives no value (the template opened on its own) the field is left out.
@hours
renders: server
When a place is open: the week, printed, and "open now" by the clock of the place. For a venue, a shop, a clinic, a contact page.
Server rendered.
Example
```@hours zone:America/Sao_Paulo notice:"Closed on the 12th"
mon-fri 11:30-15:00, 18:00-23:00
sat 12:00-00:00
sun closed
```
Arguments
-
zonestring Required - The time zone of the place, as the tz database names it: America/Sao_Paulo, Europe/Lisbon. "Open now" is read on that clock, not the reader's.
-
titlestring - A heading over the week.
-
noticestring - One line under the week: a holiday, new hours, "kitchen closes 30 minutes earlier".
-
members_ofstring - A group, by name or id: only its members (and whoever edits the page) see this block; everybody else sees a line saying so, with the group's door. Nothing of the block reaches them — not on the page, not in its Markdown, not through the MCP, the search or their calendar feed (an @event is on its members' and editors' feeds only).
-
consentstring - A flag the reader must have allowed before this block shows (`consent:videos`; several, separated by spaces). It has to be one a `@consent` on this site offers.
Body
One instruction per line. One line per day or run of days, then the hours: `mon-fri 09:00-18:00`, `sat 10:00-14:00, 16:00-20:00`, `sun closed`. Days in English or Portuguese. An end before the start runs past midnight.
@members
renders: server
The people in a group: name, a line about them, who runs it. Shown only to those the group lets see its list (its managers; its members when the group says so). Nothing for anybody else.
Server rendered.
Example
```@members group:"Turma 3" label:"Quem está na turma"
```
Arguments
-
groupstring Required - The group, by name or id. A name must be one you stand in, or a group with a door (by_request, open).
-
labelstring - A line above the list.
-
members_ofstring - A group, by name or id: only its members (and whoever edits the page) see this block; everybody else sees a line saying so, with the group's door. Nothing of the block reaches them — not on the page, not in its Markdown, not through the MCP, the search or their calendar feed (an @event is on its members' and editors' feeds only).
-
consentstring - A flag the reader must have allowed before this block shows (`consent:videos`; several, separated by spaces). It has to be one a `@consent` on this site offers.
Body
This component takes no body.
@pages
renders: server
Also written ```pages
A gallery of pages, each one a picture of itself: the pages inside a folder (`from:`), or the pages listed in the body. Only pages the reader may open are shown.
Server rendered.
Example
```@pages from:/@docs/showcase columns:2
```
Arguments
-
columnsinteger Default: 3 - How many cards per row (1–4). Defaults to 3. Allowed: 1 to 4
-
fromstring - A folder: its path (/@you/work), or ~/work for a folder of the space this page is in. Its pages with something written are the gallery, in the order they were made, and a new page joins it by itself — the way to keep a section's hub. Without it, the pages listed in the body.
-
limitinteger Default: 12 - How many cards at most (1–48). Defaults to 12. A list in the body longer than this shows its first ones, and validate warns. Allowed: 1 to 48
-
members_ofstring - A group, by name or id: only its members (and whoever edits the page) see this block; everybody else sees a line saying so, with the group's door. Nothing of the block reaches them — not on the page, not in its Markdown, not through the MCP, the search or their calendar feed (an @event is on its members' and editors' feeds only).
-
consentstring - A flag the reader must have allowed before this block shows (`consent:videos`; several, separated by spaces). It has to be one a `@consent` on this site offers.
Body
One instruction per line. Without `from:`, one page path per line. `/a/section | /a/section/one` links to the first and pictures the second.
@patterns
renders: server
The section pattern library: every pattern, grouped, with a link to it rendered and its markdown to copy.
Server rendered.
Example
```@patterns
```
Arguments
-
members_ofstring - A group, by name or id: only its members (and whoever edits the page) see this block; everybody else sees a line saying so, with the group's door. Nothing of the block reaches them — not on the page, not in its Markdown, not through the MCP, the search or their calendar feed (an @event is on its members' and editors' feeds only).
-
consentstring - A flag the reader must have allowed before this block shows (`consent:videos`; several, separated by spaces). It has to be one a `@consent` on this site offers.
Body
This component takes no body.
@pdf
renders: server
A page of a PDF uploaded to this site, drawn in the page (or a few, pages:18-19). Only that page's bytes are fetched; a click opens the PDF in the site's viewer at that page. Without a script, or printed, it is a link to the viewer at that page.
Server rendered.
Example
```@pdf src:/f/k3Fq9ZrX2mB7vT1wLp8sYa/curso.pdf page:18 title:"Figure 3: the request cycle"
```
Arguments
-
srcpath Required - The PDF's address on this site, /f/<token>/<name>.pdf, as `files` lists it. Starts with a single / — "//host/x" is another site, not a path. No #page= here: the page is page:.
-
pageinteger Default: 1 - The page drawn. 1 by default. Allowed: 1 to 100000
-
pagesstring - A range of pages drawn one under the other, first-last: pages:18-19. At most 4. Instead of page:.
-
titlestring - A short line shown under the page.
-
heightinteger - The most pixels tall a page is drawn. By default a page fits the width of the column. Allowed: 120 to 2000
-
members_ofstring - A group, by name or id: only its members (and whoever edits the page) see this block; everybody else sees a line saying so, with the group's door. Nothing of the block reaches them — not on the page, not in its Markdown, not through the MCP, the search or their calendar feed (an @event is on its members' and editors' feeds only).
-
consentstring - A flag the reader must have allowed before this block shows (`consent:videos`; several, separated by spaces). It has to be one a `@consent` on this site offers.
Body
This component takes no body.
@posts
renders: server
The pages inside a folder as a list of posts, newest first: title, date and a line each. The date is the page's ```meta date:, else the day it was made. Only pages the reader may open are listed; a public folder also offers its RSS and Atom feeds.
Server rendered.
Example
```@posts limit:5
```
Arguments
-
frompath - The folder whose pages are listed. Without it, the page the block is on.
-
limitinteger Default: 10 - How many posts, the newest first (1–50). Defaults to 10. Allowed: 1 to 50
-
feedboolean Default: true - false: leave out the links to the folder's RSS and Atom feeds.
-
members_ofstring - A group, by name or id: only its members (and whoever edits the page) see this block; everybody else sees a line saying so, with the group's door. Nothing of the block reaches them — not on the page, not in its Markdown, not through the MCP, the search or their calendar feed (an @event is on its members' and editors' feeds only).
-
consentstring - A flag the reader must have allowed before this block shows (`consent:videos`; several, separated by spaces). It has to be one a `@consent` on this site offers.
Body
This component takes no body.
@qr
renders: server
A QR code of this page, or of another address: for a table, a slide, a poster, a card. Dark on white whatever the theme, so a camera reads it.
Server rendered.
Example
```@qr label:"Abra esta página no celular"
```
Arguments
-
tostring - What the code opens: a path of this site (/@ana/menu) or a web address starting with https://. Without it, the page the block is on.
-
labelstring - A line under the code, saying what it opens.
-
sizeenum Default: medium - How large it is drawn on the screen. It prints sharp at any size. Allowed: small, medium, large
-
colorstring - The colour of the code itself, as #rrggbb. Dark enough to read against the background, or the block says so.
-
backgroundstring - The colour behind the code, as #rrggbb. White by default, which is what a camera likes best.
-
eyestring - The colour of the three corner squares, as #rrggbb. The colour of the code by default.
-
shapeenum Default: square - The shape of the small modules: square, dots or rounded. The corner squares stay square whatever this says. Allowed: square, dots, rounded
-
logostring - A mark in the middle: `brand` (the mark of this site), `none`, or the path of an image on this site (/demo/mark.png).
-
members_ofstring - A group, by name or id: only its members (and whoever edits the page) see this block; everybody else sees a line saying so, with the group's door. Nothing of the block reaches them — not on the page, not in its Markdown, not through the MCP, the search or their calendar feed (an @event is on its members' and editors' feeds only).
-
consentstring - A flag the reader must have allowed before this block shows (`consent:videos`; several, separated by spaces). It has to be one a `@consent` on this site offers.
Body
This component takes no body.
@schema
renders: server
Declares the fields of a collection of this space. Whoever edits the page sees the declaration (a reader gets nothing in its place); only somebody with settings on the space can apply it.
Server rendered.
Example
```@schema collection:inscricoes accepts:anyone
nome text required
email email required label:"E-mail"
prova reference:provas
```
Arguments
-
collectionstring Required - The name of the collection inside this space, without the @space prefix: lowercase letters, digits and hyphens, 2 to 40 characters (coord-agents, never coord_agents — field names take underscores, collection names do not).
-
visibilityenum Default: private - Who may READ the rows: private (the space's people) or public (anyone). Private by default. Allowed: private, public
-
acceptsenum Default: nobody - Who may send a row through an @form: nobody, members (people a role on the space root reaches) or anyone (in a private space: anyone who reads a published page holding the form; a page anyone may edit opens nothing). Nobody by default. Allowed: nobody, members, anyone
-
calendarstring - A date or datetime field that puts every row on the calendar of the space's own people who may read the collection: their calendar feed (Settings → Preferences) shows each row on its date, with their @remind lines as alarms. The field is indexed as if it said `indexed`. Only the space's owner applies it.
-
members_ofstring - A group, by name or id: only its members (and whoever edits the page) see this block; everybody else sees a line saying so, with the group's door. Nothing of the block reaches them — not on the page, not in its Markdown, not through the MCP, the search or their calendar feed (an @event is on its members' and editors' feeds only).
-
consentstring - A flag the reader must have allowed before this block shows (`consent:videos`; several, separated by spaces). It has to be one a `@consent` on this site offers.
Body
One instruction per line. One field per line: `name type [required] [indexed] [label:"…"]`. The types: text, long_text, number, boolean, date, datetime, email, url, select, multi_select, tags, file, reference, computed. A type may carry its argument: `select:a,b` (an option with spaces in quotes: `select:"in progress",passed`), `reference:outra`, `computed:sum(outra.valor)` (count, sum, avg, min or max; sum and avg take a number, min and max a number, a date or a datetime and answer in its type: `computed:min(tasks.due)` is a project's earliest due date). Indexed date/datetime fields do not accelerate temporal comparisons. `default:<value>` is what a new row takes when it arrives without the field or with it empty, at every door (a form, the screen, upsert_records): a value the type can hold, one of a select's options (`status select:open,closed default:open`; not on computed, file, reference, multi_select or tags). `doors:` names the only doors that may set or change the field (form, board, calendar, checklist, field, screen, mcp, import, group, feedback, system): `state select:todo,done doors:board,field,screen` refuses an upsert_records (mcp) that sets or changes state, naming the field, and lets one that leaves it alone through. A `@hook` line POSTs the changes of the rows to a URL after they are saved, signed with the collection's secret: `@hook on:updated field:status to:Ready url:https://…`. `on:` created, updated, deleted, restored (all four when left out, created and updated when the line has a `field:`); `field:` only when that field changed; `from:`/`to:` what it changed from/to, a value the field's type can hold; `source:` only through these doors (form, board, calendar, checklist, field, screen, mcp, import, group, feedback, system); `url:` https, a public host, port 443, 80 or 1024 and up. Only the space's owner applies hooks and sees their secret and deliveries (Collections screen); whoever edits the page reads the @hook lines in its source, a reader never gets them. A `@remind` line reminds people of a date field of the rows: `@remind field:due before:1d,1h to:field:assignee`. `field:` a date or datetime field; `before:` 15m, 1h, 1d, 1w (comma-separated, days and weeks only on a date field); `at:HH:MM` a time on the recipient's clock (a date field without it fires at 09:00); `to:` owner (the default), field:<an e-mail or text field naming an account> or group:<a group with a role on the space>; `via:` email (the default, Pro), hook (the `reminder` event a `@hook on:reminder` line forwards) or calendar (only an alarm on the row in the calendar feed of each person `to:` names, on every plan; the collection needs `calendar:` on that field). Only the space's own people (its owner, a role on it they opened, a member of a group with a role on it) who may read the collection are reminded, at most 50 reminder e-mails a day each; a reader never gets the @remind lines. Reserved field names: the row's own (`id`, `extra`, `record`, `included`, `data`, `resolved`, `created_at`, `updated_at`, `created_by`, `initialize`) and the methods every row answers to (`abort`, `as_json`, `assign_attributes`, `at_exit`, `attribute`, `attribute_aliases`, `attribute_method_patterns`, `attribute_missing`, `attribute_names`, `attribute_writer_missing`, `attributes`, `autoload`, `binding`, `caller`, `caller_locations`, `catch`, `class`, `class_eval`, `clone`, `concern`, `context_for_validation`, `deep_dup`, `define_singleton_method`, `display`, `display_label`, `dup`, `enable_warnings`, `enum_for`, `errors`, `eval`, `exec`, `exit`, `extend`, `fail`, `fork`, `format`, `freeze`, `gem`, `gem_original_require`, `gets`, `global_variables`, `halted_callback_hook`, `hash`, `historical_scalar_value`, `init_internals`, `initialize_clone`, `initialize_copy`, `initialize_dup`, `inspect`, `instance_eval`, `instance_exec`, `instance_values`, `instance_variable_get`, `instance_variable_names`, `instance_variable_set`, `instance_variables`, `instance_variables_to_inspect`, `itself`, `j`, `jj`, `lambda`, `load`, `local_variables`, `loop`, `matched_attribute_method`, `method`, `method_missing`, `methods`, `missing_attribute`, `model_name`, `no_warning_require`, `object_id`, `open`, `p`, `pp`, `presence`, `presence_in`, `pretty_inspect`, `pretty_print`, `pretty_print_cycle`, `pretty_print_inspect`, `pretty_print_instance_variables`, `print`, `printf`, `private_methods`, `proc`, `protected_methods`, `public_method`, `public_methods`, `public_send`, `putc`, `puts`, `raise`, `raise_validation_error`, `rand`, `raw_field_value`, `read_attribute_for_validation`, `readline`, `readlines`, `remove_instance_variable`, `require`, `require_dependency`, `require_relative`, `require_without_bootsnap`, `run_callbacks`, `sanitize_for_mass_assignment`, `sanitize_forbidden_attributes`, `select`, `send`, `set_trace_func`, `silence_warnings`, `singleton_class`, `singleton_method`, `singleton_method_added`, `singleton_method_removed`, `singleton_method_undefined`, `singleton_methods`, `sleep`, `slice`, `spawn`, `sprintf`, `srand`, `suppress`, `syscall`, `system`, `tap`, `test`, `then`, `throw`, `to_enum`, `to_json`, `to_key`, `to_model`, `to_param`, `to_partial_path`, `to_query`, `to_s`, `to_yaml`, `trace_var`, `trap`, `try`, `untrace_var`, `validate`, `validates_absence_of`, `validates_acceptance_of`, `validates_comparison_of`, `validates_confirmation_of`, `validates_exclusion_of`, `validates_format_of`, `validates_inclusion_of`, `validates_length_of`, `validates_numericality_of`, `validates_presence_of`, `validates_size_of`, `validates_with`, `validation_context`, `values_at`, `warn`, `with`, `with_options`, `with_warnings`, `yield_self`, `zeitwerk_original_require`). A hyphen reads as an underscore, so `created-at` is reserved too.
Accepted children
@hook, @remind
@themes
renders: server
The starting themes: every whole look an author can begin from, drawn in its own colours, with its theme fence to copy.
Server rendered.
Example
```@themes
```
Arguments
-
members_ofstring - A group, by name or id: only its members (and whoever edits the page) see this block; everybody else sees a line saying so, with the group's door. Nothing of the block reaches them — not on the page, not in its Markdown, not through the MCP, the search or their calendar feed (an @event is on its members' and editors' feeds only).
-
consentstring - A flag the reader must have allowed before this block shows (`consent:videos`; several, separated by spaces). It has to be one a `@consent` on this site offers.
Body
This component takes no body.
@tokens
renders: server
A theme's tokens, drawn: its colours as swatches with their codes, and its typefaces as a sample — the preview of a design system kept in a page.
Server rendered.
Example
```@tokens from:/@ana/design
```
Arguments
-
frompath - The page whose theme is drawn: a path of this site (/@ana/design). Without it, the page the block is on.
-
members_ofstring - A group, by name or id: only its members (and whoever edits the page) see this block; everybody else sees a line saying so, with the group's door. Nothing of the block reaches them — not on the page, not in its Markdown, not through the MCP, the search or their calendar feed (an @event is on its members' and editors' feeds only).
-
consentstring - A flag the reader must have allowed before this block shows (`consent:videos`; several, separated by spaces). It has to be one a `@consent` on this site offers.
Body
This component takes no body.
@use
renders: server
A component of the theme this page wears (the theme's screen lists them, with when to use each and its slots), filled with this page's words.
Server rendered.
Example
```@use cartao-de-curso
titulo: Torno para iniciantes
data: Sáb · 14 jun
```
Arguments
-
namestring Required - The component's name, as its theme lists it: `cartao-de-curso`. Written alone after @use.
-
members_ofstring - A group, by name or id: only its members (and whoever edits the page) see this block; everybody else sees a line saying so, with the group's door. Nothing of the block reaches them — not on the page, not in its Markdown, not through the MCP, the search or their calendar feed (an @event is on its members' and editors' feeds only).
-
consentstring - A flag the reader must have allowed before this block shows (`consent:videos`; several, separated by spaces). It has to be one a `@consent` on this site offers.
Body
Free text. One slot per line, `slot: words`; a list, one line per entry, its fields in the component's order: `etapas: Pedido criado | done | 10 mar`. A link or a picture slot takes an address (/…, https://…).
@video
renders: server
A video player over a file uploaded to this site. Controls on, nothing autoplays.
Server rendered.
Example
```@video src:/f/k3Fq9ZrX2mB7vT1wLp8sYa/demo.mp4 title:"Como aplicar o esquema"
```
Arguments
-
srcpath Required - Path of the file on this site, usually an upload of the page. Starts with a single / — "//host/x" is another site, not a path.
-
titlestring - A short title shown under the player.
-
preloadenum Default: metadata - How much the browser fetches before play: none, metadata or auto. Allowed: none, metadata, auto
-
posterpath - Path of an image shown before play. Starts with a single / — "//host/x" is another site, not a path.
-
modeenum Default: player - player shows controls and never autoplays; background plays muted, looped and without controls, for the ground of a :::hero (paused when the reader asks for reduced motion). Allowed: player, background
-
members_ofstring - A group, by name or id: only its members (and whoever edits the page) see this block; everybody else sees a line saying so, with the group's door. Nothing of the block reaches them — not on the page, not in its Markdown, not through the MCP, the search or their calendar feed (an @event is on its members' and editors' feeds only).
-
consentstring - A flag the reader must have allowed before this block shows (`consent:videos`; several, separated by spaces). It has to be one a `@consent` on this site offers.
Body
This component takes no body.
@whatsapp
renders: server
The round WhatsApp button in a site's corner: one tap opens the conversation with the message already written.
Server rendered.
Example
```@whatsapp number:"+55 21 95550-0134" message:"Olá! Vi o site e quero mais informações."
```
Arguments
-
numberstring Required - The WhatsApp number, with the country code: "+55 21 98519-2305".
-
messagestring - What the conversation starts with, already written for the person.
-
labelstring - What a screen reader says, and the hint on hover. Defaults to "Talk on WhatsApp" in the page's language.
-
positionenum Default: corner - corner: on a site, fixed in the bottom corner while the page scrolls. inline: where it is written. Allowed: corner, inline
-
members_ofstring - A group, by name or id: only its members (and whoever edits the page) see this block; everybody else sees a line saying so, with the group's door. Nothing of the block reaches them — not on the page, not in its Markdown, not through the MCP, the search or their calendar feed (an @event is on its members' and editors' feeds only).
-
consentstring - A flag the reader must have allowed before this block shows (`consent:videos`; several, separated by spaces). It has to be one a `@consent` on this site offers.
Body
This component takes no body.
@chart
renders: client
Also written ```chart
A chart or a table, drawn from CSV: bars, stacked bars, a line, an area, a pie, a donut, a scatter or bubble plot, a heatmap, a waterfall. A reader can point at a value and hide a series.
Rendered in the browser.
Example
```@chart type:line
title: Pages published
markers: Feb=Launch
---
month,pages
Jan,3
Feb,7
```
Arguments
-
typeenum Default: bar - Which drawing. `stacked` piles the series of a bar chart; `pie` and `donut` read the first series, one slice per row. `scatter` reads x and y from the first two number columns and sizes a bubble by an optional third; `heatmap` fills a cell per row and column by its value and prints it; `waterfall` reads one column: the first row is the start total, the last the end total (blank to compute it), the rows between are signed contributions. Allowed: bar, stacked, line, area, pie, donut, scatter, heatmap, waterfall, table
-
titletitulostring - Printed above the chart.
-
markersmarcosstring - Moments on the category axis, as category=label pairs separated by semicolons: `markers: Jun=Launch; Aug=New price`. Each is a dashed line with its label, outside the series and the legend, and said in words under the chart. A pair naming no category of the data is left out.
-
lookenum - `editorial`: the chart on diagram-design's fixed 1000 px sheet, its reference geometry for the type (axes, bar widths, label positions), in the page's colours; the sheet scales down on a phone. `page` (the default): the chart laid out at the page's width. Allowed: page, editorial
-
focalfocostring - The one item drawn in the page's accent, the rest in the series palette, the way diagram-design marks one element: a row (`focal: S5`), a series (`focal: plates`), or in a heatmap a `row,column` cell (`focal: payments,S4`). Exactly one; a second name after a comma is refused, and so is a name the data has not. The legend and the table mark it with ★, so the hue is never the only sign.
Body
CSV, or the whole block as JSON. CSV: the first row names the columns, the first column labels the category axis. The whole body may be JSON instead.
@chat
renders: client
Also written ```chat
A conversation: one message per line, `who: text` with an optional ` @ time`. `me` (or `eu`) sits on the right.
Rendered in the browser.
Example
```@chat title:Suporte
ana: Oi, chegou?
me: Chegou sim @ 10:42
```
Arguments
-
titletitulostring - The line above the thread.
Body
One message per line. One `who: text @ time` per line.
@checklist
renders: client
Also written ```checklist
A working checklist: it counts, it groups under ## headings, and it remembers — in the reader's own browser, never on the page. For ticks every reader shares and an agent can tick, use @data view:checklist over a collection (manual views).
Rendered in the browser.
Example
```@checklist title:"Antes do deploy"
## Testes
- [ ] Rodar a suite
- [x] Console limpo
```
Arguments
-
titletitulostring - The line above the list.
Body
Items, separated by a --- line. One `- [ ] something` per line, with optional `## Section` headings.
@profile
renders: client
Also written ```profile
The head of a link page: avatar, name, bio and a row of social icons.
Rendered in the browser.
Example
```@profile
name: Nara
bio: A taste of everything
avatar: /demo/nara.svg
instagram: https://instagram.com
```
Arguments
-
namestring Required - The name printed under the avatar.
-
biostring - One paragraph under the name.
-
avatarstring - An image URL, absolute or root-relative.
-
shapeenum Default: circle - The avatar's shape. Allowed: circle, rounded
Body
One link per line. More `platform: url` lines.
@links
renders: client
Also written ```links
Full-width buttons, one per line. A `* ` prefix makes the featured one.
Rendered in the browser.
Example
```@links style:outline
* [Join](https://x.com/join)
[Streams](/streams) every Friday, 8pm
[Live taping](https://x.com/live) July 16 until:2030-07-16
[The mic I use](https://x.com/mic){sponsored}
```
Arguments
-
styleenum - Overrides the theme's button style for this block. Allowed: filled, outline, soft
-
shapeenum - Overrides the theme's button shape for this block. Allowed: square, slight, rounded, pill
Body
One link per line. One `[Label](url)` per line; `` on the line adds a thumbnail; a bare text line is a section heading. Text after the link is a note under the label (`preferred · 20 min`). `from:2026-07-01` and `until:2026-07-16` after the link keep the button on the page only in that window, both days included: a dated link leaves by itself. `{sponsored}` right after the link, as in prose, marks a paid or affiliate button: a visible word and `rel="sponsored nofollow"`.
@reviews
renders: client
Also written ```reviews
A row of review cards, each with its stars.
Rendered in the browser.
Example
```@reviews title:"O que dizem"
★★★★★ Ana
Best bagels in town.
```
Arguments
-
titletitulostring - The line above the row.
Body
Items, separated by a --- line. One review per block, separated by a --- line: `★★★★☆ Name` or `4/5 Name`, then the text.
@faq
renders: client
Also written ```faq
Questions that open, one <details> each.
Rendered in the browser.
Example
```@faq
Do you ship?
Yes, worldwide.
---
Returns?
Within 30 days.
```
Arguments
-
titletitulostring - The line above the questions.
Body
Items, separated by a --- line. One question per block, separated by a --- line: the question line, then the answer.
@embed
renders: client
Also written ```embed
A card that names a provider and links out. Never a frame the reader did not ask for: the page loads no third party inside itself, and with play:here a YouTube or Vimeo video is a poster and a button until the reader presses play (ADR 013).
Rendered in the browser.
Example
Arguments
-
youtubestring - A YouTube URL.
-
spotifystring - A Spotify URL.
-
podcaststring - A podcast URL.
-
videostring - A video URL.
-
calendaragendastring - Where somebody books a time with you: a Cal.com, Calendly or Google Calendar appointment URL.
-
musicmusicastring - A track, an album or a playlist, wherever it lives.
-
applemusicstring - An Apple Music URL.
-
soundcloudstring - A SoundCloud URL.
-
bandcampstring - A Bandcamp URL.
-
deezerstring - A Deezer URL.
-
tiktokstring - A TikTok video or profile URL.
-
instagramstring - An Instagram post or profile URL.
-
twitchstring - A Twitch channel URL.
-
vimeostring - A Vimeo URL.
-
mapstring - An address or a Google Maps URL.
-
mapsstring - The same as map.
-
titletitulostring - The card's first line.
-
notestring - The card's second line.
-
playenum - here: a YouTube or Vimeo video plays in the page, in a 16:9 frame — after the reader presses play, and not before: until then the page holds nothing of the provider, only the poster and a button. The player comes from the provider's no-cookie address (youtube-nocookie.com, Vimeo with dnt). Any other provider stays a card. Allowed: here
-
posterstring - With play:here, the picture shown until the reader presses play: a file of this site (/f/…), never the provider's own thumbnail, which would load the provider before the reader asked.
Body
This component takes no body. This block takes no body.
@diagram
renders: client
Also written ```diagram
A figure drawn from a list, in the editorial manner of diagram-design (cathrynlavery/diagram-design, MIT), each type on its reference geometry, in the page's colours and fonts, with one focal item in the accent: a layer stack, a pyramid or funnel, a loop, a timeline, nested rings, a process or data flow (lanes × steps), a story map, a security matrix, a service blueprint, an exploded view (isometric parts pulled apart), a high-level data stack, a medallion of tiers, a data-platform integration, an architecture delta (before and after, with a ledger of changes), an axonometric plan (a floor or a site seen from above), a tree (a hierarchy by indentation), an org chart (ownership, with callout strips), a dependency graph (ranks, fan-in, one cycle), a polar chart (one series on a dial), a gantt (tasks on weeks, in phases), a sankey (a quantity through three stages), a sequence (lifelines, activations, fragments), a swimlane (steps across team lanes), a flowchart (shapes carry type, labelled branches), a state machine (states, dots, curved returns), a quadrant (a 2×2 of dots) or a scenario matrix, a radar (series over axes), an ER model (entities, cardinality), a UML class diagram (compartments, typed arrows), a venn (sets meeting at one sweet spot), a treemap or marimekko (area as share), a fishbone (causes on bones, one root cause), a wardley map (value chain over evolution), a kanban (columns, WIP chips, card states), a user journey (stages, sentiment curve, pain), a database schema (tables, columns, foreign keys), and `figure`, a placed architecture (nodes on a grid, zones, routed connectors). Optional motion: the items enter one by one, with controls. A mermaid fence still draws any of these in mermaid's grammar (`look:editorial` gives it the same manner). The grammar of every type, with a live example each: /@docs/blocks/diagram; one example per diagram-design type: /@docs/showcase/diagram-design.
Rendered in the browser.
Example
```@diagram type:layers motion:step
title: AI app stack
top: Abstraction
bottom: Silicon
- UI surface · chat, editor, canvas {tag:L5}
- Agent harness · tools, memory, loop {focal tag:L4}
- Prompt layer · system, few-shot, caching {tag:L3}
- SDK / client · auth, retries, streaming {tag:L2}
- Model weights · opus, sonnet, haiku {tag:L1}
```
What it draws
title: AI app stack
top: Abstraction
bottom: Silicon
- UI surface · chat, editor, canvas {tag:L5}
- Agent harness · tools, memory, loop {focal tag:L4}
- Prompt layer · system, few-shot, caching {tag:L3}
- SDK / client · auth, retries, streaming {tag:L2}
- Model weights · opus, sonnet, haiku {tag:L1}
Arguments
-
typeenum Default: layers - Which figure. `layers`: full-width bands stacked top to bottom (a stack, the OSI model, a hierarchy of abstraction). `pyramid`: trapezoids narrowing to an apex, the first item at the top. `funnel`: the same, widest first. `loop`: a hub with 5–8 stations on a ring. `timeline`: events on a baseline at honest positions. `nested`: concentric rings, outer first. `process` and `data-flow`: lanes × steps with nodes, chips and arrows. `story-map`: a backbone of activities and slices of cards with a release cut. `dp-security-matrix`: roles × components with an access level per cell. `service-blueprint`: stages × layers with the line of visibility. Each one's lines are described at /@docs/blocks/diagram. Allowed: layers, pyramid, funnel, loop, timeline, nested, process, data-flow, story-map, dp-security-matrix, service-blueprint, figure, exploded, high-level, medallion, dp-integration, architecture-delta, axonometric-plan, tree, org-chart, dependency, polar, gantt, sankey, sequence, swimlane, flowchart, state, quadrant, radar, quadrant-consultant, er, uml-class, venn, treemap, fishbone, wardley, kanban, journey, db-schema
-
motionenum Default: none - How the items enter. `none`: the complete figure. `step`: one by one, with previous, play, pause, next and replay, and the keyboard. `reveal`: plays by itself once, when the figure first comes into view, then stays complete (replay from the controls). Items without `step:N` enter in reading order. Without JavaScript, in print, or for a reader who asked for less motion, the complete figure shows. Allowed: none, step, reveal
-
titletitulostring - The figure's name (its accessible title); a `# Heading` line in the body does the same.
-
captionlegendastring - An italic aside under the figure; a `> quote` line in the body does the same.
-
descstring - One sentence a screen reader gets instead of the drawing. Written from the items when absent.
-
topstring - What grows upward, printed on the left margin above the direction arrow (layers): `top: Abstraction`.
-
bottomstring - What sits at the bottom, printed under the direction arrow (layers): `bottom: Silicon`.
-
leftstring - A rotated axis label on the left margin (pyramid, funnel): `left: Rarer · fewer · compounds ↑`.
Body
Items, separated by a --- line. One `- Name · sublabel {tags}` per line; a `---` line starts a new group where the type has groups. Tags in braces: `focal` (the one item in the accent), `step:N` (the motion step), `tag:L3` (the index tag), `side:~48/yr` (a note beside the item), `value:240` (a quantity: a funnel's widths follow it).
mermaid
renders: client
A diagram in mermaid's grammar, drawn by Pele (pele.run) unless the fence says `renderer:mermaid`: Pele lays a diagram out in well under a millisecond, adapts it to a phone and paints it in the page's theme. Mermaid draws what Pele does not (ZenUML; the `handDrawn` look; `themeCSS`). Either way the colours are the page's (theme keys diagram_*), unless the diagram names its own in mermaid's configuration (`%%{init: {"theme": "forest", "themeVariables": {…}}}%%`, or `config:` in its front matter), which both renderers follow. The one block with no @ spelling: a mermaid fence renders on GitHub, Obsidian, Notion and GitLab, which read the first word of the fence line and ignore the rest.
Rendered in the browser.
Example
Arguments
-
rendererrenderizadorenum - Who draws it. `pele` (the default) is many times faster and follows the page's theme with no redraw; `mermaid` keeps mermaid's own drawing, for what only it does. A reader can compare a page both ways with `?diagrams=pele` or `?diagrams=mermaid` in the address. Allowed: pele, mermaid
-
lookenum Default: page - `editorial`: the diagram in the manner of diagram-design — one accent on the node classed `focal`, the others in ink and muted by their class (`store`, `external`, `input`, `optional`, `security`, via `:::class` or `class A focal`), the name in sans 600 over a mono sublabel (`<br/>` splits them), edge labels in small mono capitals, and arrows in steps when the configuration says `%%{init: {"flowchart": {"curve": "stepAfter"}}}%%`. `page` (the default): mermaid's usual look in the page's colours. Allowed: page, editorial
Body
A diagram, in mermaid's own grammar. Mermaid source, in mermaid's own grammar, configuration included. With `look:editorial`, `# key: value` lines in the body set the sheet (`# unit:`, `# scale: 120 by 20`, `# legend: A; B {x:220}`, `# trend:`, `# source:`), and a `{x: y:}` tag on a row label pins its position; `look:page` ignores them.
Layout directives
Lines of ::: arrange the page — bands, columns, grids, media — around ordinary markdown. Every argument is a choice from a list, never CSS, and every layout works from a phone to an ultra-wide screen, in light and dark.
:::section
A band of the page: its width, its surface (or a picture under it, with a shade that keeps text readable) and the space around it. Everything inside flows top to bottom.
-
stickyDefault: none - top holds the whole band at the top of the window while the page scrolls — a contact strip and a :::nav inside it stay together. Give the nav inside no sticky of its own. Allowed: none, top
-
widthDefault: normal - normal keeps the reading width, wide uses the page width, full runs edge to edge. Allowed: normal, wide, full
-
surfaceDefault: default - The band's background, from the theme: soft (its surface colour), faint (a step lighter than soft, 40% of it on the background), alt (the theme's second ground, surface_alt: a grey band beside peach ones; not set, a neutral grey that follows neither the surface nor the accent), tint (a wash of its accent), accent (the accent itself), inverse (the theme turned over), fade (the surface colour at the top paling into the page's background at the bottom; set the theme's surface for its colour). Text colours are chosen for contrast — on a fade, against both ends — in light and dark schemes. Allowed: default, soft, faint, alt, tint, accent, inverse, fade
-
mediaDefault: none - background lays the band's first picture (alone in its paragraph) under the whole band, behind the text, as a hero's: a photo band, a marble closing band. The band stays as tall as what it holds; the picture covers it, cropped to fit. Allowed: none, background
-
shadeDefault: dark - Over a background picture: dark (light text) or light (dark text), strong enough for 4.5:1 on any photo. Under light the theme's heading and button colours stay where they read on the wash, and links read at 4.5:1 in both schemes. Allowed: dark, light
-
tileDefault: none - With media:background, repeats the picture as a texture (a marble, paper, a pattern) instead of covering the band with it, each tile 160px (small), 320px (medium) or 640px (large) wide and never stretched; shade: keeps the text readable as on a photo. The editor's preview shows the picture covering the band; the page tiles it. Allowed: none, small, medium, large
-
edge_topDefault: none - The band's top edge as a shape instead of a straight line — wave, torn (paper), curve or slant — cut out of the band so the page shows through, like the bands of fdl.co (wave) and digfamily.co (torn). The band grows by the shape's height, so nothing inside is cut. Allowed: none, wave, torn, curve, slant
-
edge_bottomDefault: none - The band's bottom edge as a shape: wave, torn, curve or slant. Same as edge_top, at the bottom. Allowed: none, wave, torn, curve, slant
-
spaceDefault: 3 - Space above and below, a step of the theme's scale. Allowed: 0, 1, 2, 3, 4, 5
-
space_topDefault: auto - The space above in px (space_top:52), instead of space:'s step, to match a measured design to the pixel. auto keeps space:'s. Allowed:
-
space_bottomDefault: auto - The space below in px (space_bottom:31), instead of space:'s step. auto keeps space:'s. Allowed:
-
fontDefault: inherit - The face of the band's own text: inherit, heading, ui (the theme's face for controls, font_ui) or a local stack — a broker's contact strip and breadcrumb are Poppins over Open Sans. Allowed: inherit, heading, ui, system, serif, mono, arial
-
alignDefault: left - Where text sits. narrow-center keeps it left on wide screens and centres it on a phone, where a stacked page reads better centred: a switch by screen width, not a narrow column (for that, measure:). Allowed: left, center, narrow-center
-
measureDefault: auto - How wide the band's paragraphs and lists run: auto (the theme's reading width), narrow (about 28 characters), medium (about 40: a lede of two lines under a wide headline, as passare.com's hero sets it) or wide (about 60). Under align:center the column stays centred. Headings keep the band's width, so a headline can run wider than the lede under it. Allowed: auto, narrow, medium, wide
-
flowDefault: auto - The space between one thing and the next inside it, a step of the theme's scale: one space for everything, whatever the things are. auto keeps each element's own margins, which is what prose wants — a heading further from the paragraph above it than from the one below. Allowed: auto, 0, 1, 2, 3, 4, 5
-
hideDefault: none - Hide on narrow screens (phones) or on wide ones, to show a different arrangement for each. Allowed: none, narrow, wide
-
motionDefault: none - How it appears as the reader scrolls to it; items of a layout arrive one after another. Nothing moves for a reader who asks for reduced motion, and without JavaScript everything is simply there. Allowed: none, fade, rise, scale
-
id - A name for this block, so a link can land on it (`[Spaces](#spaces)`) and an agent can address it. Written as the element's id, never as a class. Without one, a link to a heading inside a band lands on the heading — halfway down its column in a split, with the picture cut off above it. Allowed: letters, numbers, dashes and underscores, starting with a letter or a number
Example
:::section width:wide surface:soft space:4 align:center
# Automate your routine
Everything between the lines is ordinary markdown.
:::
:::hero
The opening of a page: at least a given height, content centred — with its first or last thing pinned to the top or bottom edge if asked — optionally over a background image with a shade that keeps text readable.
-
heightDefault: half - auto fits the content, half is half the window, screen fills it. Allowed: auto, half, screen
-
mediaDefault: none - background puts the first image inside the hero behind the text. Allowed: none, background
-
shadeDefault: dark - Over a background image: dark (light text) or light (dark text), strong enough for 4.5:1 on any photo. Allowed: dark, light
-
tileDefault: none - With media:background, repeats the picture as a texture (a marble, paper, a pattern) instead of covering the hero with it, each tile 160px (small), 320px (medium) or 640px (large) wide and never stretched; shade: keeps the text readable as on a photo. The editor's preview shows the picture covering the hero; the page tiles it. Allowed: none, small, medium, large
-
alignDefault: center - Where the content sits. narrow-center is left on wide screens and centred on a phone: a switch by screen width, not a narrow column (for that, measure:). Allowed: center, left, narrow-center
-
widthDefault: wide - How wide the content may get. Allowed: normal, wide, full
-
measureDefault: auto - How wide the band's paragraphs and lists run: auto (the theme's reading width), narrow (about 28 characters), medium (about 40: a lede of two lines under a wide headline, as passare.com's hero sets it) or wide (about 60). Under align:center the column stays centred. Headings keep the band's width, so a headline can run wider than the lede under it. Allowed: auto, narrow, medium, wide
-
surfaceDefault: default - The ground when there is no background image (see section surface). alt is the theme's second ground (surface_alt). fade is the theme's surface colour at the top paling into the page's background at the bottom, the text chosen to read on both ends. Allowed: default, soft, alt, tint, accent, inverse, fade
-
edge_topDefault: none - The band's top edge as a shape instead of a straight line — wave, torn (paper), curve or slant — cut out of the band so the page shows through, like the bands of fdl.co (wave) and digfamily.co (torn). The band grows by the shape's height, so nothing inside is cut. Allowed: none, wave, torn, curve, slant
-
edge_bottomDefault: none - The band's bottom edge as a shape: wave, torn, curve or slant. Same as edge_top, at the bottom. Allowed: none, wave, torn, curve, slant
-
pinDefault: none - Keeps the hero's first thing at its top edge (a logo, an eyebrow), its last at the bottom (a row of logos, a hint to scroll), or both, while the rest stays centred. It shows when the hero is taller than its content: height half or screen. Allowed: none, first, last, both
-
flowDefault: auto - The space between one thing and the next inside it, a step of the theme's scale: one space for everything, whatever the things are. auto keeps each element's own margins, which is what prose wants — a heading further from the paragraph above it than from the one below. Allowed: auto, 0, 1, 2, 3, 4, 5
-
hideDefault: none - Hide on narrow screens (phones) or on wide ones, to show a different arrangement for each. Allowed: none, narrow, wide
-
motionDefault: none - How it appears as the reader scrolls to it; items of a layout arrive one after another. Nothing moves for a reader who asks for reduced motion, and without JavaScript everything is simply there. Allowed: none, fade, rise, scale
-
id - A name for this block, so a link can land on it (`[Spaces](#spaces)`) and an agent can address it. Written as the element's id, never as a class. Without one, a link to a heading inside a band lands on the heading — halfway down its column in a split, with the picture cut off above it. Allowed: letters, numbers, dashes and underscores, starting with a letter or a number
Example
:::hero height:screen media:background shade:dark

# Work that runs itself
Automate the routine between your tools.
:::
:::split
Two parts side by side — text and media — that stack when there is not room for both. By ratio, the two share the width; with a rail, the first is a side column of a fixed width and the other takes the rest.
Its items are separated by a --- line.
-
ratioDefault: 1/2 - How much of the width the first part takes. Allowed: 1/3, 1/2, 2/3
-
sideDefault: left - Which part comes first on wide screens; on narrow ones the first item is always on top. Allowed: left, right
-
alignDefault: center - Vertical alignment of the two parts. Allowed: start, center, end
-
spaceDefault: 3 - The gap, a step of the theme's scale. Allowed: 1, 2, 3, 4, 5
-
narrowDefault: stack - stack puts the parts one above the other when narrow; keep keeps them side by side. Allowed: stack, keep
-
reverseDefault: none - narrow puts the second part on top when the parts stack, so a picture written after its text comes first on a phone. Allowed: none, narrow
-
stickyDefault: none - Which part stays in place while the other scrolls past it, as a portfolio's side column does. It only sticks while the parts are side by side, never when they stack. Allowed: none, first, second
-
railDefault: none - Makes the first part a side column of that width, in rem, and gives the other part everything else — a side menu, a portfolio's rail, a form beside a text. The side keeps its width on any screen instead of growing with it, and the parts stack when the other would get less than half. With a rail, ratio is not used. Allowed: none, 12, 16, 20, 24
-
flowDefault: auto - The space between one thing and the next inside it, a step of the theme's scale: one space for everything, whatever the things are. auto keeps each element's own margins, which is what prose wants — a heading further from the paragraph above it than from the one below. Allowed: auto, 0, 1, 2, 3, 4, 5
-
hideDefault: none - Hide on narrow screens (phones) or on wide ones, to show a different arrangement for each. Allowed: none, narrow, wide
-
motionDefault: none - How it appears as the reader scrolls to it; items of a layout arrive one after another. Nothing moves for a reader who asks for reduced motion, and without JavaScript everything is simply there. Allowed: none, fade, rise, scale
-
id - A name for this block, so a link can land on it (`[Spaces](#spaces)`) and an agent can address it. Written as the element's id, never as a class. Without one, a link to a heading inside a band lands on the heading — halfway down its column in a split, with the picture cut off above it. Allowed: letters, numbers, dashes and underscores, starting with a letter or a number
Example
:::split ratio:1/2 side:right
## Text first
A paragraph that sits beside the picture.
---

:::
:::columns
Items side by side in equal columns, all stacking at once when the row gets too narrow.
Its items are separated by a --- line.
-
thresholdDefault: 40 - Below this width, in rem, the columns stack. Allowed: 30, 40, 50, 60
-
limitDefault: 4 - With more items than this, they stack whatever the width. Allowed: 2, 3, 4, 5
-
alignDefault: stretch - Vertical alignment of the columns. Allowed: start, center, end, stretch
-
itemsDefault: plain - card draws each item as a card; stat sets each item's heading as a large number (it counts up when motion is on); step numbers the items as a process. Allowed: plain, card, stat, step
-
numberDefault: default - With items:stat, the colour of the number: default is the heading colour, accent the theme's accent as text (moved until it reads on the ground it sits on, a band's included), muted its secondary text colour. Allowed: default, accent, muted
-
captionDefault: muted - With items:stat, the line under the number: muted (secondary text colour) or plain, the body text as any paragraph. Allowed: muted, plain
-
sizeDefault: normal - With items:stat, how large the number is drawn, always in proportion to its column: normal (about 30-60px), large (38-72px), display (45-88px), for a site whose figures are the page's largest type. The top of each range needs a wide column: in a section of the default width, three columns draw large at about 53px; width:wide or fewer columns reach it. Allowed: normal, large, display
-
spaceDefault: 3 - The gap, a step of the theme's scale. Allowed: 1, 2, 3, 4, 5
-
flowDefault: auto - The space between one thing and the next inside it, a step of the theme's scale: one space for everything, whatever the things are. auto keeps each element's own margins, which is what prose wants — a heading further from the paragraph above it than from the one below. Allowed: auto, 0, 1, 2, 3, 4, 5
-
hideDefault: none - Hide on narrow screens (phones) or on wide ones, to show a different arrangement for each. Allowed: none, narrow, wide
-
motionDefault: none - How it appears as the reader scrolls to it; items of a layout arrive one after another. Nothing moves for a reader who asks for reduced motion, and without JavaScript everything is simply there. Allowed: none, fade, rise, scale
-
id - A name for this block, so a link can land on it (`[Spaces](#spaces)`) and an agent can address it. Written as the element's id, never as a class. Without one, a link to a heading inside a band lands on the heading — halfway down its column in a split, with the picture cut off above it. Allowed: letters, numbers, dashes and underscores, starting with a letter or a number
Example
:::columns items:card
### Plan
Tell us what you need.
---
### Build
We build it with you.
---
### Launch
It goes live.
:::
:::grid
As many items per row as fit, each at least `min` wide; one per row on a phone. An item can span more columns or rows with :::cell.
Its items are separated by a --- line.
-
minDefault: 16 - The smallest an item may get, in rem, before the row wraps. Allowed: 8, 10, 12, 14, 16, 18, 20, 24, 28
-
colsDefault: auto - At most this many items per row, however wide the page gets. Six items with cols:3 come out as two rows of three instead of five and one alone. A phone still gets one per row. Allowed: auto, 2, 3, 4
-
itemsDefault: plain - card draws each item as a card; stat sets each item's heading as a large number (it counts up when motion is on); step numbers the items as a process. Allowed: plain, card, stat, step
-
numberDefault: default - With items:stat, the colour of the number: default is the heading colour, accent the theme's accent as text (moved until it reads on the ground it sits on, a band's included), muted its secondary text colour. Allowed: default, accent, muted
-
captionDefault: muted - With items:stat, the line under the number: muted (secondary text colour) or plain, the body text as any paragraph. Allowed: muted, plain
-
sizeDefault: normal - With items:stat, how large the number is drawn, always in proportion to its column: normal (about 30-60px), large (38-72px), display (45-88px), for a site whose figures are the page's largest type. The top of each range needs a wide column: in a section of the default width, three columns draw large at about 53px; width:wide or fewer columns reach it. Allowed: normal, large, display
-
alignDefault: stretch - Vertical alignment of items in a row. Allowed: stretch, start, center
-
spaceDefault: 3 - The gap, a step of the theme's scale. Allowed: 1, 2, 3, 4, 5
-
flowDefault: auto - The space between one thing and the next inside it, a step of the theme's scale: one space for everything, whatever the things are. auto keeps each element's own margins, which is what prose wants — a heading further from the paragraph above it than from the one below. Allowed: auto, 0, 1, 2, 3, 4, 5
-
hideDefault: none - Hide on narrow screens (phones) or on wide ones, to show a different arrangement for each. Allowed: none, narrow, wide
-
motionDefault: none - How it appears as the reader scrolls to it; items of a layout arrive one after another. Nothing moves for a reader who asks for reduced motion, and without JavaScript everything is simply there. Allowed: none, fade, rise, scale
-
id - A name for this block, so a link can land on it (`[Spaces](#spaces)`) and an agent can address it. Written as the element's id, never as a class. Without one, a link to a heading inside a band lands on the heading — halfway down its column in a split, with the picture cut off above it. Allowed: letters, numbers, dashes and underscores, starting with a letter or a number
Example
:::grid min:16 items:card
### Fast
Pages render in milliseconds.
---
### Typed
Nothing you write becomes CSS.
:::
:::cell
Inside a grid item: how many columns and rows that item takes (bento layouts), and which layer it sits on.
-
spanDefault: 1 - Columns the item takes; full takes the whole row. On a phone every item is one column. Allowed: 1, 2, 3, 4, full
-
rowsDefault: 1 - Rows the item takes. Allowed: 1, 2, 3
-
layerDefault: 0 - Stacking order when items overlap (with offset). Allowed: 0, 1, 2, 3
-
flowDefault: auto - The space between one thing and the next inside it, a step of the theme's scale: one space for everything, whatever the things are. auto keeps each element's own margins, which is what prose wants — a heading further from the paragraph above it than from the one below. Allowed: auto, 0, 1, 2, 3, 4, 5
-
id - A name for this block, so a link can land on it (`[Spaces](#spaces)`) and an agent can address it. Written as the element's id, never as a class. Without one, a link to a heading inside a band lands on the heading — halfway down its column in a split, with the picture cut off above it. Allowed: letters, numbers, dashes and underscores, starting with a letter or a number
Example
:::grid min:14
:::cell span:2 rows:2

:::
---
### Small tile
:::
:::card
A panel: a surface, padding, the theme's radius, an optional border and shadow.
-
toneDefault: soft - The panel's surface, with contrast-checked text (see section surface). alt is the theme's second ground (surface_alt), as on a band. ok, warn, info and danger are a status: the panel takes a light wash of the colour a pill of that status wears, for a notice, a result or a warning. Allowed: default, soft, alt, tint, accent, inverse, ok, warn, info, danger
-
mediaDefault: inset - bleed: a frameless picture (`:::cover frame:none`) that opens the card runs to the card's edges, under the card's top corners, as a listing card shows its photo; the text keeps the card's padding. Allowed: inset, bleed
-
borderDefault: none - A hairline border. Allowed: none, line
-
textDefault: inherit - The size of the panel's own text, in px, whatever the page's body size: a site whose body is 12px writes its chips at 15 (text:15). Allowed: inherit, 12, 13, 14, 15, 16, 18
-
fontDefault: inherit - The face of the panel's own text: inherit (the page's body face), heading (the theme's heading face), ui (the theme's face for controls, font_ui) or a local stack that loads nothing (system, serif, mono, arial) — a broker's search chips are Arial on an Open Sans page. Allowed: inherit, heading, ui, system, serif, mono, arial
-
headingDefault: normal - How large the panel's own headings are: normal (the theme's), large (20px and bold, as a call-to-action tile's line is set) or larger (22px, a listing's count above its cards), whatever the theme's heading scale. Allowed: normal, large, larger
-
heightDefault: auto - How tall the panel stands at least, its content centred top to bottom: auto (as tall as what it holds), short (about 190px), medium (300px, a broker's call-to-action tile) or tall (400px). Allowed: auto, short, medium, tall
-
shadowDefault: none - A shadow under the panel. Allowed: none, soft, lifted
-
spaceDefault: 2 - Padding inside, a step of the theme's scale. Allowed: 1, 2, 3, 4
-
offsetDefault: 0 - Pull the element up into the content above it, in steps of the scale. Allowed: 0, up-1, up-2, up-3
-
tiltDefault: none - A slight rotation, a few degrees. Allowed: none, left, right
-
flowDefault: auto - The space between one thing and the next inside it, a step of the theme's scale: one space for everything, whatever the things are. auto keeps each element's own margins, which is what prose wants — a heading further from the paragraph above it than from the one below. Allowed: auto, 0, 1, 2, 3, 4, 5
-
hideDefault: none - Hide on narrow screens (phones) or on wide ones, to show a different arrangement for each. Allowed: none, narrow, wide
-
motionDefault: none - How it appears as the reader scrolls to it; items of a layout arrive one after another. Nothing moves for a reader who asks for reduced motion, and without JavaScript everything is simply there. Allowed: none, fade, rise, scale
-
id - A name for this block, so a link can land on it (`[Spaces](#spaces)`) and an agent can address it. Written as the element's id, never as a class. Without one, a link to a heading inside a band lands on the heading — halfway down its column in a split, with the picture cut off above it. Allowed: letters, numbers, dashes and underscores, starting with a letter or a number
Example
:::card tone:accent shadow:lifted
### Founding plan
Everything, for the first hundred creators.
:::
:::inline
Items in a line that wraps: buttons, tags, logos, small facts.
Its items are separated by a --- line.
-
justifyDefault: start - How the line is distributed. Allowed: start, center, end, between
-
alignDefault: center - Vertical alignment within a line. Allowed: center, start, end
-
spaceDefault: 2 - The gap, a step of the theme's scale. Allowed: 1, 2, 3, 4
-
space_topDefault: auto - The room above the line in px (space_top:34), instead of the line's own margin, to match a measured design. Allowed:
-
space_bottomDefault: auto - The room under the line in px (space_bottom:46), instead of the line's own margin. Allowed:
-
stickyDefault: none - top keeps the line at the top of the screen while the page scrolls under it, below the app's header: a few buttons that change how the page is viewed (Pele / Mermaid, light / dark), with no bar behind them. Allowed: none, top
-
logosDefault: none - A logo strip: every picture in the line at one height — small 24px, medium 32px, large 48px — linked or not, drawn whole, a wide wordmark held to five times its height, and, without space:, a wider gap. A linked picture with alt text ([](url)) is always the picture, never a button. Allowed: none, small, medium, large
-
logos_toneDefault: original - Recolours every picture in the line: dark draws them black, for white-on-transparent logos on a light ground; light draws them white, for dark logos on an accent, inverse or photo ground. original keeps their colours. In a reader's dark scheme the two swap, so the logos stay visible on the dark ground. Allowed: original, dark, light
-
hideDefault: none - Hide on narrow screens (phones) or on wide ones, to show a different arrangement for each. Allowed: none, narrow, wide
-
id - A name for this block, so a link can land on it (`[Spaces](#spaces)`) and an agent can address it. Written as the element's id, never as a class. Without one, a link to a heading inside a band lands on the heading — halfway down its column in a split, with the picture cut off above it. Allowed: letters, numbers, dashes and underscores, starting with a letter or a number
Example
:::inline justify:center
[Start free](/signup)
---
[See pricing](/pricing)
:::
:::cover
Media cropped to a ratio, optionally in a device frame.
-
ratioDefault: 16/9 - The shape the image or video is cropped to. Allowed: 16/9, 16/10, 3/2, 4/3, 5/4, 1/1, 4/5, 3/4, 2/3, 9/16, 2/1, 21/9
-
focusDefault: center - Which part of the media stays in view when it is cropped. Allowed: center, top, bottom, left, right
-
frameDefault: rounded - none, rounded corners, a circle (avatars), a browser window or a phone around the media. Allowed: none, rounded, circle, browser, phone
-
shadowDefault: none - A shadow under the media. Allowed: none, soft, lifted
-
shadeDefault: none - A dark wash over the media so what an overlay writes on it reads: bottom darkens the lower half (a price under a photo), top the upper half, dark the whole picture evenly. A plain overlay on a shaded cover writes in white. Allowed: none, bottom, top, dark
-
sizeDefault: full - How wide the media is, never wider than its column: full fills it, half is half of it, medium up to 512px (a video poster beside text), small 96px (a headshot in a byline; with frame:circle, round), icon 40px (a feature's icon, drawn whole, never cropped). small and icon are square unless ratio: says otherwise; in a centred band or hero the media sits in the middle. Allowed: full, half, medium, small, icon
-
offsetDefault: 0 - Pull the element up into the content above it, in steps of the scale. Allowed: 0, up-1, up-2, up-3
-
tiltDefault: none - A slight rotation, a few degrees. Allowed: none, left, right
-
hideDefault: none - Hide on narrow screens (phones) or on wide ones, to show a different arrangement for each. Allowed: none, narrow, wide
-
motionDefault: none - How it appears as the reader scrolls to it; items of a layout arrive one after another. Nothing moves for a reader who asks for reduced motion, and without JavaScript everything is simply there. Allowed: none, fade, rise, scale
-
id - A name for this block, so a link can land on it (`[Spaces](#spaces)`) and an agent can address it. Written as the element's id, never as a class. Without one, a link to a heading inside a band lands on the heading — halfway down its column in a split, with the picture cut off above it. Allowed: letters, numbers, dashes and underscores, starting with a letter or a number
Example
:::cover ratio:16/9 frame:browser shadow:lifted

:::
:::overlay
Content placed over its parent and kept inside it: a badge on a picture, or — with kind:plain — anything at all, a card over a photo, a caption, a play button.
-
atDefault: center - Where on the parent it sits. Allowed: center, top-left, top-right, bottom-left, bottom-right, bottom
-
kindDefault: badge - badge draws it as a small pill, which is what a label on a picture wants. plain draws nothing of its own: whatever is inside — a card, a heading, a button — sits over the parent as it is, never larger than the parent, scrolling inside itself if it would be. tags: each paragraph a small capitalised tag on a dark ground, stacked down the corner, as a listing marks its photo (exclusive, for sale, available); a paragraph that is only a picture stays a picture, a favourite button above the tags. Allowed: badge, plain, tags
-
id - A name for this block, so a link can land on it (`[Spaces](#spaces)`) and an agent can address it. Written as the element's id, never as a class. Without one, a link to a heading inside a band lands on the heading — halfway down its column in a split, with the picture cut off above it. Allowed: letters, numbers, dashes and underscores, starting with a letter or a number
Example
:::cover ratio:4/3

:::overlay at:top-right
**New**
:::
:::
:::carousel
A horizontal strip of items that scrolls and snaps; no autoplay.
Its items are separated by a --- line.
-
itemDefault: normal - How wide each item is: about a quarter, a third or two thirds of the strip (wider on phones). Allowed: narrow, normal, wide
-
itemsDefault: plain - card draws each item as a card. Allowed: plain, card
-
spaceDefault: 3 - The gap, a step of the theme's scale. Allowed: 1, 2, 3, 4
-
hideDefault: none - Hide on narrow screens (phones) or on wide ones, to show a different arrangement for each. Allowed: none, narrow, wide
-
motionDefault: none - How it appears as the reader scrolls to it; items of a layout arrive one after another. Nothing moves for a reader who asks for reduced motion, and without JavaScript everything is simply there. Allowed: none, fade, rise, scale
-
id - A name for this block, so a link can land on it (`[Spaces](#spaces)`) and an agent can address it. Written as the element's id, never as a class. Without one, a link to a heading inside a band lands on the heading — halfway down its column in a split, with the picture cut off above it. Allowed: letters, numbers, dashes and underscores, starting with a letter or a number
Example
:::carousel item:narrow items:card
"Best tool I adopted this year." — Ana
---
"It replaced three apps." — Bia
:::
:::masonry
Items of different heights packed into columns, like a photo wall. Reading order runs down each column.
Its items are separated by a --- line.
-
minDefault: 16 - The narrowest a column may get, in rem. Allowed: 12, 14, 16, 18, 20, 24
-
itemsDefault: plain - card draws each item as a card. Allowed: plain, card
-
spaceDefault: 3 - The gap, a step of the theme's scale. Allowed: 1, 2, 3, 4
-
hideDefault: none - Hide on narrow screens (phones) or on wide ones, to show a different arrangement for each. Allowed: none, narrow, wide
-
motionDefault: none - How it appears as the reader scrolls to it; items of a layout arrive one after another. Nothing moves for a reader who asks for reduced motion, and without JavaScript everything is simply there. Allowed: none, fade, rise, scale
-
id - A name for this block, so a link can land on it (`[Spaces](#spaces)`) and an agent can address it. Written as the element's id, never as a class. Without one, a link to a heading inside a band lands on the heading — halfway down its column in a split, with the picture cut off above it. Allowed: letters, numbers, dashes and underscores, starting with a letter or a number
Example
:::masonry min:14 items:card
"Short quote." — Ana
---
A longer testimonial that takes more lines than the others.
:::
:::marquee
A strip that scrolls by itself, for logos or short quotes. It pauses on hover and stands still for a reader who asks for reduced motion.
Its items are separated by a --- line.
-
speedDefault: normal - How fast the strip moves. Allowed: slow, normal, fast
-
directionDefault: left - Which way it moves. Allowed: left, right
-
spaceDefault: 4 - The gap between items, a step of the theme's scale. Allowed: 1, 2, 3, 4, 5
-
hideDefault: none - Hide on narrow screens (phones) or on wide ones, to show a different arrangement for each. Allowed: none, narrow, wide
-
id - A name for this block, so a link can land on it (`[Spaces](#spaces)`) and an agent can address it. Written as the element's id, never as a class. Without one, a link to a heading inside a band lands on the heading — halfway down its column in a split, with the picture cut off above it. Allowed: letters, numbers, dashes and underscores, starting with a letter or a number
Example
:::marquee speed:slow

---

---

:::
:::banner
A band pinned to an edge of the screen — a cookie notice, an announcement, a promotion — with anything inside. Without a script it is a band at the end of the page, where it was written; with one it floats, and can be closed.
Its items are separated by a --- line.
-
positionDefault: bottom - Where it sits once a script pins it: along the bottom edge, along the top, in the middle over the dimmed page (where the reader answers before going on), or as a card in the bottom corner. Bands on the bottom edge stack, never overlap: one with no close and no @consent (a call bar) holds the edge, and a cookie notice sits on top of it until answered. Allowed: bottom, top, center, corner
-
shapeDefault: flat - flat runs edge to edge; floating is a card with a margin, the theme's corners and a shadow. The middle and the corner are always a card. Allowed: flat, floating
-
dismissDefault: none - Whether the reader may close it without answering: never; until the page is opened again; or for good, remembered on this site by the band's id. A `@consent` inside closes it when answered, whatever this says. Allowed: none, once, remember
-
surfaceDefault: default - The band's ground, with contrast-checked text. Allowed: default, soft, inverse
-
widthDefault: wide - How wide the band's content may get. Allowed: wide, full
-
hideDefault: none - Hide on narrow screens (phones) or on wide ones, to show a different arrangement for each. Allowed: none, narrow, wide
-
id - A name for this block, so a link can land on it (`[Spaces](#spaces)`) and an agent can address it. Written as the element's id, never as a class. Without one, a link to a heading inside a band lands on the heading — halfway down its column in a split, with the picture cut off above it. Allowed: letters, numbers, dashes and underscores, starting with a letter or a number
Example
:::banner position:bottom dismiss:remember surface:inverse id:cookies
Este site usa vídeos do YouTube, que carregam cookies do Google.
---
[Saiba mais](/privacidade)
:::
:::rows
A list of settings or facts, one row per item: the first line is the row's title, the next its hint, and the last line — whatever it holds: a value, a button, a `switch:on`, a `pill:` — sits at the row's end. A row whose title is a link opens it from anywhere on the row, with a chevron at the end.
Its items are separated by a --- line.
-
insetDefault: none - none draws hairlines between rows on the page itself; card puts the rows in a rounded panel of their own, the grouped list of a phone's settings. Allowed: none, card
-
spaceDefault: 2 - How much room each row has above and below, a step of the theme's scale. Allowed: 1, 2, 3
-
endDefault: last - last puts the item's last line at the row's end (when the item has more than one line); none keeps every line under the title. Allowed: last, none
-
hideDefault: none - Hide on narrow screens (phones) or on wide ones, to show a different arrangement for each. Allowed: none, narrow, wide
-
id - A name for this block, so a link can land on it (`[Spaces](#spaces)`) and an agent can address it. Written as the element's id, never as a class. Without one, a link to a heading inside a band lands on the heading — halfway down its column in a split, with the picture cut off above it. Allowed: letters, numbers, dashes and underscores, starting with a letter or a number
Example
:::rows
**Reader notes**
Readers can mark a passage and leave a note beside it.
`switch:on`
---
**Display name**
`dropdown:Ana Ceramics`
---
[**Address and domain**](./address)
`pill:warn:Waiting for DNS`
:::
:::shell
An app's frame: a side column (the first item, usually a :::sidenav) beside the main part (the second item, usually a template's :::slot). On a wide screen it is a panel with the side column at a fixed width; on a phone it fills the screen, the side column goes away and a first line of the main part that is a link with `icon:chevron-left` becomes the bar that goes back. In the main part a `#` heading is the screen's title, with a hairline under it, and a `##` heading is a small muted label over a group of rows, as on a settings screen; a bigger heading inside the main part is a `###`.
Its items are separated by a --- line.
-
railDefault: 16 - The side column's width, in rem. Allowed: 14, 16, 18, 20
-
frameDefault: panel - panel draws the frame as a raised panel with the theme's radius and a shadow, over the page's ground; plain draws no panel; full makes the shell the page: edge to edge, from the top, at least as tall as the screen, with no radius or shadow (with ```view standalone: true it is the whole screen a reader gets). Allowed: panel, plain, full
-
dividerDefault: line - A hairline between the side column and the main part. Allowed: line, none
-
narrowDefault: back - What the side column becomes on a phone: back drops it and keeps only the way back; drawer adds a Menu button to that bar, which opens the side column as a drawer from the start edge, the current page marked. Allowed: back, drawer
-
hideDefault: none - Hide on narrow screens (phones) or on wide ones, to show a different arrangement for each. Allowed: none, narrow, wide
-
id - A name for this block, so a link can land on it (`[Spaces](#spaces)`) and an agent can address it. Written as the element's id, never as a class. Without one, a link to a heading inside a band lands on the heading — halfway down its column in a split, with the picture cut off above it. Allowed: letters, numbers, dashes and underscores, starting with a letter or a number
Example
:::shell
:::sidenav
[`icon:user` Profile](./profile)
[`icon:settings` Preferences](./preferences)
:::
---
[`icon:chevron-left` Settings](./settings)
:::slot
:::
:::
:::timeline
A sequence of steps or events joined by a line: an order's tracking, a stepper, an activity feed, an onboarding. Each item, separated by ---, is a step: its first line the title, the next ones its details (a date, who did it). `state:done`, `state:current`, `state:upcoming`, `state:error` or `state:skipped` written in an item gives its marker and says where it is in words; an item that is only a heading names a group (Today, In progress); a :::timeline inside an item is its sub-steps.
Its items are separated by a --- line.
-
directionDefault: vertical - vertical runs down the page; horizontal runs across, as a stepper, and turns vertical when the page is narrow. Allowed: vertical, horizontal
-
markerDefault: dot - What sits on the line at each step: a dot coloured by its state; the step's number; or the `icon:` the item's first line starts with. Allowed: dot, number, icon
-
lineDefault: solid - The line that joins the steps. Allowed: solid, dashed, none
-
densityDefault: normal - How much room each step has: compact suits a long feed. Allowed: normal, compact
-
hideDefault: none - Hide on narrow screens (phones) or on wide ones, to show a different arrangement for each. Allowed: none, narrow, wide
-
id - A name for this block, so a link can land on it (`[Spaces](#spaces)`) and an agent can address it. Written as the element's id, never as a class. Without one, a link to a heading inside a band lands on the heading — halfway down its column in a split, with the picture cut off above it. Allowed: letters, numbers, dashes and underscores, starting with a letter or a number
Example
:::timeline
**Pedido criado** `state:done`
10 mar 2026
---
**Em trânsito** `state:current`
Royal Mail · previsão 12 mar
---
**Entregue** `state:upcoming`
:::drawer
A panel that slides in from an edge of the screen over the page, holding anything at all. The first item is what its button says (words, an `icon:` too); the second is what it holds. Without a script both are on the page where they were written; with one the button opens the panel, and the reader closes it with its × button, Escape, a tap outside, or by following a link inside.
Its items are separated by a --- line.
-
edgeDefault: end - The edge it slides in from: end is the right in a left-to-right page and the left in a right-to-left one; start the other side; top and bottom slide down or up. Allowed: end, start, top, bottom
-
sizeDefault: normal - How much of the screen it takes: from the side, its width (18, 22 or 32rem, or all of it); from the top or the bottom, up to a height (a third, half, three quarters, or all of it), shorter when what it holds is. Allowed: narrow, normal, wide, full
-
collapseDefault: always - always is a drawer at every width; narrow keeps what it holds on the page where it was written while the page is wide, and makes it a drawer behind its button on a phone. Allowed: always, narrow
-
surfaceDefault: default - The panel's ground, with contrast-checked text. Allowed: default, soft, inverse
-
hideDefault: none - Hide on narrow screens (phones) or on wide ones, to show a different arrangement for each. Allowed: none, narrow, wide
-
id - A name for this block, so a link can land on it (`[Spaces](#spaces)`) and an agent can address it. Written as the element's id, never as a class. Without one, a link to a heading inside a band lands on the heading — halfway down its column in a split, with the picture cut off above it. Allowed: letters, numbers, dashes and underscores, starting with a letter or a number
Example
:::drawer edge:start
`icon:menu` Etapas
---
:::sidenav
[Intake](./intake)
[Risco](./risco)
:::
:::
:::tabs
Panels that take turns in one place, one tab each: Details, Timeline, Notes. Each item, separated by ---, is a tab; its first line — a heading, or a line that is only bold — names it, and the rest is its panel. Without a script every panel is on the page under its own name; with one the reader picks a tab (arrow keys too), and a link to anything inside a panel opens it.
Its items are separated by a --- line.
-
styleDefault: line - line underlines the tab that is open, along a hairline; pill draws the tabs as a row of buttons, the open one filled. Allowed: line, pill
-
hideDefault: none - Hide on narrow screens (phones) or on wide ones, to show a different arrangement for each. Allowed: none, narrow, wide
-
id - A name for this block, so a link can land on it (`[Spaces](#spaces)`) and an agent can address it. Written as the element's id, never as a class. Without one, a link to a heading inside a band lands on the heading — halfway down its column in a split, with the picture cut off above it. Allowed: letters, numbers, dashes and underscores, starting with a letter or a number
Example
:::tabs
### Detalhes
Cliente: Ana Ceramics
---
### Timeline
Em trânsito desde 10 mar.
---
### Notas
Sem notas.
:::
:::slot
In a template (a page other pages wear): where the wearing page goes. Everything around it — a nav, a side column, a footer — is what those pages have in common. A named slot holds a default that a page may replace with :::fill.
-
nameDefault: main - main is where the page's own content goes, and a template needs one. The others are places a page may fill; what is written inside the slot is what shows when it does not. Allowed: main, hero, aside, top, bottom, cta
Example
:::nav
**[Studio](~)**
---
- [Work](~/work)
- [About](~/about)
:::
:::slot
:::
:::slot name:cta
## Let's talk
[Write to us](~/contact)
:::
:::fill
In a page that wears a template: what goes into one of the template's named slots instead of its default. It leaves the page's own flow and shows where the template put that slot.
-
nameDefault: aside - The slot to fill. One the template does not have stays where it was written, so nothing a person wrote disappears. Allowed: hero, aside, top, bottom, cta
Example
:::fill name:cta
## Hiring designers
[See the roles](~/jobs)
:::
# The page's own content