📐 Slide Layouts
Declaring a slide’s layout does two things today: it types the slide, and it tells the linter which content schema to validate it against. It also puts the type in the generated HTML, so a theme can style it.
It also changes how the slide looks — for nine of them. Since ziradocs/toolchain#254, the generator ships a CSS file per covered layout, keyed on the
data-slide-typeattribute it emits. The rest render like a content slide. See Which layouts have styling below for exactly which is which — the table is the contract, not a description of intent.
🎯 Layout Overview
Section titled “🎯 Layout Overview”Setting a layout types the slide and, when that layout has a schema, tells the linter which content rules to check it against. There are exactly two ways to set one, one per mode.
Flex mode — a layout: block before the heading
Section titled “Flex mode — a layout: block before the heading”---layout: hero---# Welcome to Our Product## Revolutionary solutions for modern businessesThe block goes immediately before the slide’s heading. Only layout is read from it: any other
key is reported as having no effect. An explicit layout: also overrides the default rule that
types the deck’s first # heading as the title slide.
Strict mode — the SLIDE <type> keyword
Section titled “Strict mode — the SLIDE <type> keyword”SLIDE testimonial title: "What our customers say"
TEXT "This product changed our business completely." - Jane Smith, CEOThe type goes on the SLIDE line itself. It is not a property inside the block — writing
layout: "testimonial" under SLIDE intro is an error (Unknown content block property).
📋 Recognized layouts
Section titled “📋 Recognized layouts”23 layout names are recognized; 19 of them have a schema. A name outside these 23 still types
the slide, but the linter warns (LAYOUT_UNKNOWN) because nothing validates it — that is how a
typo like comparision surfaces.
The four without a schema (chapter, cover, intro, with_directive) are accepted and mapped
to a template by the generator; they simply have no content rules of their own, so nothing about
their content is checked.
What the linter actually enforces from a schema is the element count and the forbidden-element
list — both as warnings — plus a rule of the layout’s own, which 17 of the 19 schemas have
(title_slide and default have none). Min / Max below is the element count, ∞ meaning no
maximum.
The schema also declares required, optional and allowed properties. Those three are not evaluated by anything — they are metadata inside the struct, not rules (ziradocs/toolchain#256) — so they are not listed here. The only property checks that exist are three bespoke ones, listed under What fails the build below.
| Layout | Min / Max elements | Forbidden elements |
|---|---|---|
before_after |
2 / 4 | code, chart |
call_to_action |
1 / 3 | code, table, chart, mermaid |
chapter |
(no schema) | — |
closing |
0 / 3 | code, table, chart, mermaid, map |
code_example |
1 / 4 | table, chart, map |
comparison |
2 / 4 | code, mermaid, chart |
content |
1 / ∞ | — |
cover |
(no schema) | — |
dashboard |
1 / 6 | code, mermaid |
default |
0 / ∞ | — |
feature_showcase |
2 / 6 | code, table |
hero |
0 / 3 | code, table, chart |
intro |
(no schema) | — |
pricing |
1 / 4 | code, chart, mermaid |
process |
2 / 6 | code, table, chart |
section |
1 / 3 | code, table, chart, map |
stats |
1 / 3 | code, mermaid |
team |
1 / 8 | code, chart, table |
testimonial |
1 / 3 | code, table, chart |
timeline |
2 / 6 | code, table, chart |
title |
0 / ∞ | text, code, points, table, image |
title_slide |
0 / 1 | text, code, points, table |
with_directive |
(no schema) | — |
Those per-layout rules are the interesting half: a testimonial is checked for a quote and an
author, a code_example for a code block, a dashboard for metrics or a chart. See
llm-kit/validation-checklist.md
§5 for the rule IDs.
What fails the build
Section titled “What fails the build”Almost everything a layout can report is a warning. Exactly four diagnostics are errors, and they come from four layouts:
| Layout | Error | Condition |
|---|---|---|
title |
LAYOUT001 |
neither heading nor title is set |
content |
LAYOUT004 |
the slide has no elements at all |
code_example |
LAYOUT008 |
the slide has no code block |
hero |
LAYOUT009 |
title is not set |
Those are also the only property checks in the linter, which is why SLIDE comparison without a
title lints clean while SLIDE hero without one fails
(ziradocs/toolchain#256). Every other layout
reports warnings only, so a mismatched layout is noisy but still builds.
Read the row before declaring a layout. Those bounds were calibrated for strict mode, where
each declared block is one element; flex prose reaches them faster, so layout: testimonial on a
slide with eight elements trades a clean content slide for a pile of warnings
(ziradocs/toolchain#253).
🛠️ Layout Customization
Section titled “🛠️ Layout Customization”Using Layout with Content Types
Section titled “Using Layout with Content Types”With Text Elements
Section titled “With Text Elements”---layout: hero---
# Main Title## Subtitle
Regular content goes here. It is parsed and validated as a `hero` slide; the arrangement onscreen is the theme's job.With Multiple Elements
Section titled “With Multiple Elements”SLIDE feature_showcase title: "New Feature: Smart Analytics"
TEXT # New Feature: Smart Analytics Our latest feature provides intelligent insights.
IMAGE "./screenshots/analytics-dashboard.png" "Analytics Dashboard Screenshot"
POINTS - Real-time data processing - Automated insights generation - Custom report buildingWith Interactive Elements
Section titled “With Interactive Elements”<<quiz>> and <<poll>> are real elements since
ziradocs/toolchain#198. They carry a YAML body
and work in both dialects and both modes:
<<quiz>>question: "Which type of ML would you use for spam detection?"options: - "Unsupervised learning" - "Supervised learning" - "Reinforcement learning"answer: 1explanation: "We have labelled examples of spam and legitimate mail."<<end>>answer is 0-based: answer: 1 selects the second option. See
Quizzes and polls for the full key list and what
the rendered output does.
Layout Properties
Section titled “Layout Properties”Requires
v2.32.4or newer, and the two dialects fail differently inv2.26.0. Instrictit is a hard error —Unknown content block property: columnsand the build stops. Inflex, which is the default, the key is dropped with no diagnostic at all: the build reports zero warnings and the slide simply renders without the option.
A layout can carry options that change how its content is arranged (ziradocs/toolchain#255). They are declared per layout: writing one on a layout that does not accept it is reported, not silently ignored.
| Option | Layouts that accept it | Values |
|---|---|---|
columns |
comparison, stats, dashboard, call_to_action |
an integer from 1 to 4 |
align |
hero, testimonial, call_to_action |
left or center |
Flex puts them in the same block as layout:. The order inside the block does not matter, and
the keys go at the top level — the block is a list of key: value lines, not nested YAML:
---layout: comparisoncolumns: 2---## Two side by side
:::infoThe first option, with its points.:::
:::tipThe second one, beside it rather than under it.:::Strict puts them as properties under the SLIDE line, like title::
SLIDE comparison title: "Two side by side" columns: 2A value outside its range is reported (FLEX004 in flex, a parse error in strict) and the option is
dropped — never applied halfway. An option written on a layout that does not accept it is reported
per slide, naming that slide’s layout and what it does accept.
They travel in the AST as layout_config, and the HTML emits them as data-layout-columns /
data-layout-align, so a theme can react to them in pure CSS:
.slidelang-slide[data-slide-type="comparison"][data-layout-columns="2"] .slidelang-content-elements { display: grid; grid-template-columns: repeat(2, 1fr);}Any other key in that block still has no effect and is still reported (FLEX002 in flex, a hard
error in strict).
🎨 Layout with Themes
Section titled “🎨 Layout with Themes”A theme can style a layout through the selectors the generator emits (see below). The
--slidelang-layout-* variables shown in earlier versions of this page were never read by
anything and no longer appear anywhere; the layout CSS that ships today uses the ordinary theme
tokens. Those tokens carry the slidelang- prefix in the bundle — the layout files are written
against --primary-color and the loader rewrites them, so what a theme declares and redefines is
--slidelang-primary-color, exactly as every theme in the repo already does. Declare whatever
variables your own CSS uses:
{ "name": "corporate-theme", "variables": { "--hero-bg": "linear-gradient(135deg, #667eea 0%, #764ba2 100%)" }}.slidelang-slide[data-slide-type="hero"] { background: var(--hero-bg);}Layout-Specific CSS Classes
Section titled “Layout-Specific CSS Classes”Every slide carries its layout in two places in the generated HTML:
<div class="slidelang-slide slidelang-hero-slide" data-slide-type="hero">So a theme can target a layout either way:
.slidelang-slide[data-slide-type="hero"] { /* … */ }.slidelang-hero-slide { /* … */ }The bundled CSS keys on the attribute, not the class: data-slide-type is the block type
verbatim, so it is immune to the class-namespacing pass the generator runs over the template. Your
own theme CSS can use either.
Which layouts have styling
Section titled “Which layouts have styling”A layout only loads its CSS when a slide actually uses it, so a deck pays for nothing it does not write.
All 23 recognized names, and nothing else:
| Layouts | What you get | |
|---|---|---|
| Styled | comparison, stats, dashboard, testimonial, hero, call_to_action, timeline, process, code_example |
Its own CSS file, written against the shape that layout actually has in real decks |
| Base-styled | title, title_slide, cover, intro, section, chapter, closing, end |
The base stylesheet and the themes dress these; no separate file |
| Content-styled | content, default, with_directive |
The ordinary content slide — this is the baseline everything else is compared against |
| Not styled yet | before_after, feature_showcase, team, pricing |
Renders like a content slide |
The four in the last row are typed and validated like any other layout; only the appearance is
missing. before_after and feature_showcase need the template to group a heading with the
elements that follow it, which it does not do today — a split-screen before_after cannot be
expressed with the current DOM. team and pricing can be written as a table today, which is what
the example decks do, so a dedicated stylesheet has not been worth its weight yet.
title_slide, cover and intro are aliases of title, and chapter of section: they carry
their family’s class, so they look identical to it.
A layout without CSS is not an error. It types the slide and picks the linter’s schema, and renders like a content slide. Nothing is lost.
🔧 Composing a slide
Section titled “🔧 Composing a slide”There is no layout inheritance (extends:), no expression-evaluated layout
(layout: "{{ device == 'mobile' ? … }}"), and no way to nest several layouts inside one slide.
None of these parse.
For composition inside a slide, use what exists: <<grid>> / <<column>> for side-by-side
content, and ::: special blocks for callouts. See
Grid and Column Layouts.
Shared visual defaults across decks belong to the theme system, not to per-slide metadata.
📊 Working with layouts
Section titled “📊 Working with layouts”- Pick the layout that matches the content, not the one that looks nicest — the linter validates the slide against that layout’s schema, so a mismatch shows up as warnings.
- Read the schema before declaring a layout. Several cap how many elements a slide may hold, so
layout: testimonialon a slide with eight elements trades a cleancontentslide for a pile of warnings. - Check the result with
slidelang build --lint-onlybefore shipping a deck.
🎯 Layout Selection Guide
Section titled “🎯 Layout Selection Guide”Which layout fits which content. Remember this only affects typing and validation today, not appearance.
| Content Type | Recommended Layout | Alternative |
|---|---|---|
| Opening slide | hero |
call_to_action |
| Product features | feature_showcase |
comparison |
| Team introduction | team |
testimonial |
| Data presentation | stats |
dashboard |
| Process explanation | process |
timeline |
| Case study | before_after |
testimonial |
| Pricing | pricing |
comparison |
| Technical demo | code_example |
feature_showcase |
| Call to action | call_to_action |
hero |
🔗 Related Documentation
Section titled “🔗 Related Documentation”- Flex Mode Reference - Layout syntax in Flex mode
- Strict Mode Reference - The
SLIDE <type>form - Grid and Column Layouts - Composition inside a slide
One neighbouring page has not been reconciled with this one yet. Directives & Configuration documents a
layout_override:slide property the parser rejects, along withstyle_class=/custom_css=attributes and::::includedirectives that need the same check. Tracked in ziradocs/website#10 — until that lands, this page is the one to trust on layouts.Specialized Layouts has been reconciled: it now says per layout what its CSS actually does, and which layouts have none.