Reference

<deck-root> API

For authors who script or embed a deck, and for extension writers: every attribute of <deck-root>, its slide-change event, and the use() method that registers an extension.

Reactive properties

PropertyTypeWhat it controls
current number (state) Index of the active slide (0-based).
step number (state) Current step within the active slide (0 = first reveal).
overview boolean (reflected) Toggles the overview mode.
transitionstring (reflected) Lazy-loads the transition module. See Optional modules · transitions.
autoplay number ms (reflected) Auto-advance interval. 0 disables. Pauses on hover, resets on user nav.
loop boolean (reflected) Wrap around at the deck edges (carousel mode).
swipe boolean (reflected) Enable pointer-driven horizontal swipe navigation (touch + mouse).
fluid boolean (reflected) Fill the box and reflow instead of the zoom-to-fit canvas. Also honoured per slide (a slide carrying fluid escapes the canvas for the real viewport).
noHint boolean · attr no-hint Hide the bottom-left key-hint chips.
noArrows boolean · attr no-arrows Hide the bottom-right navigation chevrons.
noCounterboolean · attr no-counterHide the bottom-right n / total counter.
noZoom boolean · attr no-zoom Disable slide zoom (Ctrl/⌘+wheel, pinch, +/-/0) · on by default.
width heightnumber (default 1920 / 1080)Logical canvas. Only the aspect ratio and the rem baseline depend on them · the canvas is then scaled to fit the box.
mouseNav string · attr mouse-nav Mouse mechanisms in use. none disables them, or pass a space-separated subset of click wheel arrows aux. Unset means all of them.
nav string (reflected) 2d opts into chapter/slide grid navigation. Unset stays linear, whatever the deck-section structure.
preview boolean (reflected) Passive render · the deck still scales and letterboxes but wires no keyboard, mouse, autoplay or presenter handler. Used by the presenter preview panes.
blank 'black' | 'white' | null (state)The full-screen blank overlay (the B / W clicker keys). Not an attribute.
presenterActiveboolean (state) Set by the presenter module while the speaker window is open · the main window then hides its hint chips and arrows.

current, step, blank andpresenterActive are reactive state, readable and writable from script but carrying no attribute. The rest are reflected, so setting the attribute in HTML and setting the property from script do the same thing.

Fixed canvas or fluid

By default the deck is a fixed logical canvas ofwidth × height, scaled uniformly to fit its box and letterboxed when the aspect differs · every slide then keeps an identical layout at any window size. fluid drops that: the stage fills the box and the slide reflows like a web page. A single slide can carryfluid on its own to escape the canvas while it is the active one.

fluid
<!-- Fluid deck · fills its box and reflows, no logical canvas -->
<deck-root fluid>
  <deck-feature>
    <h1 slot="title">Reflows with the window</h1>
  </deck-feature>
</deck-root>

<!-- Or one slide at a time, inside a zoom-to-fit deck -->
<deck-root>
  <deck-feature>
    <h1 slot="title">Scaled to the 1920 x 1080 canvas</h1>
  </deck-feature>
  <deck-feature fluid>
    <h1 slot="title">This one uses the real viewport</h1>
  </deck-feature>
</deck-root>

Events

deck-root dispatches one event of its own,slide-change, when the active slide changes · not on a step change within a slide. It does not bubble, so listen on thedeck-root element itself. Its detail carriescurrent and previous, the two slide elements (previous is null on the first render). The transition module and the presenter window are both built on it.

Registering an extension · use()

use(plugin) is the element's own public method, next to the standard custom-element lifecycle. It takes an object with a name and any of the optional hookssetup, steps, applyStep andnavigate, and returns a function that unregisters it. It is idempotent by name: registering the same name twice keeps the first one. Each hook receives a small context with the host element, the livecurrent and step, the slide list, andrequestUpdate().

  • setup(ctx) · runs once on registration, may return a teardown.
  • steps(slide, ctx) · contributes to that slide's step count · the engine takes the maximum of its own count and every plugin's.
  • applyStep(step, slide, ctx) · runs after the engine applied a step.
  • navigate(to, ctx, proceed) · wraps a cross-slide move · call proceed() to run it, return a truthy value when handled. Only the first registered plugin with this hook owns navigation; a second one is warned about and ignored.
use() and slide-change
const deck = document.querySelector('deck-root');

const unregister = deck.use({
  name: 'count-steps',
  setup(ctx) {
    console.info('slides', ctx.slides.length);
  },
  steps(slide) {
    return slide.querySelectorAll('[data-reveal]').length;
  },
  applyStep(step, slide) {
    slide.querySelectorAll('[data-reveal]').forEach((el, i) => {
      el.toggleAttribute('shown', i < step);
    });
  },
});

