proNew318 lines · framer-motion
Navbar Dock
A dock that leans toward your cursor. A macOS-dock-style icon navigation anchored along the top or bottom edge of a short framed backdrop, with icons that magnify based on pointer proximity and a flat, tappable row on touch screens.
- Use it for
- An app shell, control surface or desktop-style product demo that wants a playful, tactile primary navigation instead of a flat top bar.
- Themes
- Light + dark
- License
- Commercial use
Live
Navigation
Jump anywhere without losing your place
The same six destinations stay one tap away, wherever you are in the product.
tsx
"use client";
import * as React from "react";
import { AnimatePresence, motion, useMotionValue, useReducedMotion, useSpring, useTransform } from "framer-motion";
import { cn } from "@/lib/utils";
function useReducedMotionSafe() {
const prefersReduced = useReducedMotion();
const [mounted, setMounted] = React.useState(false);
React.useEffect(() => setMounted(true), []);
return mounted ? !!prefersReduced : false;
}
/**
* A macOS-dock-style icon navigation: icons magnify based on pointer proximity
* (distance from pointer X to each icon's centre, mapped to a spring-driven size).
* Anchored `absolute` along the top or bottom edge of a short framed backdrop so it
* never escapes the block. Below ~640px there is no reliable pointer, so a flat,
* evenly sized, comfortably tappable row replaces the magnifying one.
*/
export type DockIconId = "home" | "search" | "messages" | "files" | "insights" | "settings";The rest is in Pro.
Full source, the rebuild prompt and registry install unlock with Pro or Lifetime.
Get ProHow it behaves
- →A shared framer-motion MotionValue tracks the pointer's X position inside the dock; each icon derives its distance to the pointer from its own getBoundingClientRect and maps that distance to a target size with useTransform, smoothed through a useSpring so growth/shrink feels elastic, not stepped.
- →magnification scales how large the nearest icon grows relative to baseSize; baseSize sets the resting icon size.
- →The dock is positioned absolute at the top or bottom edge of its own framed backdrop (position prop), never fixed, so it stays inside the block at any zoom.
- →Hovering or focusing an icon reveals a small label tooltip positioned absolute above (bottom-anchored dock) or below (top-anchored dock) that icon, inside the icon's own relative wrapper.
- →Below the sm breakpoint, or for any non-mouse pointer, the magnifying dock is replaced by a flat row of evenly sized, comfortably tappable icon buttons with no hover dependency.
- →activeId highlights one icon (border, tint and a small indicator dot) and is kept in sync with internal click state; onSelect fires with the clicked icon's id.
Accessibility
- ✓Every icon is a real `<button>` with `aria-label` and `aria-pressed` reflecting the active state; the SVG icons are `aria-hidden`.
- ✓Tooltips also appear on keyboard focus (`onFocus`/`onBlur`), not only on pointer hover, so keyboard users get the same label.
- ✓The mobile flat row keeps all 6 icons at a 44px+ tap target with no reliance on hover or pointer proximity.
- ✓Pointer tracking only runs for mouse input (`pointerType === "mouse"`) and is skipped entirely under `prefers-reduced-motion`, which renders every icon at a fixed, static size.
- ✓Honours prefers-reduced-motion.