macOS Dock

Featured

by Dax · tsx · 49 lines

A macOS-style dock where icons magnify as you hover near them. Each item scales based on its distance from the cursor, creating the iconic fish-eye effect. Uses framer-motion for smooth springs.

docknavigationmagnifyframer-motion
49 lines
"use client";
import { useRef } from "react";
import { motion, useMotionValue, useSpring, useTransform } from "framer-motion";

function DockItem({ icon, label, mouseX }: {
  icon: string; label: string; mouseX: any;
}) {
  const ref = useRef<HTMLDivElement>(null);

  const distance = useTransform(mouseX, (val: number) => {
    const rect = ref.current?.getBoundingClientRect();
    return val - (rect ? rect.x + rect.width / 2 : 0);
  });

  const size = useSpring(
    useTransform(distance, [-120, 0, 120], [48, 72, 48]),
    { mass: 0.1, stiffness: 200, damping: 12 }
  );

  return (
    <motion.div
      ref={ref}
      style={{ width: size, height: size }}
      className="flex items-center justify-center rounded-xl bg-white/10 text-2xl backdrop-blur-sm"
      title={label}
    >
      {icon}
    </motion.div>
  );
}

export function Dock({ items }: {
  items: { icon: string; label: string }[];
}) {
  const mouseX = useMotionValue(Infinity);

  return (
    <motion.div
      onMouseMove={(e) => mouseX.set(e.pageX)}
      onMouseLeave={() => mouseX.set(Infinity)}
      className="mx-auto flex items-end gap-2 rounded-2xl border border-white/10 bg-black/50 px-3 py-2 backdrop-blur-xl"
    >
      {items.map((item) => (
        <DockItem key={item.label} {...item} mouseX={mouseX} />
      ))}
    </motion.div>
  );
}