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
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>
import { Dock } from "./motion/react/Dock";
<Dock>Your content</Dock>
<script setup lang="ts">
import Dock from "./motion/vue/Dock.vue";
</script>
<template>
<Dock>Your content</Dock>
</template>
const el = document.querySelector("#title");
el.dataset.motion = "dock";
The wrappers: Dock.tsx (React, TypeScript) and Dock.vue (Vue). Both render the same attributes as the HTML; the loader does the rest.
Options
| Attribute | Default | What it does |
|---|---|---|
data-motion-magnify | 1.7 | how big the icon under the pointer grows |
data-motion-reach | 150 | how far from the pointer icons still grow |
data-motion-size | 54 | the icons' resting size |
data-motion-launch | true | pressed toggle buttons bounce and keep a dot below them |
data-motion-label | Dock | the 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.