Skip to content

Markup

Busker reads your mock through five data- attributes and writes back a handful of classes. Nothing else is assumed: no wrapper components, no required class names, no shadow DOM.

AttributeOnWhat it means
data-cursorone elementThe pointer. Busker positions it and shows the press.
data-scene="home"a page of the mockOne is shown at a time. Named in scene and in routes.
data-nav="home"the same scene elementWhich nav item is lit while this scene is up.
data-nav-item="home"a nav button or linkGets is-active when a scene claims it.

Anything else — rows, buttons, modals, inputs — is just your markup, targeted by whatever selector you like.

ClassOnWhen
buskerthe rootFor as long as busker is running. Everything in busker.css hangs off it.
is-activea scene, a nav itemWhile that scene is the one on screen.
is-interactiveevery routes targetAlways. It is what makes clickable things look clickable.
is-hoverthe current targetFrom the moment the cursor lands until it sets off again.
is-pressingthe cursorFor 200ms as it presses.
is-ringingthe cursorFor 500ms — the ripple outlives the press so the click reads.
is-hintevery routes targetFor 1.5s after a visitor clicks something dead.
is-asidethe rootOnce a visitor has taken over.

Busker removes all of them on destroy().

The root is the element you pass to busk(). Two things follow from that:

  • The cursor is positioned against it. busker.css sets position: relative on .busker for you. If you are writing your own styles, the root needs to be a positioning context.
  • Visibility is measured on it. The show runs while the root is on screen, which means the root should be the visible frame of the mock, not a wrapper that is taller than the viewport. See visibility if you want to loosen that.

A scene is one page of the mock. Busker shows one at a time by putting is-active on it, and busker.css does the rest: scenes are stacked and cross-fade into each other, so the mock never changes height and nothing pops. The element holding them needs a height of its own — see Styling.

Scenes never change on a timer. They change because something was clicked — by the cursor or by a visitor — and a route said so. That is the whole point: there is one cause, so there is nothing to synchronise.

[data-cursor] can be any element. busker.css styles it as the soft dot busker’s own demos use, sized by --busker-cursor-size. To draw your own pointer instead, put an <svg> in there and skip the cursor rules — see Styling.

The cursor is hidden until busk() runs, so it never flashes on a page whose JavaScript has not loaded, and it stays hidden under prefers-reduced-motion.

Getting started · Next: Click-driven routines