/docs/routing

Choose routes and UI surfaces

See which URLs a mounted router creates, then expose and customize only the surfaces your application needs.

Use the configured mount path for every deck URL

Mounting app.route(decks.mountPath, decks.router()) places every route below the configured mount path.

Understand each generated surface

Route / APIPurpose
/Public deck index; can be disabled
/:slugViewer with controls and the slide frame
/:slug/renderSlide document inside the viewer iframe
/:slug/presentationProjection or shared display
/:slug/presenterSpeaker view with next slide and notes
/:slug/printAll slides for printing or browser PDF
/:slug/embedExternal iframe route; created only when embed is enabled

Disable unused surfaces in the shared config

Normally, set unused surfaces to false in router.pages inside hono-decks.config.ts. Every standard surface except embed is enabled by default. When dev is omitted, development mode is derived from the NODE_ENV set by Vite or Wrangler.

hono-decks.config.ts
export default defineDecksConfig({
  mountPath: "/decks",
  router: {
    pages: {
      index: false,
      print: false,
      presenter: ({ dev }) => dev,
    },
  },
})

Resolver functions run per request, so they can also check authentication or environment bindings.

Disabling print also removes the print button from the default viewer and external embed. Cmd / Ctrl + P then uses the browser's native print behavior instead of opening the dedicated route. Links added explicitly by your application are left unchanged.

Customize the default UI or build an app-owned page

Use pages.index.render to change only the deck index. Keep shared behavior in hono-decks.config.ts; the following decks.router(overrides) example changes one mount point only.

TypeScript
decks.router({
  pages: {
    index: {
      title: ({ decks }) => String(decks.length) + " decks",
      render: ({ title, defaultContent }) => <main><h1>{title}</h1>{defaultContent}</main>,
    },
  },
})

Build a route owned by the Hono app

decks.context() supplies deck, TOC, and URL metadata to custom detail or admin routes.

TypeScript
app.get(
  "/decks/:slug/about",
  decks.context(),
  (c) => c.json({
    title: c.var.deck.meta.title,
    slides: c.var.deck.slides.length,
    toc: c.var.deckToc,
  }),
)

Share the same slide position by URL

The viewer, presentation, and presenter screens share the slide position as ?slide=2&step=1. slide is one-based. step starts at zero, where step=0 means staged content has not started appearing. Advancing beyond the last step of the last slide leaves the URL unchanged.

For external iframe use, continue to security and allow explicit origins. Use the API reference when you need a specific option.