Component reference
Every component here works in any slide without an import. This page is generated from the
catalog of @kadal/deck 0.10.0, the same data npx kadal-deck info components <Name>pnpm exec kadal-deck info components <Name>yarn kadal-deck info components <Name>bunx kadal-deck info components <Name>,
the VS Code extension’s hovers and the MCP servers read, so it matches the engine you install.
Props marked required must be given; the rest have the default shown, or none.
Layout
Section titled “Layout”Placing and sizing blocks on the 1920 × 1080 stage.
Absolute · Center · Col · Cols · Drag · DragArrow · FitText · Frame · Grid · Spacer · Stack · Stretch · Transform
Absolute
Section titled “Absolute”Places a block at stage coordinates (pixels on the 1920 × 1080 stage).
<Absolute x={1500} y={80} w={320}><Badge tone="warn">Draft</Badge></Absolute>| Prop | Type | Default | |
|---|---|---|---|
x |
number |
0 |
Left, px. |
y |
number |
0 |
Top, px. |
w |
number |
Width, px. | |
h |
number |
Height, px. | |
rotate |
number |
0 |
Degrees. |
className |
string |
Center
Section titled “Center”Centres its children horizontally and vertically in the space it has.
<Center>
# One big idea
</Center>| Prop | Type | Default | |
|---|---|---|---|
className |
string |
One column inside <Cols> (Markdown inside needs blank lines around it).
<Col span={2}>
Wide column
</Col>| Prop | Type | Default | |
|---|---|---|---|
className |
string |
||
span |
number |
Grid columns to span. |
Columns: each child (or <Col>) is a column. cols takes a CSS grid template.
<Cols cols="2fr 1fr"><Col>
The main point, in Markdown.
</Col><Col>

</Col></Cols>| Prop | Type | Default | |
|---|---|---|---|
cols |
string |
CSS grid-template-columns, e.g. “1fr 1fr” or “2fr 1fr”. | |
n |
number |
Number of equal columns (instead of cols). |
|
gap |
string |
"2rem" |
CSS gap. |
className |
string |
||
align |
string |
CSS align-items; “start” stops cards in a row from sharing a height. |
A block you place by hand. pos is “x,y,w,h[,rotation]” in stage pixels (_ height: automatic) or a name in the slide’s dragPos frontmatter. In kadal-deck dev, double-click it to move, resize, turn and nudge it; the position is saved into deck.mdx. Elsewhere it is simply placed.
<Drag pos="1400,120,380,_">

