/docs/authoring

Author an MDX deck

Use the Markdown, MDX, and deck-specific syntax supported by the compiler.

Keep each deck in its own directory

Use decks/<slug>/deck.mdx. The directory name becomes the URL slug, so decks/launch/deck.mdx appears at /decks/launch.

The opening --- block contains deck metadata. Later separators start new slides, so a bare --- cannot be used as a thematic break inside a slide.

decks/launch/deck.mdx
---
title: Hono at the edge
transition: fade
---

# Hono at the edge

---
title: Runtime boundary
layout: statement
---

Node for I/O. Hono for routes.

Write slide content with GFM and MDX

Use CommonMark plus GFM tables, task lists, strikethrough, and autolinks. MDX adds JSX elements and expressions.

MDX
# Runtime boundary

Use **bold**, *emphasis*, `inline code`, and [links](https://hono.dev/).

- Node for build-time I/O
- Hono for runtime routes

- [x] Compile the deck
- [ ] Deploy the Worker

| Layer | Responsibility |
| :-- | :-- |
| Node | Build-time I/O |
| Hono | Runtime routes |

~~Filesystem access at runtime~~

> Keep the Worker bundle filesystem-free.

```ts
const runtime = "Hono"
```
Fenced code
Add a language such as ts, tsx, or css after the opening fence to enable syntax highlighting in the slide.
MDX
Use JSX components, props, and expressions. Keep import and export statements at the top of the file.

Separate deck and slide metadata

Opening frontmatter applies to the deck. Frontmatter immediately after a slide separator applies only to that slide. Unknown keys remain in meta but produce a warning.

Deck
title, description, author, tags, date, theme, transition, transitionDuration, transitionEasing, draft, assets, presenter
Slide
title, layout, class, notes, background, transition, transitionDuration, transitionEasing
Transitions
none, fade, fade-out, slide-left, slide-right, slide-up, slide-down, view-transition
Layouts
default, centered cover, and centered statement are built in. A custom name becomes a layout-<name> class that can be styled in theme.css.

Reveal content one step at a time with fire

Add fire to a component to reveal it in source order. Use :::fire for Markdown and :::fire{each="item"} for list items. Use <Fire> to group multiple JSX elements into one step. The compiler removes fire before rendering the component.

MDX
<Card fire />

<Chart fire="scale" at="2" />

:::fire{at="+2"}
Markdown block
:::

:::fire{each="item" depth="2" every="2"}
- Parent one
  - Child one
- Parent two
  - Child two
:::

<Fire effect="fade-up">
  <Heading />
  <Description />
</Fire>

The staged-reveal model and the at, depth, and every options draw in part on Slidev's v-click and v-clicks. The syntax and implementation are specific to hono-decks; compatibility with Slidev is not guaranteed. at="2" sets an absolute position, while at="+2" advances two steps from the current position. For lists, depth selects the nested levels and every sets how many items appear per step. Both default to 1.

Choose an effect

Use fire="scale" on a component and effect="scale" with :::fire. Built-ins are none, fade, fade-up, and scale. Define custom effects in theme.css.

MDX
<Chart fire="blur-in" />

:::fire{effect="blur-in"}
Markdown block
:::
theme.css
[data-fire-effect="blur-in"] {
  --fire-transform: scale(.98);
  --fire-filter: blur(12px);
  --fire-duration: .32s;
  --fire-easing: ease-out;
}

Add notes for the presenter

Text under notes: | and MDX comments are combined into presenter notes and omitted from the slide. Every MDX comment is treated as a note, even if you intended it only as a source-code comment.

MDX
---
notes: |
  Explain why generation runs before deployment.
---

# Build once, serve anywhere

{/* Mention the generated module boundary. */}

Start with server components

Named exports from components/index.tsx are available as tags in that deck's MDX. Registries are deck-local, so the same component name can exist in another deck.

TypeScript
// decks/welcome/components/index.tsx
export function Metric(props: { value: string; label: string }) {
  return <figure>
    <strong>{props.value}</strong>
    <figcaption>{props.label}</figcaption>
  </figure>
}
MDX
<Metric value="18 ms" label="Response time" />

Use an island only for browser interaction

Use components/client/index.tsx only for components that need clicks or local state. The compiler generates and serves the client entry, so ordinary applications do not add a separate asset route.

TypeScript
// decks/welcome/components/client/index.tsx
import { useState } from "hono/jsx/dom"

export function Counter() {
  const [count, setCount] = useState(0)
  return <button onClick={() => setCount(count + 1)}>
    Count: {count}
  </button>
}

Reference assets and embeds explicitly

Reference images under decks/launch/assets/ with paths relative to deck.mdx. Explicit directives are available for youtube, x, card, embed, and iframe.

MDX
![Architecture](./assets/runtime-boundary.svg)

@[youtube](https://www.youtube.com/watch?v=VIDEO_ID)
@[x](https://x.com/honojs/status/POST_ID)
@[card](https://hono.dev/docs/)
@[embed](https://example.com/demo)
@[iframe](https://example.com/demo)

A bare URL on its own line becomes a normal link. Configure CSP and allowed origins before publishing external iframes. To serve assets from R2, use withR2Assets() without changing MDX paths.

Add a deck-local theme

Place theme.css beside deck.mdx to style only that deck. Start with the provided CSS variables, then add selectors for specific content.

decks/welcome/theme.css
/* decks/welcome/theme.css */
:root {
  --hono-decks-accent-color: #ff5b1a;
}

.slide h1 {
  text-wrap: balance;
}

Preview changes with the dev command

Terminal
npm run dev

While the Vite or Wrangler dev command is running, saved MDX is recompiled automatically and the browser updates after a successful compile. Use npm run decks:compile in CI or when checking the compiler by itself. Compile errors identify the source file and slide number.

After the deck renders, continue to routes and UI for public surfaces or configuration for bindings and R2.