Skip to content

Sidebar and tab indicator

The page below is the real demo.html from the kit. Use its “Toggle dark” button for the dark theme.

Current rule (v2.0.1, 2026-11-13): Demo navigation uses real href links. The labelled tablist has tab/panel relationships, one tab stop, Left/Right and Home/End selection. Initial indicator placement and resize are immediate; section changes retarget one transform transition. Background colours change immediately to keep animation compositor-only. Supersedes the retained implementation/timing claims below; see docs/current-rules.md#cr-motion-01 and motion-flow.

The current section is shown by one box that slides to the selected item, instead of each item repainting its own highlight. The same hook moves the tab underline. A resize skips the transition so a collapsing section never makes the indicator lag.

Open demo.html in a browser (it links ../../tokens/tokens.css) and use “Toggle dark” to check both themes.

File What it is
sidebar.css The .sw-indicator box, the rules that drop the item’s own highlight once the indicator is placed, and the tab underline, verbatim from the app.
demo.html A standalone page with the live animation in light and dark, replayable.
react/ Copies of the real app files (see react/README.md for the imports to replace).
previews/ Animated WebP and GIF previews, light and dark (regenerated by scripts/make-previews.mjs).
  • Staff and member sidebar: components/shell/Sidebar.tsx, SidebarItem.tsx, SidebarSection.tsx (the “More” group uses the collapse family).
  • Tabs with an underline: .desk-tab-active and .sw-tab-indicator in staff panels.
  • Hook: lib/motion/useSlideIndicator.ts.

Moving one box shows where you came from and where you are now; repainting a list item does not. It is also the cheapest possible animation: one transform.

Current rule (v2.0.1, 2026-11-13): The retained table/snippet below records the original app copy. Use the current executable files and the complete flow recipe for decision 399; see current rules.

Property Value
transform --sw-dur-base 180 ms, --sw-ease-standard
Size set directly (width and height are never transitioned)
Resize transition: none for that update

A change of the current item or tab (the hook key). The container gets data-slide once the indicator is placed; the indicator hides when nothing matches.

The token duration is 0, so the box jumps to the new item; the current item is still marked by aria-current.

Colours come from tokens (--color-accent-soft fill, --color-accent-ink underline).

  • Do transition only transform and set the size directly.
  • Do keep aria-current="page" on the real item.
  • Do not animate the sidebar on route changes (see route-transition).
  • Do not repaint each item’s highlight separately.

Current rule (v2.0.1, 2026-11-13): The retained table/snippet below records the original app copy. Use the current executable files and the complete flow recipe for decision 399; see current rules.

<nav id="nav" style="position:relative">
<div class="sw-indicator" id="bar"></div>
<a class="sw-slide-item" aria-current="page">Requests</a><a class="sw-slide-item">Inventory</a>
</nav>

Call the placement function from demo.html (a plain-JS port of useSlideIndicator) whenever the current item changes and on resize.

Every other animation in the product, and the rules behind them: ../../docs/motion.md. Index of the kit: ../README.md.

Demo navigation uses real href links. The labelled tablist has tab/panel relationships, one tab stop, Left/Right and Home/End selection. Initial indicator placement and resize are immediate; section changes retarget one transform transition. Background colours change immediately to keep animation compositor-only.

Complete rules, sequencing, keyboard and verification. The demo includes real static posters and explicit image Play/Pause controls.

These aliases are local additions; global tokens are unchanged. Promote through the token batch when adopted.

Local custom property Definition
--sw-collapse-exit calc(var(--sw-dur-base) * .75)

Copied from motion/sidebar/ on every build: the stylesheet, demo.html, react/ copies of the app files and the previews/.