---
title: "Directives"
description: "The directives this theme adds to what an author can write, and the document field."
canonical: directives.html
navigation-title: "Directives"
---

<a id="directives"></a>

# Directives

- [layout](#layout)
- [hero](#hero)
- [band](#band)
- [grid](#grid)
- [split](#split)
- [half](#half)
- [card](#card)
- [stat](#stat)
- [swatch](#swatch)
- [surface](#surface)
- [quote](#quote)
- [button](#button)
- [button-bar](#button-bar)
- [directory-tree](#directory-tree)
- [accordion](#accordion)
- [accordion-item](#accordion-item)
- [facts](#facts)
- [register](#register)
- [entry](#entry)
- [steps](#steps)
- [step](#step)
- [example](#example)
- [specimen](#specimen)

The directives this theme adds to what an author can write, and the document
field. The extension registers them, so a project with the theme can use
them at once. There is nothing to add to `guides.xml` and no template to
copy.

| Written | What it is for | Draws |
| --- | --- | --- |
| `:layout:` | a field, not a directive: which of the two shapes the page takes | — |
| `hero` | the opening claim of a landing page, beside one image | `.sds-split` and `sds-figure` |
| `band` | a full-bleed section of a landing page, and everything after it | `.sds-band` |
| `grid` | a set read side by side, reflowed by its own minimum width | `sds-grid` |
| `split` | two of anything, side by side until there is no room for two | `.sds-split` |
| `half` | one side of a split, where that side is several blocks | `.sds-stack` |
| `card` | a way into something: a title that goes somewhere, and what is behind it | `sds-card` |
| `stat` | one number as a fact | `sds-stat` |
| `surface` | one filled plane, with a statement in place | `sds-surface` |
| `quote` | a sentence from somewhere else, with its source | `sds-quote` |
| `button` | one press, and where it goes | `sds-button` |
| `button-bar` | the presses of a page, in one row | `.sds-actions` |
| `accordion`, `accordion-item` | questions with their answers folded behind them | `sds-accordion` |
| `steps`, `step` | an instruction read from the top, numbered down one rail | `sds-steps` |
| `facts` | a block of facts, scanned down the terms | `sds-facts` |
| `register`, `entry` | a list a reader cites: numbered, addressed, and the work it asks for | `sds-register` |
| `example` | a piece of markup and, under it, what it renders as | `sds-code` in `.sds-example` |
| `specimen` | a rendered card, at the size of its measurement | `sds-embed` |

Each of them draws an element of this system and takes that element's own
options, spelt the way the element spells them. So `href` links and
`src` takes a file here as everywhere else, and what a component gains,
the directive gains with it. Every section below names the element it
draws, and [Components](../frontend/components/index.md) is that element's reference.

Every example on this page stands once: the block is the body that drew
the thing under it, which is what `example` is for.

<a id="layout"></a>

## layout

Not a directive. A field at the top of a document, beside the navigation
title, and it decides which shape the page takes.

```text
:navigation-title: Overview
:layout: marketing

================
What this is for
================
```

<a id="confval-layout"></a>

**`layout`**

- Type: string
- Default: "default"

`marketing` renders the page as a run of full-bleed bands with no rail.
Anything else, and a page with no such field, is the manual shape. The
toctree in a rail on the left, the trail above the title, the text held
to sixty-six characters.

Both shapes carry the same bar and the same footer, because a reader must
never have to work out which site they are on. The body changes.

> [!NOTE]
> A field is invisible only because something claimed it. One nobody
> claims renders as a definition list in the body, which is what a
> misspelt field looks like. `:laoyut: marketing` prints the word and the
> value above the title of a page that is still a manual.

<a id="hero"></a>

## hero

The opening claim of a marketing page, beside one decorative image. It goes
right after the document title, so the title stays the page's real heading,
browser title and source for navigation.

The opening summary belongs inside the directive.

![](../_images/design-system-workbench.png)

The document title stands above it in the source and is not part of it. The
argument is the image source. The theme composes the split, the stack and
the figure it already has. At a narrow viewport that split becomes a column
by the rule of every other split in the system. Content after the hero and
before the next band stays part of the opening section.

<a id="confval-hero-alt"></a>

**`alt`**

- Type: string
- Default: ""

What the image shows, when it adds a meaning the copy lacks. Leave it out
for a decorative illustration whose subject already has its name beside
it.

<a id="band"></a>

## band

A full-bleed section of a landing page. The ground runs edge to edge, and
the content inside keeps the page measure.

## This heading is a band, on a manual page

And the paragraph after it, beside the section
rather than inside it. What follows a band
belongs to it on a page built out of bands.
This page is not one.

On a page whose layout is not `marketing`, that is the whole of it: a
section inside the column, not a ground edge to edge. The page decides the
shape a band takes, not the band.

**A band does not wrap a page in itself. It opens one.** What follows belongs
to it until the next band starts. What stands before the first one is a
band as well: a page opens on the canvas. That is the whole syntax, and it
has a reason beyond a tidy source.

A band is full-bleed and takes the page inset itself. So a band inside another indents its text by a gutter nobody
asked for, and stops at the width of its parent.

```text
.. band:: What it costs
   :quiet:
   :id: pricing

Everything from here, up to the next band.

.. band::

And this is back on the canvas.
```

That one is a print, not a render, and it is the only source on this page
that is. What a band does with the content after it happens where the page
is bands. Here it renders as two sections with the text loose between them,
which is what the example above shows.

A page with no band at all is the single band it looks like.

<a id="confval-quiet"></a>

**`quiet`**

- Type: flag

The second ground. Quiet and plain in turn make a run of bands read as a
sequence, not as a wall. Two bands in a row share one hairline.

<a id="confval-id"></a>

**`id`**

- Type: string

An anchor, so a link elsewhere on the site can land on this section.

<a id="confval-the-heading"></a>

**`the heading`**

- Type: string

The band's argument. It is an option and not a section heading, because
a section heading inside a directive is not one. reStructuredText parses
sections at document level. A line with `====` under it, written in
here, ships both the line and the equals signs as text.

The landing page of [the example project](example.md) is the same
directive at home, with the run of them at work.

<a id="grid"></a>

## grid

A set read side by side, reflowed by its own minimum width.

**[What it is](index.md)**

A badge above the title, and the whole
card lit at the top of its frame under
the pointer. A paragraph long enough to
decide how tall this row is. That is the
only thing the card beside it has to
agree with.

**[What it costs](installation.md)**

One Composer package.

No column count, and that is the design. Three across on a desk, two on a
tablet, one on a phone, from how narrow an item can get, not from a
breakpoint. It holds cards, figures, or anything else read as a set. Each
item draws itself, and the grid decides how many stand in a row.

The two above differ in length on purpose. A set whose items say the same
amount cannot show what the wall does. The short one draws to the row, not
to its own sentence. The element is `sds-grid` in
[Content](../frontend/components/content.md).

<a id="confval-grid-variant"></a>

**`the argument`**

- Type: default | wide | dense | flush

How much room one item needs, said as what the items hold, not as a
number. `wide` for a card with a picture and a paragraph, `dense` for
a figure or a name and a glyph. `flush` takes the gutter out, so the
set shares a hairline and reads as one wall. Without it the set gets the
width every set gets. A name the element does not define falls back, and
does not pass through. `:variant:` says the same thing as an option.

<a id="confval-grid-class"></a>

**`class`**

- Type: string

Carried onto the element. An author who wrote it meant it for their own
stylesheet, and a theme must not drop what it does not understand.

<a id="split"></a>

## split

Two of anything, side by side until there is no room for two.

A paragraph and a picture are two blocks,
so they stand as two columns and nothing
here says which is which.

![The workbench, beside the paragraph](../_images/design-system-workbench.png)

**Every block in it is a column.** That is the whole rule, and why the
example above needs nothing to mark its halves. A paragraph is one block,
and a figure is another. The moment a side is a heading, its paragraph and
a press, those are three columns, unless something says where the side
ends. `half` is that something.

No width and no count anywhere. The halves fold under each other by their
own minimum, the way every set in this system reflows. The class is
`.sds-split` in [Page layout](../frontend/layout.md).

<a id="confval-split-align"></a>

**`align`**

- Type: start | center | end

Where the shorter half stands against the taller one: at the top, level
with it, or at the foot. `start` is the default, and `center` is what
a line beside a picture usually wants.

<a id="confval-split-leads"></a>

**`leads`**

- Type: start | end

Which half comes first once the two have stacked. `start` is the
written order. `end` puts the second half above the first. A picture at
the end of the line on a page, and above the sentence it illustrates on a
phone. It changes nothing while the two fit side by side. The order a
reader reads is not the source order at every width, and the layout
cannot work that one out itself.

<a id="confval-split-class"></a>

**`class`**

- Type: string

Carried onto the split, for the reason the grid's is.

<a id="half"></a>

## half

One side of a split: the blocks that stand together as one column.

## Two paragraphs, one side

This is the first of them, and it is not a
column.

This is the second. Without the `half`
around both, it is one.

![The workbench, read before the text on a phone](../_images/design-system-workbench.png)

It takes no position of its own. The split decides where a half stands,
because the other half is what it stands against. Anywhere else it is the
blocks it holds, in the rhythm a page keeps between them. Its optional
argument becomes an `h2` inside the column. Use it when the heading names
that side, not both sides of the split. A reStructuredText section heading
has no place inside a directive.

<a id="confval-half-class"></a>

**`class`**

- Type: string

Carried onto the column, for the reason `split` carries it.

<a id="card"></a>

## card

One card: a title that goes somewhere, and what is behind it.

**[Installation](installation.md)**

What the package needs, and the commands that
render a project with it.

For a desk

<a id="confval-card-href"></a>

**`href`**

- Type: string

A document, as a `:doc:` reference spells it, resolved per page. It is
the same thing the title's own reference says, for a card whose title is
plain text. Where both stand, this one wins.

<a id="confval-label"></a>

**`label`**

- Type: string

The tracked-out line over the title. The name or number of a set of
cards, `CHAPTER 02`, `FOR EDITORS`, or the date of an entry. The same
register and the same line.

<a id="confval-tag"></a>

**`tag`**

- Type: string

What kind of thing the card is, in the badge beside the label. A fact
about the card, not a result, so it carries no tone and no glyph. The
row drops where neither this nor the label stands.

<a id="confval-icon"></a>

**`icon`**

- Type: string

A glyph above the label, for a set a reader tells apart before a read.
The name is an icon of this system; see [Icons](../design-system/icons.md).

<a id="confval-card-src"></a>

**`src`**

- Type: string

The picture, flush at the top of the card. The render copies a path in
the documentation source into the output and resolves it per page. A URL
somewhere else stays as it is. Either way it is one `<img>`, so a
drawing arrives in the colours its file declares.
[Artwork](../design-system/artwork.md) says why, and what the file has to be ready
for.

The name is `src` here and on the element, because everything in this
system that takes a file has that name.

<a id="confval-card-alt"></a>

**`alt`**

- Type: string

What the picture shows, for a reader who cannot see it. Written and
empty says decorative, a card whose art only repeats the title. Left out
entirely says nobody decided, which reads very differently.

<a id="confval-footer"></a>

**`footer`**

- Type: string

One line under a hairline at the foot of the card: what the reader gets
there, who it is for, what state it is in.

<a id="confval-action"></a>

**`action`**

- Type: string

The call to action, in words: `Read it`. Not a button and not a second
link. The whole card already goes there, so this is the line that says
so, and the arrow after it leans out under the pointer. Drawn only where
the card has somewhere to go.

<a id="confval-card-class"></a>

**`class`**

- Type: string

Carried onto the element, for the reason the grid's is.

**The title carries the target.** \``.. card:: :ref:`Introduction
\<introduction\>\`\`\` is how a TYPO3 manual writes a card. The words of the
reference become the heading, and the reference becomes where the card
goes. A plain title with `:href:` says the same thing the other way round.

**The whole card is the link, and there is exactly one.** The title's anchor
stretches over the frame. So a screen reader announces the title, while a
pointer hits the card. A second anchor inside it is a second destination
under one frame, which is why there is no option for a button. A link in
the prose of a card still works, and is a card that asks to be two cards.

**The options are \`\`sds-card\`\`'s properties, all of them, spelt the way the
element spells them.** A directive that draws a component and answers for
half of it sends the author to their own stylesheet for the other half.
That is the one thing this system exists to prevent.

One that renames what it carries makes them translate a card they have
already read. `href` links and
`src` takes a file here for the reason they do everywhere else. What the
element gains, this gains. Its reference is `sds-card` in
[Content](../frontend/components/content.md).

The node is `sds-card` itself and not a `div` with its classes. The
element is the front door here as everywhere else. So the card draws in one
file, and a rendered page cannot drift from one a product wrote. The template
writes none of the card. It sets the options above and lets the element
draw its own markup, which is what makes the card the component's to
change.

A reader with no JavaScript gets the whole of it anyway. Every element in
the site renders before the publish. So the picture, the row, the title and
the summary are in the document with no script. In a browser the element
upgrades over that rendering. This is the theme-wide arrangement,
not the card's own; see [Core markup, and what it becomes](markup.md).

<a id="stat"></a>

## stat

One number as a fact: the figure, what the count is of, and the line that
bounds it.

**240 ms** — median answer
Measured over the last release, on a warm index.

**2 of 3** — sources answering
One is slow and one is unreachable from the checker.

<a id="confval-stat-value"></a>

**`the argument`**

- Type: string
- Required

The figure, `5`, `240`, `12.4+`, never "many". It is the argument
and not an option because it is what the line is about.

<a id="confval-stat-unit"></a>

**`unit`**

- Type: string

What the figure is in: `ms`, `%`, `kB`. The element sets it a step
down. It joins it to the number with the narrow no-break space a figure
must not split from, so no page has to know that character.

<a id="confval-stat-label"></a>

**`label`**

- Type: string

What the count is of, under the figure and in the label register.

<a id="confval-stat-of"></a>

**`of`**

- Type: string

The whole the figure is a part of, after it: `2 of 3`. Only where the
figure is a part. A measurement is out of nothing. It is words and not a
bar, so every figure in a set keeps the same shape and their notes start
on one line.

<a id="confval-stat-icon"></a>

**`icon`**

- Type: string

A glyph on the figure's line, before the number. Muted and never in a
status colour, for the reason a card's is. A figure is a subject, not a
result.

<a id="confval-stat-class"></a>

**`class`**

- Type: string

Carried onto the element, for the reason the grid's is.

**The body is the bound, and in practice it is mandatory.** "5 sources" says
nothing until it says which five. A figure with no bound is a claim, not a
fact, which is the whole reason `sds-stat` is a component. It stands
between the tags, not as an option, because out of a document that line
carries links.

**A set of figures is a set**, so it goes in `grid` like any other. At
`dense`, the width a number and the line under it hold. `flush` works
too. There the figures share a hairline, and the wall gives each its ground.

The frame in a wall is the wall's. So a figure anywhere else stays bare, and
a row of numbers on a page is not a row of boxes. The element is
`sds-stat` in [Content](../frontend/components/content.md), beside its grid.

<a id="swatch"></a>

## swatch

One colour of a palette: the chip, its name, and what it resolves to.

- **--accent** `var(--accent)` — `#FF8700`

- **--text-primary** `var(--text-primary)` — `light-dark(#1C1A17, #EDE9E2)`

- **--border-subtle** `var(--border-subtle)` — `light-dark(#E3DFD6, #2B2823)`

<a id="confval-swatch-value"></a>

**`the argument`**

- Type: string
- Required

What paints the chip: a token as written, `var(--accent)`, or a literal
where the value belongs to a mode the page is not in. It is the argument
because it is what the line is about. **Anything that is not a colour
drops out, and nothing paints it.** The value arrives from a document,
and a style attribute is not where a theme finds out what it is.

<a id="confval-swatch-name"></a>

**`name`**

- Type: string

The name of the colour. The token where there is one, because that is
the name a design writes. The human name where the palette has no
tokens.

<a id="confval-swatch-resolved"></a>

**`resolved`**

- Type: string

What that name resolves to, in full. A token alone documents half the
system. The value is the half that says what the mode did with it, and a
pair stands as the pair: `light-dark(#FFFFFF, #171614)`.

<a id="confval-swatch-kind"></a>

**`kind`**

- Type: string

`fill` (the default) or `line`. A hairline is a colour too and cannot
show as a fill. At one pixel a value is invisible, and as a fill it is a
different job by the same number. `line` makes the chip its own edge,
with the page's ground inside it.

<a id="confval-swatch-class"></a>

**`class`**

- Type: string

Carried onto the element, for the reason the grid's is.

**There is no body.** A colour that needs a paragraph carries a rule about
where it can appear. That rule is prose beside the palette, not inside one
entry of it.

**A palette is a set**, so it goes in `grid` like any other. At `wide`,
the width a name and a `light-dark()` pair under it hold. The element is
`sds-swatch` in [Content](../frontend/components/content.md).

<a id="surface"></a>

## surface

One filled plane, with a statement in place.

The tool reads every source. It writes nothing back.

**Rule 02**

Their origins tell two answers that disagree

apart.

<a id="confval-surface-heading"></a>

**`the argument`**

- Type: string
- Required

The title of the plane, in the quieter register. This is not a
destination, and a title that looks like one is a promise the box does
not keep.

<a id="confval-surface-plane"></a>

**`plane`**

- Type: string

The fill. `raised` sits on the canvas and reads as a plane. `sunken`
is machine output: code, logs, structured content. Named for the fill,
because in a system with no shadows that is what tells two planes apart.
`raised` is the default.

<a id="confval-surface-label"></a>

**`label`**

- Type: string

The tracked-out line over the title, where a set has numbers or sources:
`AUDIENCE 01`, `SOURCE`, `STEP 02`. Over the title, not in it. A
title with its own number reads as part of the sentence.

<a id="confval-surface-icon"></a>

**`icon`**

- Type: string

A glyph above the label, where a reader tells a set apart before a read.
It stands beside the plane's own title, never alone, and takes the muted
ink for the reason a card's does. A plane is a subject, not a result.

<a id="confval-surface-class"></a>

**`class`**

- Type: string

Carried onto the element, for the reason the grid's is.

**A plane states, a card goes somewhere.** That is the whole line between
the two, and it decides which one a page wants. A card's frame is the link
and its title is the anchor, so a set of planes claims nothing to click.
Neither is what `.. topic::` is. A digression in the reading flow that the
outline does not list stays an `<aside>`, and is not one of a set.

**It goes in a** `grid` **like any other set**, at the width the
statements hold. A plane on its own is a plane in the flow and renders, but
a single one says nothing the paragraph above it did not. The element is
`sds-surface` in [Content](../frontend/components/content.md).

<a id="quote"></a>

## quote

A sentence from somewhere else, with its source.

> The fallback was never the problem. *Not saying*
> it was a fallback was the problem.
>
> — 24 July 2026

<a id="confval-quote-by"></a>

**`the argument`**

- Type: string
- Required

Who said it: a person, a document, a release note. It is the argument and
not an option because the element demands it. A quotation with no source
in a product's own writing reads as the product quoting itself. A
mandatory thing as an option is a thing authors leave out.

<a id="confval-quote-as"></a>

**`as`**

- Type: string

What they are to the subject, where the name alone does not say it: a
maintainer, a reviewer, the documentation. Spelt `as` and not `role`,
because `role` is the global ARIA attribute and claims a role that does
not exist.

<a id="confval-quote-meta"></a>

**`meta`**

- Type: string

When, and anything else in the label register: a date, a release, a
revision.

<a id="confval-quote-initials"></a>

**`initials`**

- Type: string

Their initials, and the monogram draws only with these given. A byline
derives them from a name. A quotation does not, because half of what is
worth a quote is a document. A monogram of a filename is a person
invented for a source with none.

<a id="confval-quote-href"></a>

**`href`**

- Type: string

Where to read it in full. The attribution becomes that link. A target
outside the site stays as it is, and one inside it resolves like any
other reference.

<a id="confval-quote-class"></a>

**`class`**

- Type: string

Carried onto the element, for the reason the grid's is.

**The sentence goes between the tags**, because out of a document it carries
links and emphasis, which an attribute cannot hold. A block quote is the
spelling to reach for, and it is not available. The parser resolves an
indented block with an attribution line into a definition list, so
`<blockquote>` never reaches a template. This directive is how a manual
quotes anything. The element is `sds-quote` in
[Content](../frontend/components/content.md). The attribution it draws is
`sds-byline`, which is why there is no option here for the order of that
row.

<a id="button"></a>

## button

One press, and where it goes.

[Installation](installation.md)

[The renderer](https://docs.phpdoc.org/components/guides/guides/)

<a id="confval-button-label"></a>

**`the argument`**

- Type: string
- Required

The label, and where the press goes with it. As a reference, a `:doc:`
or an external link, the words are the label and the reference is the
target. A card's title carries the same thing. It is the argument
and not an option because it is what the control says.

<a id="confval-button-href"></a>

**`href`**

- Type: string

The target as a path instead, and it wins where both stand.

<a id="confval-button-variant"></a>

**`variant`**

- Type: string
- Default: "primary"

`primary`, `secondary` or `ghost`. One primary per view. A second
makes neither of them mean anything.

<a id="confval-button-size"></a>

**`size`**

- Type: string
- Default: "md"

`sm` for the smaller control, a press beside a line of text, not under
a section. `lg` for the one action a page is for. Beside a second large
button neither is the one, and that is what `md` is for.

<a id="confval-button-icon"></a>

**`icon`**

- Type: string

A glyph before the label, an icon of this system; see
[Icons](../design-system/icons.md).

<a id="confval-icon-only"></a>

**`icon-only`**

- Type: flag

The glyph is the whole control, and the button is a square. It needs a
name, and the label is it. The words become the control's title and do
not draw.

<a id="confval-button-title"></a>

**`title`**

- Type: string

The control's name where the label does not say it, and what a pointer
at rest on it reads.

<a id="confval-button-rel"></a>

**`rel`**

- Type: string

What the target is to this page: `external`, `prev`, `next`. Only
with a target, as the anchor's own attribute.

<a id="confval-disabled"></a>

**`disabled`**

- Type: flag

The control is there and takes no press. It drops where the press goes
somewhere. A link has no disabled state, and a grey one the browser
follows anyway is worse than none.

<a id="confval-button-class"></a>

**`class`**

- Type: string

Carried onto the element, for the reason the grid's is.

**A press on a rendered page is a link.** With somewhere to go, the element
draws an `<a>`. That gives the reader the middle click, the hover target
and the status line the browser already has. A control with a listener has
none of them.

A button with nowhere to go does nothing on a press. So `type`, `for`
and `command` are not on offer. A document has no form
to submit and no element to command, and a page that needs them is an
application, not a manual.

**The label is the words, not the markup.** A reference rendered where it
stands puts a link inside the control. The reference becomes the control's
target instead. That is the trade the card makes with its title, and why
both come off the node, not out of a template.

The element is `sds-button` in [Controls](../frontend/components/controls.md), with
the properties this leaves out and the ones above.

<a id="button-bar"></a>

## button-bar

The controls of a page, in one row.

[Installation](installation.md)

[The renderer](https://docs.phpdoc.org/components/guides/guides/)

<a id="confval-button-bar-class"></a>

**`class`**

- Type: string

Carried onto the row, for the reason the grid's is.

Named for what it holds and the shape it holds them in. A row of controls
is layout, not a component, so it has no variant. What stands in it sits on
one line, centred against each other, which is what a link beside a button
needs. It holds whatever a page puts in it, and
one press in it is the primary. It emits `.sds-actions`, the row in
[Page layout](../frontend/layout.md), written by the theme the way `band` writes its
section.

<a id="directory-tree"></a>

## directory-tree

A directory, in the shape it has on disk, in the spelling a TYPO3 manual
already uses. So a page written for the other theme renders here as it is.

A nested list, because that is what a tree is. **The name is the first
literal in an item, and the rest of the line is what it is for.** A filename
is a literal anyway, and prose after it is prose about it, so there is no
syntax of this directive's own to learn. An item with no literal is a name
and nothing else.

```
docs/  — the sources, as a project already writes them  Index.rst  guides.xml  — the theme, the mark and the versionssite/  — what the render writes, and what is published  index.html  styles/  — the drop-in, copied there by the finishing step    soul.css    soul.js
```

The fold is `<details>`, so it works before a script runs and
find-in-page opens the directory it lands in. This replaces the tree as a
text block with its notes lined up with spaces. That alignment goes wrong
the moment one name changes by a character, and a reader with a narrow
window never sees it straight.

<a id="confval-directory-tree-level"></a>

**`level`**

- Type: integer
- Default: 2

How deep it stands **open**. Nothing drops below it. What is deeper
folds, which a reader can undo. A level past the depth of the tree opens
the whole of it.

The theme this spelling comes from stops the *draw* below the level
instead. That takes away what a reader came for and gives them no way to
ask for it. A page that set it for that reason still renders here, with
the deep part folded, not gone.

<a id="confval-directory-tree-show-file-icons"></a>

**`show-file-icons`**

- Type: flag

Mark a directory and a file as such. Off by default. The fold says which
is which wherever there is anything to fold, and a wall of glyphs down a
short tree is decoration. The slash in its name tells an empty directory
apart.

<a id="confval-directory-tree-class"></a>

**`class`**

Passed to the element, for the surface that has to place one.

<a id="accordion"></a>

## accordion

Questions with their answers folded behind them, in the spelling a TYPO3
manual already uses.

**What does it need installed?**

PHP 8.2 or newer, and a project it can read —
see [Installation](installation.md).

**Can it run in CI?**

Yes. [Publishing it, in CI](publishing.md) is the job, command for command.

<a id="confval-accordion-group"></a>

**`group`**

- Type: string

The set's name. It is the group the answers fold in, so one open closes
the last. A page with two sets gives them different names, or one closes
the other's answers. A set with none gets one.

It is `:group:` and not `:name:` because an answer takes `:name:`
in the meaning every other directive gives it: the address of a link.
One spelling for both is two meanings a page apart.

<a id="confval-multiple"></a>

**`multiple`**

- Type: flag

More than one answer open at a time, for a set whose answers a reader
compares. Without it a set is exclusive, because a list is easier to read
than a wall.

<a id="confval-accordion-class"></a>

**`class`**

- Type: string

Carried onto the element, for the reason the grid's is.

**The fold is a** `<details>`. It works before a script runs, the keyboard
reaches it, find-in-page opens the answer it lands in, and the platform
closes the others. That is why the answers carry the set's name, and why a
page never writes one on an item. The element is `sds-accordion` in
[Navigation](../frontend/components/navigation.md).

<a id="accordion-item"></a>

## accordion-item

One question, and the blocks folded behind it.

**What does it need installed?**

PHP 8.2 or newer, and a project it can read.
No daemon, and no database of its own.

<a id="confval-open"></a>

**`open`**

- Type: flag

Open at the start. For the first answer on a page of them, usually, so
the shape of an answer shows without a press. `:show:` is the same flag
under the name the Bootstrap theme gave it.

<a id="confval-accordion-item-header-level"></a>

**`header-level`**

- Type: integer

Accepted and dropped. A control folds a set of questions, not a heading,
so it takes no level in the outline.

<a id="confval-accordion-item-name"></a>

**`name`**

- Type: string

The address of this one answer, for a page that links to it. It stands
on the answer, not on the question. The platform opens a fold whose
content a fragment points into. One a fragment points at stays shut,
which is why a link that has to show the answer aims inside it. The
reader still arrives at the question. The answer keeps the head's height
as scroll margin, so the row stands at the line and not behind the bar.

<a id="confval-accordion-item-class"></a>

**`class`**

- Type: string

Carried onto the element, for the reason the grid's is.

**The question is the argument, and the answer follows it.** That is not a
preference. An answer is paragraphs, lists and code blocks, which no
attribute carries. The node is `sds-accordion-item` itself, and the
template writes none of its markup, the same arrangement as the cards
above.

<a id="facts"></a>

## facts

A block of facts, scanned down the terms. The body is a field list, which
is the shape a name-and-value pair already has in the source.

- **Change:** [1482](https://example.org/c/1482) · patch set 2
- **Target:** `main` · `2.4`
- **Read:** 2026-09-11, in a worktree of its own

The field's name is the term and its body the value, and a value carries a
link, a literal or a badge. The element is `sds-facts` in
[Data & machine output](../frontend/components/data.md).

<a id="confval-facts-class"></a>

**`class`**

- Type: string

Carried onto the element, for the reason the grid's is.

<a id="register"></a>

## register

A list a reader cites: numbered, addressed, and scanned at a glance first.
The entries stand in the body in any order. The register numbers them when
the page renders, sorts them into their groups, and writes every one into
one table first. Every entry with a `:todo:` goes into a second table, the
work the list asks for. No line of the document says a number.

**The unit suite for the lookup fails** (blocks, introduced by this change)
Every case that resolves one key twice fails.

To do: Adapt the four tests that expect the second read.

**The key stays the file's own identifier** (ok)
Checked against a catalogue with a dotted key.

<a id="confval-register-name"></a>

**`name`**

- Type: string
- Default: "register"

What the group sections and the entries' addresses start with,
`findings-blocks` and `findings-1-1`, so two registers on one page
keep apart.

<a id="confval-register-prefix"></a>

**`prefix`**

- Type: string

What stands before every entry's number, `F` for findings. Nothing
unless the register says so: an entry is `1.1` by itself.

<a id="confval-register-todo-prefix"></a>

**`todo-prefix`**

- Type: string

What stands before the number of what is to do, `T` for the work a
finding asks for.

<a id="confval-register-findings"></a>

**`findings`**

- Type: flag

The four groups of a review's findings, in the order a review reads
them: *Blocks submission*, *Sent back*, *Worth a change*, *Checked and
correct*. Their keys are `blocks`, `back`, `change` and `ok`.

<a id="confval-register-groups"></a>

**`groups`**

- Type: string

Any other set of groups, as the JSON the element takes:
`[{ "key": "…", "heading": "…", "label": "…", "tone": "…" }]`. An
entry whose group the register does not name stands last, in the order
written. Without groups the entries count up as written.

<a id="confval-register-class"></a>

**`class`**

- Type: string

Carried onto the element, for the reason the grid's is.

The element is `sds-register` in [Content](../frontend/components/content.md),
which says how it numbers and what it draws.

<a id="entry"></a>

## entry

One entry of a register. Its title is the argument, what it holds the
body, and everything that fits in a string an option.

**The reader is a new instance per call** (change, older than the change)
The service is a singleton, so one reader in the constructor is the
same object with one construction fewer per label.

To do: Construct the reader once, in the constructor.

<a id="confval-entry-group"></a>

**`group`**

- Type: string

The key of the group it belongs to, for the register that groups.

<a id="confval-entry-origin"></a>

**`origin`**

- Type: string

Where it came from, in a few words: `introduced by this change`,
`older than the change`.

<a id="confval-entry-todo"></a>

**`todo`**

- Type: string

What is to do about it, in one sentence. It stands as the entry's last
line, and the register lists it with the work of the other entries.

<a id="confval-entry-name"></a>

**`name`**

- Type: string

The address of this one entry, where the register's own, made from the
number, is not the one a page wants to cite.

<a id="confval-entry-class"></a>

**`class`**

- Type: string

Carried onto the element, for the reason the grid's is.

<a id="steps"></a>

## steps

An instruction read from the top, numbered down one rail.

1. **Require the package**
   It brings the renderer, the highlighter and the Markdown parser with
   it, so this one line is all four.
2. **Select the theme**
   `theme="soul"` in `guides.xml` names it, and the `<extension>`
   element is what makes it exist — see [Installation](installation.md).
3. **Draw the signet** (optional)
   A project with no mark takes its title in the bar, which is where a
   name belongs when there is only one.

<a id="confval-steps-class"></a>

**`class`**

- Type: string

Carried onto the element, for the reason the grid's is.

**No option numbers a stop, and there is none to add.** The number is the
set's own count. So a step in the middle renumbers everything under it, and
no page changes in two places. That is the whole reason to write a set, not
four paragraphs with a typed figure each. For the same reason nothing here
says how far along a reader is. A rendered page does not know, and a manual
that guessed is wrong for every reader but one.

Use it where the order is the point. Things to do in any order are a bullet
list. A numbered list from `#.` is the right shape for steps of one line
each. This one is for stops with a command, a file to edit and the output
that says it worked. The element is `sds-steps` in
[Content](../frontend/components/content.md).

<a id="step"></a>

## step

One stop of an instruction, and the blocks that do it.

1. <a id="render-the-site"></a>

   **Render the site**
   The first command writes documents; the second turns them into a site.

   ```bash
   vendor/bin/guides docs --output=site -c docs --fail-on-error
   ```

It stands inside a `steps`, and that is not a formality. A stop draws a
number, and a number is a place in a set. A step anywhere else is the
blocks it holds, the way a `half` outside a `split` is the column it
was going to be.

<a id="confval-optional"></a>

**`optional`**

- Type: flag

A stop a reader can skip. The disc stays unfilled, and the word stands
beside the title. An unfilled ring says nothing to a reader who cannot
see it, so the drawing is never the whole claim.

<a id="confval-step-name"></a>

**`name`**

- Type: string

The address of this one stop, for a page that links to it, as `:name:`
means everywhere else. It lands on the stop itself, and nothing has to
open first. A step has no fold, which is the one thing that made
`accordion-item` put its address on the answer instead.

<a id="confval-step-class"></a>

**`class`**

- Type: string

Carried onto the element, for the reason the grid's is.

**The title is the argument, and the work follows it**, for the reason a
question and its answer stand that way. A command, a file to edit and the
line that says it worked are what no attribute carries. The title takes no
heading level either. The number says where a reader is in an instruction,
and a page whose outline is its steps has buried its own sections.

<a id="example"></a>

## example

What the author wrote, and under it what it renders as, out of one body.

[Installation](installation.md)

**The block a reader copies is the block that ran.** A page that prints
markup in a `code-block` and writes it a second time to render it holds
two copies of one example. The copy nobody checks is the one the reader
takes away. Here the print is the lines the parser got, and the render
comes from those same lines, so the two cannot part. `specimen` below
does that for a card, a level up.

<a id="confval-example-caption"></a>

**`the argument`**

- Type: string

The caption over the block: what this one shows. Without it the block
carries nothing but its language and the button that copies it.

<a id="confval-example-language"></a>

**`language`**

- Type: string
- Default: "text"

The colour of the print. `text` by default, because no highlighter on
this site knows reStructuredText, and a language the server cannot
colour is better said than faked. A project whose examples are in
something it does know says so here.

<a id="confval-example-class"></a>

**`class`**

- Type: string

Carried onto the frame the render stands in, for the reason the grid's
is.

**The frame has a dashed line, the only one in the system.** That is what
it is for. A solid one is a box on the page. What is inside this one is not
part of the page: a thing shown, at the end of a run of things read. It is
`.sds-example`, and it has no fill either. So a card or a surface in it
stands on its real ground, not on a plane the manual put under it.

The options are not in the print, because the parser has taken them off the
body by the time the directive sees it.

**What an example cannot show is a page.** The frame is a box in the column.
So a band inside one is the section a band is on a manual page, not the
full-bleed ground of a marketing one. That is what the band above is in an
example to show.

What follows a band belongs to it only where the page is bands. So a source
that opens two of them renders here as two sections with
the text loose between them. That one stays a `code-block` beside prose
that says so. `:layout:` is a field, not a directive, and has nowhere to
go in a body.

<a id="specimen"></a>

## specimen

A rendered card, at the size of its drawing.

[Surfaces · 700x277](../_cards/guidelines/colors-surfaces.card.html)

<a id="confval-the-card"></a>

**`the card`**

- Type: string
- Required

The directive's argument: a path under `_cards/` in the documentation
source. The card is a whole document with a stylesheet of its own, so it
stands in a frame, not inline. It carries the specimen chrome, which a
page must not inherit, and it can pin its own mode.

<a id="confval-viewport"></a>

**`viewport`**

- Type: string
- Default: "700x260"

Width by height, in pixels, and it is not decoration. Every card
declares the size of its measurement in its own `@dsCard` header, and
the gate proves it still fits there. A card at any other size documents
something nobody checked.

<a id="confval-title"></a>

**`title`**

- Type: string
- Default: "Specimen"

The caption under the frame, beside the viewport. It is also the frame's
accessible name, the only thing a reader who cannot see the card gets.

The frame is an `sds-embed`, the element in
[Media](../frontend/components/media.md), fixed at the viewport above. Where the
column is narrower it scrolls, and does not squeeze the card into a width
nothing measured. [Core markup, and what it becomes](markup.md) has the other half of that node: a video,
the same directive's opposite, which fills the column instead.

The cards have to be inside the documentation source. The renderer copies an
asset a document points at and nothing else. This repository's \```` make
guides`` copies ``specimens/`` into ``docs/_cards/ ```\` before each render and
rewrites the stylesheet links inside each card on the way. That directory
is a task's output, and git ignores it.

> [!IMPORTANT]
> This directive is for a project that ships rendered cards of its own. It
> makes a guideline page show the rule instead of a description of it. It
> is the reason the guidelines in this manual and the specimens in
> Storybook cannot say different things: they are the same file.

> [!NOTE]
> [Core markup, and what it becomes](markup.md) for what the renderer's own directives, admonitions, code
> blocks, tabs, `confval`, topics, come out as under this theme.
