On this page
- Slide boundaries
- Templates and slots
- Automatic selection
- Two-column slides
- Images, quotes, and code
- Freeform placement
Slide boundaries
Separate slides with a Markdown thematic break, such as --- on its own line
with blank lines around it. An initial YAML front-matter block configures the
deck instead of creating a slide boundary.
---
theme: minimal
---
# Opening
## A short subtitle
---
# Agenda
- Introductions
- Results
- Questions
Templates and slots
Add <!-- layout: NAME --> to select a layout explicitly. The directive uses
the names below; the Ruby API returns symbols such as :title_body and
:two_column.
| Layout | Ruby symbol | Slots | Content |
|---|---|---|---|
title |
:title |
title, subtitle |
One or two headings |
title+body |
:title_body |
title, body |
A heading with text, lists, tables, or mixed blocks |
two-column |
:two_column |
title, left, right |
A heading with left and right div directives |
image+text |
:image_text |
title, text, image |
A heading, text blocks, and a local image |
full-bleed-image |
:full_bleed_image |
image |
Image content |
quote |
:quote |
quote, attribution |
A block quote and attribution |
code |
:code |
title, code |
A heading and fenced blocks |
blank |
:blank |
None | An empty template |
Explicit layouts take precedence even when the content does not fit their
slots. Use title+body for mixed content rather than forcing a template that
does not display all the blocks.
Automatic selection
Without a layout comment, Hadar selects the first matching case:
- A
leftorrightdiv directive selectstwo-column. - A block quote selects
quote. - Code blocks with only headings alongside them select
code. - Images with text select
image+text; image-only content selectsfull-bleed-image. - No content selects
blank. - One or two headings without other blocks select
title. - Everything else selects
title+body.
A slide with fenced code plus prose or a table uses title+body, keeping the
mixed content visible.
Two-column slides
Use Beid div directives to assign content to each column:
<!-- layout: two-column -->
# Revenue
::: left
Revenue rose **18%** year over year.
:::
::: right
New customers: 42
:::
The title becomes slot(:title), and the column content becomes slot(:left)
and slot(:right). Plain Markdown viewers may display the ::: markers.
Images, quotes, and code
For an image with explanatory text:
<!-- layout: image+text -->
# Revenue trend
Revenue increased throughout the quarter.

Use an existing local asset. Relative destinations resolve from the opened deck’s directory. Preview rejects remote URLs and unsupported URI schemes.
For a quotation:
<!-- layout: quote -->
> Keep the source editable.
The Hadar team
For source code:
<!-- layout: code -->
# A Ruby deck
```ruby
deck = Hadar::Deck.open("slides.md")
```
Freeform placement
Freeform is an explicit per-slide opt-in. Each Markdown block needs a preceding
placement comment with x,y,width,height percentages:
<!-- layout: freeform -->
<!-- place: 5,8,90,20 -->
# Quarterly report
<!-- place: 10,35,80,50 -->
Revenue increased **18%**.
Coordinates refer to the inner canvas after theme margins. Width and height must be positive, and each rectangle must fit within 0–100%. Missing, malformed, overflowing, or unused placement comments raise an error.
Blocks become source-order slots item_1, item_2, and so on. An image-only
paragraph becomes an image slot. Edit placement comments in the Markdown
source to reposition blocks; the editor does not provide drag-and-drop
positioning.
Plain Markdown viewers show the content in source order and lose the placement. Hadar displays a compatibility warning for these slides. After an external edit reloads a freeform slide, select the block again before editing, because its item number may have changed.
See the template layout decision and freeform placement decision for the source model.