Skip to main content

Chapter 10 · Part II · The craft

Composed pages

The Markdown of composed pages: the four-colon page fence that names a page template, frames and the slot attribute that send content to the frames of the template, figures with labels at the anchors of a picture, and the warnings that check the content against the template

Updated 2026-10-169 minenescadefritptzhjaar

In short

Some pages are not one column of running text but a set of boxes, like a page of a school textbook with a title band, a text and three coloured boxes with photos. Postext calls them composed pages. The shape of the page is a template in the configuration, and the Markdown only says which piece of text goes into which box. This page shows how to write that Markdown: the page fence, the frames, the slot names, and pictures with labels such as the names on a map. It also lists the warnings Postext gives when the text and the template do not match.

The template holds the form of the page; the Markdown holds its content and says which frame each piece goes to.

A composed page is a page laid out from a template: named frames (a title band, a text, a box with its photo), groups that move together and a decoration, all defined in the configuration under pageTemplates. The Markdown of the page is a fenced block that names its template and pours content into the frames by name. No position or size is ever written in the Markdown, and no content text is ever written in the configuration, so a translation is the same template with other words.

This page covers the Markdown. In this release the parser reads composed pages and the slot checks run, so the Checks panel and postext check report a page that does not match its template. Laying the template out on the page comes in the next release; until then the content of a composed page is set in the running text, in Markdown order, on pages of its own, so nothing written in it is lost. A document without composed pages lays out exactly as before.

#The page fence

::::page{template="tema-cajas" fondo="banda-retos"}
# La actividad económica y el dinero
 
Las personas utilizan :chip[recursos]{style="clave"} que se obtienen de la naturaleza…
::::

A composed page opens with a line of four colons followed by page and its attributes, and closes with a bare line of the same number of colons. Inside, three-colon containers (:::frame, :::callout, :::figure, :::columns, :::paper) open and close as they always do, so a bare ::: closes the innermost of them and never the page. A page written with five colons (:::::page) closes with five; a four-colon line inside it is then ordinary text.

AttributeEffect
template="…"Required. The id of an entry of pageTemplates.
spreadThe page is a spread of two facing pages; the template must be a spread template too.
id="…", #idAn anchor: a :ref to it prints the page the composed page lands on.
any otherA value the template reads as {attr.name}, such as a background picture chosen page by page: fondo="banda-retos" with resourceId: "{attr.fondo}" in the decoration.

A composed page always starts a new page (or spread), and the text after its closing fence starts on the next one.

The three-colon :::page{split=…} is a comic page (see Comics) and keeps that meaning. A three-colon :::page that carries template= is still read as a comic page, and the warning pageFenceLength says that a composed page needs four colons.

When a fence is missing, the parser recovers without losing text:

  • a page left open runs to the end of the chapter and is reported as an unclosed container at its opening line;
  • a ::::page line met while a page is open closes the open page there first (reported the same way);
  • the closing fence closes any frame or box still open inside the page, reporting each one;
  • a closing fence with another number of colons is not the page's: it stays in the text, where you can see it.

#Frames and slots

:::frame{slot="dinero" label="El dinero"}
Es el instrumento utilizado como medio de pago…
 
Hasta hace pocos años, lo más normal era pagar con dinero en **efectivo**…
:::

A slot is the name a piece of content asks for; it matches the name of a frame of the template. :::frame{slot="…"} sends everything inside it to that frame. Its body is full Markdown: paragraphs, lists, headings, chips, ::resource embeds, :ref references, footnotes, :::columns and nested callouts. label and title give the frame's tab or title its words, as they do for a :::callout; the frame's look comes from the callout style the template gives it.

A single block can name its slot itself:

