axi0motion

Dock

A row of icons that swell toward the pointer and part to make room, with labels that rise above them, launch bounces and badges.

  • enhancer
  • toolbar
  • icons
  • magnify
  • pointer
  • apps
  • since 0.2

Background Studio: tune it below, then copy the code

Your system asks for reduced motion: the demo shows its final state and nothing moves.

Live demo

Dock example

Controls

1.7
150 px
54 px

Code

It follows the controls above: change an option and the code changes with it.

<link rel="stylesheet" href="/axi0/motion/motion.css?v=6">
<script src="/axi0/motion/motion.js?v=10" defer></script>

<div data-motion="dock" aria-label="Apps">
  <button type="button" aria-label="Home" aria-pressed="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 11l9-7 9 7v9a1 1 0 0 1-1 1h-5v-6h-6v6H4a1 1 0 0 1-1-1z"/></svg></button>
  <button type="button" aria-label="Search" aria-pressed="false"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><circle cx="11" cy="11" r="6.5"/><path d="M20 20l-4.2-4.2"/></svg></button>
  <button type="button" aria-label="Mail" aria-pressed="false" data-badge="3"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="5" width="18" height="14" rx="2.5"/><path d="M4 7l8 6 8-6"/></svg></button>
  <button type="button" aria-label="Music" aria-pressed="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M9 18V5l11-2v13"/><circle cx="6" cy="18" r="3"/><circle cx="17" cy="16" r="3"/></svg></button>
  <button type="button" aria-label="Photos" aria-pressed="false"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="4" width="18" height="16" rx="3"/><circle cx="9" cy="10" r="1.8"/><path d="M21 16l-5-5-9 9"/></svg></button>
  <button type="button" aria-label="Settings" aria-pressed="false"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="3"/><path d="M12 2v3M12 19v3M4.9 4.9L7 7M17 17l2.1 2.1M2 12h3M19 12h3M4.9 19.1L7 17M17 7l2.1-2.1"/></svg></button>
</div>

The wrappers: Dock.tsx (React, TypeScript) and Dock.vue (Vue). Both render the same attributes as the HTML; the loader does the rest.

Options

AttributeDefaultWhat it does
data-motion-magnify1.7how big the icon under the pointer grows
data-motion-reach150how far from the pointer icons still grow
data-motion-size54the icons' resting size
data-motion-launchtruepressed toggle buttons bounce and keep a dot below them
data-motion-labelDockthe toolbar's name when the element has no aria-label

Accessibility

- The element becomes a toolbar with a label. Tab enters it once; Left and Right arrows, Home and End move between the icons; Enter or Space presses one. - Every icon keeps its own accessible name (aria-label, title or text); a badge adds itself to that name ("Mail, 3"). The floating label is decoration, hidden from screen readers. - Toggle buttons (aria-pressed) flip when pressed; the dot under an open one shows that state, and so does aria-current="page" on links. - Keyboard focus swells the focused icon the way the pointer does. Touch never magnifies. - Reduced motion drops the bounce; the swell still follows the pointer but jumps instead of easing. Reduced motion shows every state at once, with no movement, and stops anything that would move on its own. Frame loops and CSS animations pause off screen and in hidden tabs. Only transform, opacity and paint animate, so nothing around it moves.

Size

dock.js is 2.5 KB gzip, with components-kit.js 3.9 KB it needs. A page loads the loader (2.7 KB) and core.js (1.4 KB) once, whatever it uses.