Floating Dock — Springy Magnification in a Navigation Bar

A breakdown of how the FloatingDock component animates its items, expands a tooltip label, and keeps a nav bar feeling physical without a single layout jump.

AnimationsFramer MotionTailwind CSSReact

The FloatingDock component is the animated navigation bar you see throughout this site: a row of icons that magnify as your cursor approaches, with a tooltip label that slides out for the focused item.

What makes it feel good

The whole effect is built on three moving parts:

  • Item magnification — the icon nearest your cursor scales up.
  • Label reveal — hovering an item slides its title out horizontally.
  • Container focus — the dock gains a subtle highlight and a small badge for the active item.

The trick is that each item animates to a layout position computed from its index and the hovered index, so the magnification is always symmetric around the focused icon.

The spring recipe

Framer Motion springs are used for every transform so nothing moves at constant speed:

const spring = { type: 'spring', stiffness: 320, damping: 30 };

stiffness: 320 gives a crisp response without wobble; damping: 30 kills overshoot. Combined with a tiny mass, this keeps the dock feeling responsive on fast mouse movement while remaining stable on touch.

Why layout animation instead of width?

Each nav icon changes both width and height. Rather than animating those CSS properties (which can cause reflow), the items keep a fixed size-10 box and scale their inner content with motion.div, keeping paint costs low.

Using it

import { FloatingDock } from "@/components/ui/floating-dock";

const links = [
  { title: "Home", icon: <IconHome />, href: "/" },
  { title: "GitHub", icon: <IconBrandGithub />, href: "https://github.com" },
];

<FloatingDock items={links} />

Key takeaways

  • React to the focused index, not individual hover states, so magnification centers correctly.
  • Prefer scale/transform animation over width/height for cheap, 60fps motion.
  • Tune springs by feel — start at stiffness: 320, damping: 30 and adjust in one direction at a time.