BlockWritten
A heading## Retos {slot="retos-titulo"}
A resource embed::resource{id="dinero-pago" slot="dinero-fotos"} (the two attributes, in any order)
A code listing```js {slot="codigo"}
A box or any other container:::callout{type="nota" slot="aside"}: the whole box goes to the slot
A figure:::figure{resource="mapa" slot="mapa"} (see below)

How the content is shared out:

  • Several pieces with the same slot are joined in Markdown order.
  • Content with no slot goes to the template's flow frame (the frame marked flow).
  • A heading with no slot goes first to the frame that takes its level (takes: "h1"), if the template has one, so the title of a textbook topic is just # Title at the top of the page.
  • Content that names a slot the template does not have goes to the flow frame and is reported (slotUnknown).

A slot outside a composed page is read and changes nothing.

#Figures with labels

:::figure{resource="mapa-europa" slot="mapa"}
::label[OCÉANO ATLÁNTICO]{at="atlantico" style="mar"}
::label[**Madrid**]{at="madrid"}
::label[Mar Negro]{at="62% 48%"}
:::

:::figure{resource="…"} places one resource, with its caption and number, as ::resource does, and lists the labels to set on the picture: one ::label[TEXT]{…} line each, blank lines allowed between them.

  • at names an anchor of the resource (a point defined once on the picture, shared by every language), or gives a point in percentages of the picture, at="x% y%", for a label with no anchor.
  • style names a label style and overrides the anchor's.
  • The text in brackets is inline Markdown: bold, italic, chips.

A figure works in the running text as well as in a frame. Labels are read and kept with their source; drawing them on the picture comes with the template layout, and until then a figure is set as its resource is. A line inside a figure that is neither a label nor blank ends a figure whose closing ::: is missing, and is reported as an unclosed container.

#Example

The page of a school textbook, with a title band, a text with its list and three coloured boxes, each with its photo beside it:

::::page{template="tema-cajas" fondo="banda-retos"}
# La actividad económica y el dinero
 
## La actividad económica
 
Las personas utilizan :chip[recursos]{style="clave"} que se obtienen de la naturaleza…
 
- Las :chip[empresas.]{style="clave"} Ofrecen bienes y servicios a cambio de un beneficio.
- Las :chip[personas y familias.]{style="clave"} Adquieren lo que ofrecen las empresas…
 
:::frame{slot="dinero" label="El dinero"}
Es el instrumento utilizado como medio de pago, ya que su valor es conocido…
:::
 
::resource{id="dinero-pago" slot="dinero-fotos"}
 
:::frame{slot="gasto" label="El gasto"}
- **Fijo:** es el que se produce todos los meses…
- **Variable:** puede cambiar según las necesidades…
:::
 
::resource{id="gasto-compras" slot="gasto-fotos"}
 
:::frame{slot="ahorro" label="Préstamos y ahorro"}
Si necesitas o quieres comprar algo muy caro…
:::
 
::resource{id="ahorro-balanza" slot="ahorro-fotos"}
::::

The title goes to the frame that takes h1; the subheading, the paragraph and the list go to the flow frame; each box and each photo go to the frame of their slot. The Catalan edition is the same lines with other words: the template, the slots and the photos do not change.

#Warnings

The checks read the Markdown and the configuration before any layout, so they show in the Checks panel as you type, in postext check and in the document's contentWarnings, each with the source range of what it concerns (see Configuration › Warnings in the document).

KindCauseFix
templateUnknownThe page fence names a template that no entry of pageTemplates has, or names none. Its slots are not checked.Correct the id, or add the template to the configuration.
slotUnknownA slot="…" names no frame of the page's template (frames inherited through extends and frames of a variants page count). The content goes to the flow frame.Correct the slot name, or add a frame of that name to the template.
slotEmptyA frame of the template receives nothing on this page: no slot names it, it takes no heading, and, for the flow frame, no content is left without a slot. A frame that only receives what another frame continues into it (next) is not reported. postext check lists it as a note.Write content for it with its slot, or mark the frame optional: true in the template.
pageFenceLengthA three-colon :::page carries template=. It is read as a comic page, as before.Open the page with four colons, ::::page{template="…"}, and close it with ::::.
unclosedContainerA composed page, a frame or a figure is never closed (see the recovery rules above). The Checks panel names the composed page ::::page.Add the closing fence: as many colons as the page's opening line, or ::: for a frame or a figure.

#From code

composedPages(blocks) reads the parsed blocks of a chapter (parseMarkdownWithIssues(markdown).blocks) and returns one node per page fence, in order: its template, spread, attrs with the source range of each value (attrSources), its fenceIndex (the ordinal of the fence in the chapter, the same in every language), slots (the indices of the blocks of each slot, in Markdown order), unassigned (the blocks with no slot) and the source range of the whole page. A block carries the slot it names in ContentBlock.slot, with the source range of the value; a figure is a resourceBlock whose figure holds its attributes and labels, each label with its text, its inline spans and a source map back to the Markdown. checkComposedSlots(pages, config) returns the three slot warnings for those pages.