deck.addEventListener('slide-change', (e) => {
  console.info(e.detail.previous, '->', e.detail.current, 'at', deck.current);
});

Embedding a deck in a page

A deck can live inside a course page, a guide or product documentation. The host page loads the same two files a standalone deck does, the theme stylesheet and dist/index.js, then places <deck-root> in a sized container: the element fills its container, so give that container a width and an aspect ratio, for example width: 100%; aspect-ratio: 16 / 9.

  • Arrow keys act only while the embedded deck has focus; it receives tabindex="0" automatically, so a click or a Tab gives it focus.
  • The page URL hash is left alone: deep links to a slide work for a full-page deck only.
  • mouse-nav="click arrows" keeps the mouse wheel for the host page; the mechanisms are click, wheel, arrows and aux.
  • The theme's helper classes are scoped to the deck subtree and do not restyle the host page.
  • The deck's own hint and arrows can be hidden with no-hint and no-arrows when the host page owns the chrome.

See the training carousel recipe for the autoplay variant.

Combine autoplay, loop, swipe andtransition to turn a deck into a fully-functional carousel. The four attributes are mutually independent · you can use any subset.

carousel
<!-- Carousel mode · auto-advance every 4 s, wrap at end, swipe enabled -->
<deck-root autoplay="4000" loop swipe transition="slide">
  <deck-feature>
    <h1 slot="title">Slide 1</h1>
  </deck-feature>
  <deck-feature>
    <h1 slot="title">Slide 2</h1>
  </deck-feature>
  <deck-feature>
    <h1 slot="title">Slide 3</h1>
  </deck-feature>
</deck-root>
Live preview · slide canvas

Behaviour notes:

  • Autoplay pauses while the pointer is over the deck and while the overview is open.
  • Any keyboard navigation resets the autoplay countdown so a manual nudge doesn't double-jump.
  • Swipe threshold is 60 px horizontal and at most 2× the vertical drift · accidental vertical scrolls are ignored.
  • Swipe is automatically disabled inside links, buttons, inputs, and other interactive children.

Built-in key bindings

KeyBehavior
Next / previous slide or step · the default, linear
with nav="2d"Section nav · linear fallback at edges
with nav="2d"Sub-slide nav · linear fallback at section boundaries
Space PgDnLinear next
PgUpLinear previous
Home EndFirst / last slide
OToggle overview · lazy-loads deck-overview.js on first press
PToggle presenter window · lazy-loads deck-presenter.js
? HOpen help · lazy-loads deck-help.js on first press
B .Black screen (clicker convention) · any key dismisses
W ,White screen (clicker convention) · any key dismisses
EscClose any overlay / blank screen

URL hash

The canonical URL is #N · slide N (1-indexed, flat). Other forms accepted on input only:

  • #C.N · chapter C, sub-slide N · rewritten to flat.
  • #N.s · slide N at step s.

Step-reveal in <deck-code>

Reveal subsets of lines progressively. step-groups is a JSON array of arrays · each inner array lists the 1-based line numbers to highlight at that step. Step 0 = all lines visible at full opacity.

A 3-step code reveal
<deck-code lang="js" hero step-groups='[[1,2],[3,4],[1,2,3,4,5]]'>
  const a = 1;
  const b = 2;
  function sum() {
    return a + b;
  }
  sum();
</deck-code>
Live preview

Customization tokens

The deck-root chrome (progress bar, slide counter dots, keyboard hints) is themed via these CSS custom properties · set them on the host or any ancestor.

  • --deck-root-bg · backdrop colour
  • --deck-root-progress-color · top progress bar fill
  • --deck-root-progress-height · default 3px
  • --deck-root-dot-bg · slide counter dot, inactive state
  • --deck-root-dot-active-bg · active slide dot
  • --deck-root-counter-color · "N / total" text colour
  • --deck-root-kb-hint-color · keyboard-hint footer text colour
  • --deck-root-nav-bg · background of the bottom-right nav chevrons
  • --deck-root-nav-color · chevron glyph colour
  • --deck-root-nav-opacity · chevron resting opacity · default 0.35

Adding an element

To add a layout or atom, write a class that extends LitElement, decorate it with @customElement('deck-myname'), and import the file from your deck. The new tag is immediately usable inside any slide · no registration step in deck-root. SeeOptional modules · writing an extension for the full hook contract and the setDeckCodeHighlighter hook.

Next

  • Optional modules · transitions, the presenter window, syntax highlighting and the other modules a deck imports.
  • Navigation · the keys and mouse gestures the properties above control.