</Drag>| Prop | Type | Default | |
|---|---|---|---|
pos |
string |
“x,y,w,h[,r]” in stage pixels (_ height: automatic), or a name in the frontmatter’s dragPos. |
|
place |
string |
Where it sits while pos says nothing, in the same “x,y,w,h[,r]” form — how <Sticker x y size> places itself. The source still has no position, so the first drag writes pos. |
|
at |
ClickAt |
A click step, as <Click at>. |
|
hide |
boolean |
Start shown and hide at the step. | |
effect |
string |
"fade-in" |
The reveal effect with at (see <Click effect>). |
as |
ElementType |
The element (div). | |
className |
string |
||
style |
CSSProperties |
DragArrow
Section titled “DragArrow”An <Arrow> whose ends are dragged into place in kadal-deck dev. pos is “x,y,dx,dy” (from x,y by dx,dy) or a dragPos name.
<DragArrow pos="300,700,600,-280" color="var(--deck-accent)" width={4} />| Prop | Type | Default | |
|---|---|---|---|
pos |
string |
“x,y,dx,dy”: from (x, y) by (dx, dy), stage pixels — or a frontmatter dragPos name. |
|
width |
number |
2 |
Line width (px). |
color |
string |
"currentColor" |
CSS colour. |
twoWay |
boolean |
false |
Heads at both ends. |
at |
ClickAt |
A click step. | |
hide |
boolean |
||
effect |
string |
"fade-in" |
|
className |
string |
FitText
Section titled “FitText”Text as large as fits its box, between min and max px.
<FitText max={260}>42%</FitText>| Prop | Type | Default | |
|---|---|---|---|
max |
number |
400 |
|
min |
number |
12 |
|
className |
string |
A bordered frame around media.
<Frame></Frame>| Prop | Type | Default | |
|---|---|---|---|
className |
string |
A CSS grid of its children.
<Grid cols={3} gap="1rem"><Glass>One</Glass><Glass>Two</Glass><Glass>Three</Glass></Grid>| Prop | Type | Default | |
|---|---|---|---|
cols |
string | number |
3 |
Column count or a template. |
rows |
string | number |
Row count or a template. | |
gap |
string |
"1.5rem" |
CSS gap. |
className |
string |
Spacer
Section titled “Spacer”Vertical space.
<Spacer size="3rem" />| Prop | Type | Default | |
|---|---|---|---|
size |
string |
"1rem" |
CSS length. |
Children on top of each other in one spot — combine with clicks to swap images in place.
<Stack><Click at={[1, 2]}></Click><Click at={2}></Click></Stack>| Prop | Type | Default | |
|---|---|---|---|
className |
string |
Stretch
Section titled “Stretch”Grows to fill the slide’s remaining height (an image under a heading).
## The whole map
<Stretch></Stretch>| Prop | Type | Default | |
|---|---|---|---|
className |
string |
Transform
Section titled “Transform”Scales a block around an origin.
<Transform scale={0.8}>
A table that is a little too big
</Transform>| Prop | Type | Default | |
|---|---|---|---|
scale |
number |
1 |
|
origin |
string |
"top left" |
|
className |
string |
Clicks and steps
Section titled “Clicks and steps”Steps within a slide. See Clicks and animation.
After · Case · Click · ClickCount · Clicks · Fragment · Stepper · Switch
Shows together with the previous click instead of taking a step of its own.
<Click>The claim</Click><After>…and its footnote, at the same moment</After>| Prop | Type | Default | |
|---|---|---|---|
hide |
boolean |
Start visible and hide at the step instead. | |
effect |
ClickEffect |
"fade-in" |
A reveal effect (see clickEffects) or any CSS class the theme defines. |
as |
ElementType |
The element to render; a span for inline text, div by default. |
|
className |
string |
Extra classes. | |
style |
CSSProperties |
Inline style (JSX object). | |
children |
ReactNode |
What is revealed. |
One case of a <Switch>. Without at it is one step after the case before; at={0} is what the slide starts with; the last case stays unless it has a range.
<Switch><Case at={0}>Before</Case><Case>After one click</Case></Switch>| Prop | Type | Default | |
|---|---|---|---|
at |
string | number | [number, number] |
When, in the switch’s own steps: n, “a-b”, or [a, b]. Default: one after the case before. | |
as |
ElementType |
This case’s element. | |
className |
string |
Extra classes. |
One click step: shows its children from its step on, or hides them with hide.
<Click>Appears on the first click</Click><Click at="+2" effect="fade-up">Two clicks later, sliding up</Click>| Prop | Type | Default | |
|---|---|---|---|
at |
ClickAt |
When: omitted = one after the previous step; “+N” relative (“+0” shares the previous step); a number is absolute (0 = always shown); [from, to] shows it from from until to. |
|
hide |
boolean |
Start visible and hide at the step instead. | |
effect |
ClickEffect |
"fade-in" |
A reveal effect (see clickEffects) or any CSS class the theme defines. |
as |
ElementType |
The element to render; a span for inline text, div by default. |
|
className |
string |
Extra classes. | |
style |
CSSProperties |
Inline style (JSX object). | |
children |
ReactNode |
What is revealed. |
ClickCount
Section titled “ClickCount”The click step this slide is at, or with total how many it has; with a function child, anything that depends on the count. Never adds a click step itself. Hook: useClicks().
Step <ClickCount offset={1} /> of <ClickCount total />
<ClickCount when={(c) => c >= 3}>
**Done.**
</ClickCount>| Prop | Type | Default | |
|---|---|---|---|
total |
boolean |
false |
Show the slide’s number of clicks rather than the current one. |
offset |
number |
0 |
Add this to the number shown: offset={1} counts from 1 (“step 1” before any click). |
className |
string |
||
when |
((click: number, total: number) => unknown) |
Render the children only while this is true of the count: when={(c) => c >= 2}. |
|
children |
ReactNode | ((click: number, total: number) => ReactNode) |
With when: what to show. Otherwise a function of the count, for anything that depends on it: {(c, total) => …}. Without either, the number is shown in a <span>. |
Clicks
Section titled “Clicks”Wraps a Markdown list (or any children) so each item is its own click step. Leave blank lines around the list inside it.
<Clicks>
- First point- Second point- Third point
</Clicks>| Prop | Type | Default | |
|---|---|---|---|
every |
number |
1 |
Reveal this many items per click. |
depth |
number |
1 |
How deep nested lists take part; 1 means only the outer list. |
effect |
ClickEffect |
"fade-in" |
The reveal effect for every item. |
children |
ReactNode |
A list, or blocks. |
Fragment
Section titled “Fragment”Another name for <Click>; identical.
<Fragment effect="highlight-red">Same as Click</Fragment>| Prop | Type | Default | |
|---|---|---|---|
at |
ClickAt |
||
hide |
boolean |
||
effect |
ClickEffect |
||
as |
ElementType |
The element to render; a span for inline text, div by default. |
|
className |
string |
||
style |
CSSProperties |
Stepper
Section titled “Stepper”Where the talk (or this slide) is, as fixed furniture: equal cells, so the current step never nudges the others. place="top" or "bottom" puts it on the slide’s rail, outside the layout, so it sits pixel-identical on every slide; follow walks it with this slide’s clicks.
<Stepper steps={["Build", "Rehearse", "Present", "Own the room"]} current={2} place="top" />
<Stepper steps={["Ask", "Measure", "Change"]} follow at={1} /><Switch at={1}><Case at={0}>Ask what the room needs</Case><Case>Measure it out loud</Case><Case>Change what ran long</Case></Switch>| Prop | Type | Default | |
|---|---|---|---|
steps required |
ReactNode[] |
The steps’ labels, in order. | |
current |
number |
The current step, 1-based; 0 for none yet. Ignored with follow. |
|
follow |
boolean |
Advance with this slide’s clicks (one step per click) instead of current. |
|
at |
ClickAt |
With follow: when the second step arrives, as <Click at>. Default one after the previous click. |
|
place |
"top" | "bottom" |
“top” or “bottom”: on the slide’s rail, the same place on every slide. Default: inline. | |
variant |
"chips" | "bar" | "dots" |
chips (default), bar, dots. | |
numbered |
boolean |
Number the steps (chips only). Default true. | |
className |
string |
||
label |
string |
What a screen reader calls it. Default “Progress”. |
Switch
Section titled “Switch”One child at a time, switched by clicks: each <Case> takes the next step, or at={n} / at="a-b" in the switch’s own steps; the cases share one spot, so nothing below jumps.
<Switch transition="slide-up"><Case>First</Case><Case>Then</Case><Case at="4-6">Steps 4 and 5</Case></Switch>| Prop | Type | Default | |
|---|---|---|---|
at |
ClickAt |
When the switch’s first step is: as <Click at>. Default one after the previous click. |
|
transition |
(string & {}) | "fade" | "slide-up" | "slide-left" | "scale" | "none" |
"fade" |
“fade” (default), “slide-up”, “slide-left”, “scale”, or “none”. |
unmount |
boolean |
false |
Leave hidden cases out of the page rather than hidden in it. |
as |
ElementType |
The switch’s element; div by default. |
|
childAs |
ElementType |
Each case’s element (childTag); div by default. |
|
className |
string |
||
children |
ReactNode |
<Case>s — or any elements, each one step. |
Content
Section titled “Content”Text, notes, links and small pieces of a slide.
Arrow · Badge · Callout · Confetti · Counter · Encrypted · FlipBoard · Kbd · LightOrDark · Link · Mark · Math · Notes · Qr · RenderWhen · SlideCurrentNo · SlidesTotal · Tex · Timer · TitleRenderer · Toc · Typewriter
A straight arrow between two points in stage coordinates.
<Arrow x1={300} y1={700} x2={900} y2={420} color="var(--deck-accent)" />| Prop | Type | Default | |
|---|---|---|---|
x1 required |
number |
||
y1 required |
number |
||
x2 required |
number |
||
y2 required |
number |
||
width |
number |
2 |
Stroke width. |
color |
string |
"currentColor" |
CSS colour. |
twoWay |
boolean |
false |
Heads at both ends. |
className |
string |
A small inline label.
<Badge tone="good">new</Badge>| Prop | Type | Default | |
|---|---|---|---|
tone |
"neutral" | "accent" | "good" | "warn" | "bad" |
"neutral" |
neutral · accent · good · warn · bad. |
className |
string |
Callout
Section titled “Callout”A boxed aside: info, tip, note, warn or danger, with an optional title.
<Callout kind="tip" title="Rule of thumb">
One idea per slide.
</Callout>| Prop | Type | Default | |
|---|---|---|---|
kind |
"warn" | "info" | "tip" | "danger" | "note" |
"info" |
info · tip · note · warn · danger. |
title |
ReactNode |
A string, or any content (Comark’s #title slot arrives as content). |
|
className |
string |
Confetti
Section titled “Confetti”A burst of confetti when the slide (or the given click) arrives.
<Confetti at={1} />| Prop | Type | Default | |
|---|---|---|---|
at |
string | number |
Click step. | |
count |
number |
140 |
Pieces. |
duration |
number |
2200 |
Milliseconds. |
Counter
Section titled “Counter”A number that counts up when its slide is shown.
<Counter value={12500} prefix="₹" suffix="/mo" />| Prop | Type | Default | |
|---|---|---|---|
value required |
number |
Target number. | |
from |
number |
0 |
Start. |
duration |
number |
1500 |
Milliseconds. |
decimals |
number |
0 |
Decimal places. |
prefix |
string |
"" |
Text before. |
suffix |
string |
"" |
Text after. |
className |
string |
Encrypted
Section titled “Encrypted”Text that resolves out of random glyphs.
<Encrypted text="Decoded." />| Prop | Type | Default | |
|---|---|---|---|
text required |
string |
The text. | |
speed |
number |
30 |
Milliseconds per glyph. |
delay |
number |
0 |
Milliseconds before it starts. |
className |
string |
A split-flap board whose cells flip to its text: one cell per character, a row per line.
<FlipBoard text={"HIGH WATER\n06:12"} />| Prop | Type | Default | |
|---|---|---|---|
text required |
string |
The text; \n starts a new row. |
|
rows |
number |
Rows (default: the text’s lines). | |
cols |
number |
Columns (default: the longest line). | |
className |
string |
Class on the board. | |
flipDuration |
number |
35 |
Milliseconds per flip. |
stagger |
number |
15 |
Milliseconds between neighbouring cells. |
A keyboard key.
Press <Kbd>?</Kbd> for helpLightOrDark
Section titled “LightOrDark”One thing in the light colour scheme, another in the dark (the slide’s own scheme when its frontmatter forces one): light/dark props, children marked slot="light"/slot="dark", or a function of the scheme.
<LightOrDark> <div slot="dark"></div> <div slot="light"></div></LightOrDark>| Prop | Type | Default | |
|---|---|---|---|
light |
ReactNode |
Shown in the light scheme. | |
dark |
ReactNode |
Shown in the dark scheme. | |
children |
ReactNode | ((props: { scheme: Scheme; } & Record<string, unknown>) => ReactNode) |
Either children marked slot="light" / slot="dark" (any element: <div slot="dark">…</div>), or a function of the scheme and the other props: {({ scheme }) => …}. |
A link to another slide by 1-based number, h.v, or slide id.
<Link to="results">See the results</Link>| Prop | Type | Default | |
|---|---|---|---|
to required |
string | number |
Slide number (1-based), “h.v”, or a slide id. |
|
title |
string |
Tooltip. | |
className |
string |
A hand-drawn mark: underline, box, circle, highlight, strike-through, crossed-off or bracket, drawn stroke by stroke on its click. The wobble is seeded from the text, so it looks the same on every screen and in the PDF.
The answer is <Mark type="circle">forty-two</Mark>.
<Mark type="bracket" brackets="left right" color="#e11d48" at={2}>Both sides</Mark>| Prop | Type | Default | |
|---|---|---|---|
type |
"strike" | MarkType | "line-through" | "linethrough" | "cross" | "crossed" |
"underline" |
underline · box · circle · highlight · strike-through · crossed-off · bracket (the aliases strike, line-through, cross, crossed work too). |
color |
string |
"var(--deck-accent)" |
Any CSS colour; default the theme’s accent. |
at |
ClickAt |
When: as <Click at> (default: the next click; 0 = always; [a, b] from a until b). |
|
strokeWidth |
number |
Line width in px (default 3; a highlight is as tall as the line). | |
padding |
string | number | number[] |
Space around the text in px: one number, or “top right bottom left” like CSS. Default 5. | |
iterations |
number |
2 |
Strokes per line, each a little different (default 2). |
multiline |
boolean |
One mark per line of wrapped text. Default: on for underline, highlight, strike-through, crossed-off. | |
brackets |
string | string[] |
"right" |
For a bracket: which sides — “left”, “right”, “top”, “bottom”, or several. Default “right”. |
duration |
number |
How long the stroke takes to draw, ms (default 800). | |
animationDuration |
number |
Another name for duration. |
|
delay |
number |
0 |
Wait this long after the click before drawing, ms. |
animate |
boolean |
true |
Turn the drawing animation off: the mark appears whole. |
opacity |
number |
0–1. Default 1 (a highlight: 0.35, so the text shows through). | |
className |
string |
Another name for <Tex>.
<Math tex="\int_0^1 x\,dx" block />| Prop | Type | Default | |
|---|---|---|---|
tex |
string |
||
block |
boolean |
false |
Speaker notes. Lifted out at compile time and shown in the presenter view; [click] markers line them up with clicks. HTML comments at the very end of a slide are its notes, and both kinds join.
<Notes>Open with the question. [click] Then reveal the number.</Notes>A QR code for any text or URL, rendered locally.
<Qr value="https://deck.kadal.cc" size={280} />| Prop | Type | Default | |
|---|---|---|---|
value required |
string |
Text or URL to encode. | |
size |
number |
240 |
Pixels. |
className |
string |
RenderWhen
Section titled “RenderWhen”Renders its children only in some places: main (the deck and the presenter’s current slide), slide, presenter, previewNext, overview, print/export, audience, visible; fallback everywhere else.
<RenderWhen context="presenter">Only the speaker sees this.</RenderWhen>
<RenderWhen context={["print", "overview"]} fallback={<Iframe src="https://example.com" />}></RenderWhen>| Prop | Type | Default | |
|---|---|---|---|
context required |
string | RenderWhenContext[] |
Where to render: main (the deck and the presenter’s current slide — and the audience’s phone), slide, presenter, previewNext (the presenter’s next box), overview, print (also export), audience, visible (on screen right now). Several — an array or “presenter overview” — render in any of them; visible combined with others must also hold. |
|
fallback |
ReactNode |
null |
Rendered where the context does not match. |
SlideCurrentNo
Section titled “SlideCurrentNo”This slide’s number (in a global layer: the current slide’s).
Slide <SlideCurrentNo /> of <SlidesTotal />| Prop | Type | Default | |
|---|---|---|---|
format |
"c" | "c/t" | "h.v" | "h/v" |
"c" |
“c” the flat number (default), “h.v” or “h/v” with vertical slides, “c/t” with the total. |
className |
string |
SlidesTotal
Section titled “SlidesTotal”How many slides the deck has (hidden ones left out).
<SlidesTotal /> slides| Prop | Type | Default | |
|---|---|---|---|
className |
string |
KaTeX maths from JSX. In Markdown prefer $inline$ and $$display$$, which render at build time.
<Tex tex="E = mc^2" block />| Prop | Type | Default | |
|---|---|---|---|
tex |
string |
LaTeX source. | |
block |
boolean |
false |
Display (centred, own line) instead of inline. |
A countdown (with seconds) or a stopwatch that starts when its slide is shown.
<Timer seconds={120} />| Prop | Type | Default | |
|---|---|---|---|
seconds |
number |
Count down from this; omit for a stopwatch. | |
className |
string |
TitleRenderer
Section titled “TitleRenderer”Another slide’s title, by its number or id (no prop: this slide’s own).
Next up: <TitleRenderer no={3} />| Prop | Type | Default | |
|---|---|---|---|
no |
string | number |
Slide number, 1-based. | |
id |
string |
Or the slide’s id. | |
fallback |
ReactNode |
Shown when that slide has no title (or there is no such slide). | |
as |
"div" | "h1" | "h2" | "h3" | "span" | "strong" |
"span" |
The element: span (default), h1–h3, strong, div. |
className |
string |
A table of contents from every slide’s title and heading level (hideInToc slides skipped).
## Agenda
<Toc maxDepth={1} />| Prop | Type | Default | |
|---|---|---|---|
columns |
number |
1 |
Number of columns. |
maxDepth |
number |
Number.POSITIVE_INFINITY |
Deepest heading level listed. |
minDepth |
number |
1 |
Shallowest heading level listed. |
mode |
"all" | "onlyCurrentTree" | "onlySiblings" |
"all" |
all · onlyCurrentTree · onlySiblings. |
listClass |
string |
Class on the list. |
Typewriter
Section titled “Typewriter”Text that types itself out when the slide is shown.
<Typewriter text="npm create @kadal/deck@latest" />| Prop | Type | Default | |
|---|---|---|---|
text required |
string |
The text. | |
speed |
number |
35 |
Milliseconds per character. |
className |
string |
||
cursor |
boolean |
true |
Show a cursor. |
Pictures, sound, video and embedded pages.
Audio · BlueSky · Credits · Emoji · Gif · Iframe · Image · Meme · Sticker · Tweet · Video · Youtube
An audio player.
<Audio src="/clip.mp3" />| Prop | Type | Default | |
|---|---|---|---|
src required |
string |
Audio URL. | |
autoplay |
boolean |
Play on arrival. | |
loop |
boolean |
Loop. | |
controls |
boolean |
true |
Show controls. |
className |
string |
BlueSky
Section titled “BlueSky”A Bluesky post, through Bluesky’s embed, in the slide’s colour scheme; deck export captures a poster for each scheme.
<BlueSky uri="https://bsky.app/profile/bsky.app/post/3myi2ihquwk26" />| Prop | Type | Default | |
|---|---|---|---|
uri required |
string |
The post: its bsky.app address or its AT-URI. | |
scale |
string | number |
1 |
Scale factor. |
poster |
string |
Stands in for the post in print, the overview and while it loads. | |
className |
string |
Credits
Section titled “Credits”The deck’s media credits: every attributed GIF, sticker, meme template, emoji set, icon set and <Image credit> the slides use, collected when the deck compiles and grouped by source, each with its licence and a link. credits: true in the headmatter adds a slide with it before the last slide and a corner link to it on every other slide, so it is rarely written by hand; a slide that has one is used instead.
---id: credits---
<Credits title="Thanks to" />| Prop | Type | Default | |
|---|---|---|---|
title |
string | false |
The heading (default: the headmatter’s credits.title, else “Credits”); false for none. |
|
lede |
string | false |
One line under the heading; false for none. |
|
className |
string |
Extra classes. |
One emoji as an image from an open set (Fluent 3D/Color/Flat, Noto, Noto Animated, Twemoji), served by the host (https://decks.kadal.cc/emoji by default). char is exact; name is looked up in the host’s index. Animated Noto shows a still under reduced motion and in print.
<Emoji name="party-popper" /> <Emoji char="👍🏽" set="twemoji" size={96} />| Prop | Type | Default | |
|---|---|---|---|
name |
string |
Its name in the host’s index (“party-popper”); char wins when both are given. |
|
char |
string |
The emoji itself (“🎉”, “👍🏽”): exact, no lookup. Children work too: |
|
set |
"fluent-3d" | "fluent-color" | "fluent-flat" | "noto" | "noto-animated" | "twemoji" |
fluent-3d (default), fluent-color, fluent-flat, noto, noto-animated, twemoji. | |
size |
string | number |
"1.2em" |
CSS size (a number is px). Default 1.2em: it sits in a line of text. |
alt |
string |
Alternative text (default: the name). | |
className |
string |
A GIF from a provider (KLIPY), hot-linked exactly as the provider returned it, with a small credit on hover. Print and every export (PDF, PNG, PPTX) show a card with its title and a link instead of the media — the providers’ terms don’t allow copying it.
<Gif provider="klipy" slug="hello-hi-662" src="https://static.klipy.com/ii/…/hello.gif" title="Hello" width={498} height={498} />| Prop | Type | Default | |
|---|---|---|---|
provider |
string |
"klipy" |
Who it came from: “klipy” (default), “kadal” (Kadal’s own library), “giphy”. |
id |
string |
The provider’s id. | |
slug |
string |
The provider’s slug (builds the link back). | |
src required |
string |
The media URL exactly as the provider returned it (GIF, WebP, or MP4/WebM). | |
title |
string |
Title: the alt text, the credit and the export card. | |
creator |
string |
Who made it, for the credit. | |
width |
number |
Width in px (with height: the aspect ratio). | |
height |
number |
Height in px. | |
still |
string |
A still frame from the provider, shown under reduced motion. | |
href |
string |
The page to link to in the credit and the export card (default: the provider’s page for it). | |
alt |
string |
||
className |
string |
Iframe
Section titled “Iframe”An embedded page, loaded only while its slide is near, behind a click-to-interact shield; a poster stands in for print and previews.
<Iframe src="https://example.com" poster="/posters/example.jpg" scale={0.5} />| Prop | Type | Default | |
|---|---|---|---|
src required |
string |
Page URL. | |
preload |
boolean |
Load it before its slide is near. | |
className |
string |
||
title |
string |
Accessible title. | |
poster |
string |
Stands in for the page in print, the overview and the next-slide box, and while it loads. | |
posterSize |
readonly [number, number] |
||
scale |
number |
Render the page larger and shrink it: 0.5 gives a small pane the desktop layout. |
The img mapping (every ), lazy-loaded; also usable as a tag. preview opens a lightbox on click.

<Image src="/chart.png" alt="Revenue by month" preview fit="contain" />| Prop | Type | Default | |
|---|---|---|---|
src |
string |
Image URL; /x.png is served from the deck’s public/ folder. |
|
alt |
string |
"" |
Alternative text (always write one). |
preview |
string | boolean |
true, or a larger image’s URL, to open a lightbox on click. | |
fit |
string |
CSS object-fit (cover, contain…). | |
className |
string |
||
credit |
string |
Who to thank (““Harbour at dawn” by Ana Ruiz”): listed by <Credits />, the title on hover. |
|
creditUrl |
string |
The work’s page, for the credit’s link. | |
license |
string |
Its licence (“CC BY 2.0”), for the credits. | |
licenseUrl |
string |
The licence’s text. |
Image-macro captions over a picture: white Anton with a black outline by default, as real text. template records where the picture came from (Imgflip) and shows the link back on hover and in every export.
<Meme src="https://i.imgflip.com/30b1gx.jpg" template={{ provider: "imgflip", id: "181913649", url: "https://imgflip.com/memetemplate/181913649" }} captions={[{ text: "Writing slides by hand", x: 52, y: 6, width: 45 }, { text: "Kadal Deck", x: 52, y: 56, width: 45 }]} />| Prop | Type | Default | |
|---|---|---|---|
src required |
string |
The image. | |
provider |
string |
“kadal” for a template from Kadal’s own library (the same as template={{ provider: "kadal" }}). |
|
alt |
string |
Alternative text (default: the captions). | |
template |
MemeTemplate |
{ provider: “imgflip” | “kadal”, id, url, name } — the source, credited with a link. | |
captions |
MemeCaption[] |
[{ text, x, y, width, size, align, color, stroke }]: x/y/width in % of the image (defaults 5, 4, 90), size in % of its width (default 9), align left|center|right, colours CSS (default white on black). | |
width |
string | number |
CSS width (a number is px). Default: as wide as the image, up to its box. | |
className |
string |
Sticker
Section titled “Sticker”An image placed over the slide in stage pixels — a PNG cut-out, an animated GIF/WebP/APNG. Centred unless x/y say otherwise; in kadal-deck dev double-click it to move, resize or turn it and the position is written back as pos.
<Sticker src="/stickers/rocket.webp" x={1480} y={140} size={260} rotate={-8} shadow />| Prop | Type | Default | |
|---|---|---|---|
src required |
string |
Image URL (public/ path or https). | |
alt |
string |
"" |
Alternative text (empty: decorative). |
size |
number |
Width in stage pixels (default 240); the height follows the image. | |
x |
number |
Left edge in stage pixels (default: centred). | |
y |
number |
Top edge in stage pixels (default: centred). | |
rotate |
number |
Degrees, clockwise. | |
flip |
boolean | "x" | "y" |
Mirror it: true or “x” left↔right, “y” upside down. | |
shadow |
boolean |
A soft drop shadow that follows the image’s outline. | |
pos |
string |
“x,y,w,h[,r]” — what dragging it in kadal-deck dev writes; wins over x/y/size/rotate. |
|
provider |
string |
Where it came from: “kadal” for Kadal’s own library (credited “Kadal”). | |
id |
string |
The provider’s id for it (“kadal/ship-it”). Without a provider, id is the element’s id. |
|
still |
string |
A still frame of an animated sticker: shown under reduced motion and in print. | |
credit |
string |
A credit of its own (“Photo by Ana Ruiz”), on hover and in the deck’s credits. | |
creditUrl |
string |
The credit’s link (the work’s page). | |
license |
string |
Its licence (“CC BY 4.0”), for the credits. | |
licenseUrl |
string |
The licence’s text. | |
className |
string |
||
style |
CSSProperties |
An embedded post from X/Twitter.
<Tweet id="20" />| Prop | Type | Default | |
|---|---|---|---|
id |
string | number |
Post id. | |
url |
string |
Or the post URL. | |
scale |
number |
1 |
Scale factor. |
poster |
string |
Stands in for the post in print, the overview and while it loads. |
A video that knows the slide’s clicks: plays on arrival, at a click (at), pauses at one (pauseAt), jumps or rewinds at others (steps), or when the enclosing
<Video src="/demo.mp4" at={1} pauseAt={3} steps={{ 2: 42 }} timestamp={5} autoreset="slide" />| Prop | Type | Default | |
|---|---|---|---|
src |
string |
Video URL (public/ path or https), or <source> children. |
|
autoplay |
boolean | "once" |
Play when the slide (or at, or the enclosing <Click>) arrives; “once”: only the first time. |
|
at |
ClickAt |
The click at which it starts playing (as <Click at>); implies autoplay. |
|
pauseAt |
ClickAt |
The click at which it pauses. | |
steps |
Record<string | number, VideoStep> |
What happens at further clicks: { 3: "pause", 4: "play", 6: 12.5, 8: "rewind" } (absolute clicks). |
|
autoreset |
"slide" | "click" |
“slide”: back to timestamp whenever the slide is left; “click”: whenever the deck steps back before at. |
|
timestamp |
string | number |
Start here, in seconds. | |
loop |
boolean |
Loop. | |
muted |
boolean |
true |
Muted (default true). |
controls |
boolean |
false |
Show controls. |
poster |
string |
Poster image. | |
printPoster |
string |
The poster in print, the overview and the next-slide box (default poster). |
|
printTimestamp |
string | number |
The frame shown in print and previews: seconds, or “last”. Default timestamp. |
|
className |
string |
||
children |
ReactNode |
<source> elements, captions (<track>), fallback text. |
Youtube
Section titled “Youtube”A YouTube embed by id or URL.
<Youtube id="dQw4w9WgXcQ" start={42} />| Prop | Type | Default | |
|---|---|---|---|
id |
string |
Video id. | |
url |
string |
Or the full URL. | |
autoplay |
boolean |
Play on arrival. | |
start |
number |
Start at second. | |
className |
string |
||
poster |
string |
Stands in for the player in print, the overview and while it loads. |
Highlighted code. You write fences; these are what they compile to. See Code.
The pre mapping behind fenced code blocks: Shiki highlighting, line-highlight steps, titles. Write a fence, not this tag.
```ts {1|2-3|all} [app.ts]const a = 1;const b = 2;export { a, b };```| Prop | Type | Default | |
|---|---|---|---|
className |
string |
||
data-steps |
string |
||
data-lines |
string |
||
data-start |
string |
||
data-title |
string |
||
data-max-height |
string |
||
data-hide-until-step |
string |
||
data-lang |
string |
||
data-total |
string |
||
data-monaco |
string |
editor, diff, run or write: the block is a Monaco editor (see MonacoCode). |
|
data-code |
string |
The block’s source for the editor (the modified side of a diff). | |
data-original |
string |
The original side of a {monaco-diff}. |
|
data-monaco-options |
string |
The editor’s and runner’s options, as JSON. | |
data-snippet |
string |
Where a <<< import read the code from: path#region. |
|
data-twoslash |
string |
CodeGroup
Section titled “CodeGroup”Code blocks as tabs, each named by its fence’s [title] with a file-type badge. Usually written as ::code-group … :: around the fences (::: works too); ←/→ move between tabs. clicks turns tabs on each click; print="all" prints every tab.
::code-group
```sh [npm]npm i @kadal/deck```
```sh [bun]bun add @kadal/deck```
::| Prop | Type | Default | |
|---|---|---|---|
children |
ReactNode |
The fenced code blocks, one per tab (blank lines around them inside the tag). | |
clicks |
boolean |
Open the next tab on each click of the slide, from the group’s own step on. | |
at |
string | number |
With clicks: when the first turn happens, like <Click at> ("+1", an absolute step). |
|
active |
number |
0 |
The tab open at first (0-based). Default 0. |
print |
"active" | "all" |
What print and export show: the open tab (default) or every tab. | |
className |
string |
Extra classes. |
MagicMove
Section titled “MagicMove”Shiki Magic Move: code that morphs between versions, one per click. Written as a ````md magic-move fence holding one code fence per step; an inner fence’s highlight steps ({*|2|4-5}) are clicks too, in order with the morphs. Outer options: at, lines, duration; [file.ts] adds a title bar. Follows the colour scheme and the theme menu.
````md magic-move```tslet n = 1``````tsconst n = 1```````| Prop | Type | Default | |
|---|---|---|---|
block required |
number |
Maths and diagrams
Section titled “Maths and diagrams”See Maths, diagrams and sketches.
KatexLines · Mermaid · Sketch
KatexLines
Section titled “KatexLines”Display maths whose lines light up one step per click: what $$ {1|3|all} compiles to. Write the $$ block, not this tag.
$$ {1|2|all}\begin{aligned}a &= b + c \\d &= e\end{aligned}$$| Prop | Type | Default | |
|---|---|---|---|
steps |
string |
"" |
1|3|all: one set of lines per step. |
at |
string | number |
The click the steps start at (a number, or +n). |
|
finally |
string |
Lines shown once the slide’s clicks pass the last step (default: the last step). | |
startLine |
number |
1 |
The number of the first line (default 1). |
children |
ReactNode |
The rendered formula. |
Mermaid
Section titled “Mermaid”A Mermaid diagram rendered in the browser in the deck’s colours. Pass the source as a template string.
<Mermaid>{`flowchart LR A[Write] --> B[Check] --> C[Present]`}</Mermaid>| Prop | Type | Default | |
|---|---|---|---|
children |
ReactNode |
Mermaid source as a JSX template string. | |
code |
string |
The diagram’s source, when it is not the children. | |
scale |
number |
1 |
Scale factor. |
theme |
string |
A Mermaid theme for this diagram: default, neutral, dark, forest, base. | |
config |
Record<string, unknown> |
Mermaid configuration for this diagram (themeVariables, look, flowchart…). | |
className |
string |
||
alt |
string |
What the diagram shows, for screen readers (a fence’s alt); default its first line. |
Sketch
Section titled “Sketch”An Excalidraw drawing in the deck’s colours: from the sketch DSL (scene), an .excalidraw file (src), or Mermaid (children); steps tours its regions one click at a time.
<Sketch>{`flowchart LR; idea --> slide --> talk`}</Sketch>
<Sketch src="/diagrams/flow.excalidraw" height="600px" />| Prop | Type | Default | |
|---|---|---|---|
scene |
SketchScene |
A scene built with sketch() from @kadal/deck/sketch (import it in src/components.tsx or the slide). |
|
src |
string | ExcalidrawFile |
Path to an .excalidraw file in public/. | |
mermaid |
string |
Mermaid source to convert. | |
steps |
SketchStep[] |
[] |
Regions to light up, one per click, after the whole diagram has shown. |
caption |
ReactNode |
Shown under the diagram when no step’s caption is. | |
width |
string |
CSS size limits for the drawing. | |
height |
string |
CSS max height. | |
fontSize |
number |
Font size for Mermaid conversions. | |
zoomable |
boolean |
true |
Show the button that opens it in Excalidraw’s viewer. |
className |
string |
Motion
Section titled “Motion”Animation keyed to a slide’s clicks.
Motion
Section titled “Motion”Animates a block with motion (framer-motion): initial → enter on arrival, leave on exit, and per-click targets.
<Motion initial={{ opacity: 0, x: -80 }} enter={{ opacity: 1, x: 0 }} clicks={{ "click-1": { scale: 1.2 } }}>
Slides in from the left
</Motion>| Prop | Type | Default | |
|---|---|---|---|
initial |
TargetAndTransition |
{ opacity: 0, y: 24 } |
Motion target before arrival. |
enter |
TargetAndTransition |
{ opacity: 1, y: 0 } |
Motion target on arrival. |
leave |
TargetAndTransition |
Motion target on exit. | |
clicks |
Record<string, TargetAndTransition> |
{} |
Apply from a click on: { "click-1": { x: 40 }, "click-2": { y: 60 } }. |
at |
string | number |
Tie the whole thing to a click step (like v-click + v-motion). |
|
transition |
Transition<any> |
motion transition options. | |
className |
string |
||
style |
CSSProperties |
||
as |
"div" | "h1" | "h2" | "h3" | "img" | "li" | "p" | "span" |
"div" |
Element to render. |
Decoration
Section titled “Decoration”Cards, glows and text effects. They read the theme’s tokens and take a tone.
Blob · Chip · Divider · Glass · Glow · GradientText · Halo · Icon · Ribbon · Shimmer · Tilt
A soft organic colour blob for decoration.
<Blob color="var(--deck-accent-2)" x="80%" y="20%" />| Prop | Type | Default | |
|---|---|---|---|
color |
string |
CSS colour. | |
x |
string |
"50%" |
CSS left. |
y |
string |
"50%" |
CSS top. |
size |
string |
"40%" |
CSS size. |
rotate |
number |
0 |
Degrees. |
opacity |
number |
0.5 |
0–1. |
className |
string |
A pill with an optional lucide icon.
<Chip tone="good" icon="check">Shipped</Chip>| Prop | Type | Default | |
|---|---|---|---|
tone |
Tone |
"neutral" |
One of: accent, accent-2, good, warn, bad, info, neutral, purple, pink, amber, teal. |
icon |
string |
A lucide icon name (kebab-case). | |
className |
string |
Divider
Section titled “Divider”A horizontal rule with an optional centred label.
<Divider label="Part two" />| Prop | Type | Default | |
|---|---|---|---|
label |
ReactNode |
||
className |
string |
A frosted card. Cards that share a row share a height.
<Glass tone="accent" glow>
**42 ms** p95
</Glass>| Prop | Type | Default | |
|---|---|---|---|
className |
string |
||
tone |
Tone |
"neutral" |
One of: accent, accent-2, good, warn, bad, info, neutral, purple, pink, amber, teal. |
pad |
string |
"1em" |
CSS padding. |
glow |
boolean |
false |
Coloured glow. |
style |
CSSProperties |
A soft blurred light behind the content.
<Glow color="var(--deck-accent)" x="70%" y="30%" />| Prop | Type | Default | |
|---|---|---|---|
color |
string |
CSS colour. | |
size |
string |
"60%" |
CSS size. |
x |
string |
"50%" |
CSS left. |
y |
string |
"50%" |
CSS top. |
opacity |
number |
0.35 |
0–1. |
className |
string |
GradientText
Section titled “GradientText”Text filled with a gradient (theme accents by default).
# <GradientText>Ship it.</GradientText>| Prop | Type | Default | |
|---|---|---|---|
from |
string |
Start colour. | |
to |
string |
End colour. | |
angle |
number |
90 |
Degrees. |
className |
string |
||
as |
"h1" | "h2" | "h3" | "span" | "strong" |
"span" |
Element. |
A ring of light around an icon or emoji.
<Halo tone="accent"><Icon name="sparkles" /></Halo>| Prop | Type | Default | |
|---|---|---|---|
tone |
Tone |
"accent" |
One of: accent, accent-2, good, warn, bad, info, neutral, purple, pink, amber, teal. |
size |
string |
"3.2em" |
CSS size. |
className |
string |
A Lucide icon by name, or any Iconify icon as set:name (mdi:account, logos:vue). The tag form <mdi-account /> compiles to this. Built decks bundle the drawings from the deck’s installed @iconify-json/<set> (or @iconify/json); the hosted shell, or a set not installed, fetches them from the Iconify API once and keeps them.
<Icon name="rocket" size="2em" /> <Icon name="mdi:account-circle" color="tomato" /> <logos-react class="text-3xl" />| Prop | Type | Default | |
|---|---|---|---|
name required |
string |
A Lucide name (rocket), or any Iconify icon as set:name (mdi:account, logos:vue). |
|
size |
string | number |
"1em" |
Height: CSS size or px (the width follows the icon’s proportions). Tag form: 1.2em. |
color |
string |
CSS colour (monochrome icons). | |
strokeWidth |
number |
1.75 |
Lucide icons only. |
className |
string |
||
class |
string |
Another spelling of className. |
|
style |
string | CSSProperties |
An object, or a CSS string (style="color: tomato"). |
|
title |
string |
An accessible name; without one the icon is decorative. |
Ribbon
Section titled “Ribbon”A corner ribbon on the slide.
<Ribbon tone="warn">Beta</Ribbon>| Prop | Type | Default | |
|---|---|---|---|
tone |
Tone |
"accent" |
One of: accent, accent-2, good, warn, bad, info, neutral, purple, pink, amber, teal. |
corner |
"left" | "right" |
"right" |
left · right. |
Shimmer
Section titled “Shimmer”Text with a light sweeping across it.
## <Shimmer>Now live</Shimmer>| Prop | Type | Default | |
|---|---|---|---|
className |
string |
||
as |
"h1" | "h2" | "span" | "strong" |
"span" |
A card that tilts toward the pointer.
<Tilt><Glass>Hover me</Glass></Tilt>| Prop | Type | Default | |
|---|---|---|---|
className |
string |
||
max |
number |
8 |
Maximum tilt in degrees. |
Backgrounds
Section titled “Backgrounds”Background
Section titled “Background”A registered component background (by name) or custom children as an animated layer behind this slide’s content. Usually you set background: in frontmatter instead.
<Background name="aurora" opacity={0.6} />| Prop | Type | Default | |
|---|---|---|---|
name |
string |
A registered background name (see backgrounds). | |
opacity |
number |
1 |
0–1. |
className |
string |
Live room
Section titled “Live room”Components that talk to the deck’s room. See The live room.
Leaderboard · Pace · Poll · Presence · QrJoin · Questions · Quiz · Reactions · WordCloud
Leaderboard
Section titled “Leaderboard”The quiz leaderboard.
<Leaderboard top={5} />| Prop | Type | Default | |
|---|---|---|---|
top |
number |
8 |
How many places. |
className |
string |
A gauge of the audience’s slower/faster feedback.
<Pace />| Prop | Type | Default | |
|---|---|---|---|
className |
string |
A poll the presenter opens; the audience answers from their phones. Kinds: choice, multi, rating, words.
<Poll id="lunch" question="Lunch?" options={["Dosa", "Biryani", "Both"]} />| Prop | Type | Default | |
|---|---|---|---|
id required |
string |
Stable id, unique in the deck (results are keyed by it). | |
question required |
string |
The question. | |
options |
string[] |
[] |
Answers (choice and multi). |
kind |
PollKind |
"choice" |
choice · multi · rating · words. |
scale |
number |
5 |
Points on a rating scale. |
liveResults |
boolean |
true |
Show results as they come, or only once closed. |
className |
string |
Presence
Section titled “Presence”How many people are following.
<Presence />| Prop | Type | Default | |
|---|---|---|---|
className |
string |
QrJoin
Section titled “QrJoin”The QR code and short link for the audience page — put it on the title or first slide.
<QrJoin size={300} />| Prop | Type | Default | |
|---|---|---|---|
size |
number |
260 |
Pixels. |
caption |
string |
"Scan to follow along, react and ask" |
Text under the code. |
className |
string |
Questions
Section titled “Questions”The audience’s questions, most upvoted first.
## Questions?
<Questions limit={5} />| Prop | Type | Default | |
|---|---|---|---|
limit |
number |
6 |
How many to show. |
className |
string |
A timed quiz question with points for speed; feeds the leaderboard.
<Quiz id="q1" question="2 + 2?" options={["3", "4", "5"]} correct={1} seconds={15} />| Prop | Type | Default | |
|---|---|---|---|
id required |
string |
Stable id, unique in the deck. | |
question required |
string |
The question. | |
options required |
string[] |
Answers. | |
correct required |
number |
0-based index of the right answer. | |
seconds |
number |
20 |
Time limit. |
className |
string |
Reactions
Section titled “Reactions”A reaction bar on the slide (the audience page always has one).
<Reactions />| Prop | Type | Default | |
|---|---|---|---|
className |
string |
WordCloud
Section titled “WordCloud”The audience answers in a word or two; the words grow as they repeat.
<WordCloud id="one-word" question="One word for this talk?" />| Prop | Type | Default | |
|---|---|---|---|
id required |
string |
Stable id, unique in the deck. | |
question required |
string |
The prompt. | |
className |
string |
Glossary
Section titled “Glossary”See Glossary term cards.
Term · TermReadout · Terms
A glossary term card by hand: the entry named by its text or id, or a one-off with def. The compiler links first mentions from glossary.yaml automatically.
<Term>UTM</Term> · <Term id="utm">projected metres</Term> · <Term def="Root-mean-square error." tag="Statistics">RMSE</Term>| Prop | Type | Default | |
|---|---|---|---|
id |
string |
The glossary entry (its id, name or alias). Without it the children’s text is looked up. | |
def |
string |
A one-off definition (inline Markdown). With it, the glossary is not consulted. | |
more |
string |
||
title |
string |
The card’s title for a one-off; defaults to the children’s text. | |
full |
string |
An abbreviation’s expansion. | |
tag |
string |
Category chip. | |
link |
string |
Source URL. | |
html |
string |
Set by the compiler: def/more already rendered (with KaTeX), and an automatic link. |
|
moreHtml |
string |
||
auto |
boolean |
Internal (set by the compiler). |
TermReadout
Section titled “TermReadout”The open term’s definition as page content, for a page whose slide is too small for a card (custom audience pages).
<TermReadout />| Prop | Type | Default | |
|---|---|---|---|
className |
string |
Links glossary mentions inside a plain string at render time — for words that arrive as a prop, which the compiler cannot see.
<small><Terms>{"GNSS accuracy in UTM metres"}</Terms></small>Markdown elements
Section titled “Markdown elements”What plain Markdown renders through. You rarely write these tags yourself.
Anchor
Section titled “Anchor”The a mapping: [text](#/3) and other in-deck hash links navigate; external links open in a new tab.
[the results slide](#/results) · [docs](https://deck.kadal.cc/docs/)| Prop | Type | Default | |
|---|---|---|---|
href |
string |
The li mapping: a plain item, or a click step inside <Clicks>.
- each item renders through thisThe ol mapping behind numbered Markdown lists.
1. a numbered list renders through this| Prop | Type | Default | |
|---|---|---|---|
className |
string |
The ul mapping behind Markdown bullet lists; <Clicks> steps its items.
- a Markdown list renders through this| Prop | Type | Default | |
|---|---|---|---|
className |
string |