Skip to content

Modules

Modules are the template’s convention for client-side behaviour: elements opt in with a data-module="<id>" attribute, and a matching file in src/modules/<id>.ts provides the behaviour. The insert panel’s Modules presets emit matching markup.

Every file in src/modules/ is a module. It default-exports an init function that receives the element and its dataset, and may return a teardown:

src/modules/reveal.ts
export default function (element: HTMLElement, dataset: DOMStringMap) {
// read config from data attributes, e.g. data-reveal-threshold
// ...
return () => {
/* optional cleanup */
};
}

Scoped styles live in src/styles/modules/<id>.css.

Config flows through data attributes on the same element — e.g. the starter reveal module reads data-reveal-threshold and data-reveal-once.

When does the teardown matter? In motion projects, Taxi swaps page content in-place, so return a teardown — stale listeners and observers leak across navigations otherwise. Teardowns are scoped to the module’s root element: on a navigation only modules inside the outgoing [data-taxi-view] are destroyed, while modules on persistent chrome keep running. In plain projects every navigation is a full page load, so returning a teardown is optional.

The underscore directory is the runtime, not a module:

  • create.ts — discovers modules via import.meta.glob, matches them to [data-module] elements, and guards against double-initialization when re-run (navigation, late-added content)
  • runner.ts — lifecycle registry: destroy() teardowns on navigation/swap, pageIn()/pageOut() transition hooks, view() IntersectionObserver binding, track() scroll-bound 0…1 progress
  • observe.tsObserve/ObserverManager, the IntersectionObserver helper behind onView
  • track.tsTrack (extends Observe), scroll progress tracking
Module Behaviour
reveal Fades the element in when it first enters the viewport (data-reveal-threshold, data-reveal-once)
marquee Continuous horizontal marquee
tabs Tabbed content switching