Retour au catalogue

Navbar Dock

Navigation style dock macOS fixee en bas. Les icones grossissent au hover avec effet de vague : les voisins grossissent aussi mais moins. useMotionValue + useSpring.

navbarcomplex Both Responsive a11y
playfulminimalboldsaasportfolioagencysticky
Theme

Cómo crear una navbar dock estilo macOS en React con Framer Motion

Una navbar dock estilo macOS en React usa useMotionValue de Framer Motion para seguir la posición X del cursor y useTransform para convertir la distancia entre el cursor y cada icono en un valor de tamaño, luego suaviza el resultado con useSpring. Los iconos más cercanos al puntero crecen más, creando la magnificación en onda característica.

  • Stack: React 19, Framer Motion 11, Lucide React, tokens CSS de Tailwind v4, ~137 líneas.
  • API principal: useMotionValue, useTransform, useSpring con stiffness 300, damping 25, mass 0.5.
  • Los iconos pasan de 44px (BASE_SIZE) a 68px (MAX_SIZE) dentro de un radio de influencia de 140px.
  • Accesible: cada icono tiene un aria-label y un tooltip CSS; el estado hover cambia el fondo a --color-accent.
  • Limitación táctil: la magnificación depende de la posición del puntero, por lo que degrada de forma elegante a iconos estáticos en móvil.

La Navbar Dock es una barra de navegación fija en la parte inferior de la pantalla que imita el Dock de macOS. Cada icono crece al acercarse el cursor y sus vecinos lo siguen con una intensidad decreciente, produciendo un fluido efecto de onda. Reemplaza por completo el patrón de navbar superior y funciona especialmente bien en sitios de portafolio, one-page y orientados a herramientas donde la navegación es secundaria al contenido.

Anatomía

El componente es un `<nav>` fijo centrado horizontalmente en la parte inferior del viewport con un fondo de vidrio esmerilado (backdrop-filter blur + transparencia color-mix). Dentro, una fila de componentes `DockIcon` renderiza cada uno un `motion.a` cuyo tamaño está controlado por una spring motion value. Un `<span>` de tooltip flota sobre cada icono y aparece al :hover mediante una regla CSS inyectada inline. El contenedor nav sigue la X del puntero con onMouseMove y la reinicia a -999 al mouseleave, lo que reduce todos los iconos a su tamaño base.

Cómo funciona

Un único `useMotionValue(-999)` vive en el componente padre `NavbarDock` y se transmite a cada `DockIcon`. En cada icono, `useTransform` lee el valor mouseX compartido y calcula la distancia en píxeles entre el cursor y el centro de ese icono llamando a `getBoundingClientRect()` dentro del callback de transformación. Esa distancia se mapea después de forma lineal de 0 a 140px sobre el rango de tamaño 68px a 44px, dando a los iconos más cercanos un valor mayor. El tamaño bruto alimenta `useSpring` (stiffness 300, damping 25, mass 0.5) para producir un redimensionado suave y elástico sin saltos. Cuando mouseX vale -999 (cursor fuera del dock), cada cálculo de distancia devuelve DISTANCE (140), por lo que todos los iconos vuelven a BASE_SIZE.

Cómo crearlo en React

  1. Crea la motion value compartida para el ratón

    En el componente padre, declara un único `useMotionValue(-999)` y conéctalo a `onMouseMove` y `onMouseLeave` en el elemento nav. El valor centinela -999 indica que el cursor está fuera del dock.

    const mouseX = useMotionValue(-999);
    
    <nav
      onMouseMove={(e) => mouseX.set(e.clientX)}
      onMouseLeave={() => mouseX.set(-999)}
    >
  2. Calcula la distancia entre el cursor y el centro del icono

    En cada `DockIcon`, adjunta una ref al elemento anchor. Pasa el mouseX compartido a `useTransform` y lee el bounding rect del icono dentro del callback para obtener la distancia cursor-centro en tiempo real.

    const distance = useTransform(mouseX, (val: number) => {
      const el = ref.current;
      if (!el || val === -999) return DISTANCE; // collapse
      const rect = el.getBoundingClientRect();
      const center = rect.left + rect.width / 2;
      return Math.abs(val - center);
    });
  3. Convierte la distancia en tamaño con un spring

    Usa un segundo `useTransform` para mapear el rango de distancia [0, DISTANCE] a [MAX_SIZE, BASE_SIZE]. Envuelve el resultado en `useSpring` para que el cambio de tamaño sea suave y físicamente ponderado en lugar de instantáneo.

    const sizeRaw = useTransform(distance, [0, DISTANCE], [MAX_SIZE, BASE_SIZE]);
    const size = useSpring(sizeRaw, { stiffness: 300, damping: 25, mass: 0.5 });
    
    // Apply to the motion element
    <motion.a style={{ width: size, height: size }} ... />
  4. Añade el contenedor de vidrio esmerilado y los tooltips

    Estiliza el nav con `backdrop-filter: blur(16px)` y un fondo `color-mix(in srgb, var(--color-background) 80%, transparent)` para que flote sobre el contenido. Para cada icono, posiciona un `<span>` arriba con `opacity: 0` y muéstralo al :hover del anchor mediante un bloque `<style>` inline.

Cuándo usarlo

La navbar dock encaja en sitios de portafolio, aplicaciones single-page, herramientas de diseño y agencias creativas donde la navegación es compacta (4 a 7 elementos) y donde la interacción en sí misma forma parte de la identidad de marca. Evítala en sitios con mucho contenido o e-commerce donde una navbar superior con menús desplegables resulta más práctica, y descártala si tu audiencia es principalmente móvil, ya que el efecto de magnificación requiere un puntero.

Usado por

  • Apple, Originó el patrón del Dock de macOS en 2001; el comportamiento de magnificación es la referencia canónica de este componente.
  • Linear, Usa un raíl de iconos compacto en la sidebar de su app con transiciones hover fluidas que evocan la manipulación directa del dock.
  • Raycast, Su sitio de marketing presenta cuadrículas de iconos animadas con spring y magnificación al pasar el cursor, directamente inspiradas en el Dock de macOS.
  • Framer, Muestra la magnificación estilo dock como una interacción integrada en su editor visual, lo que la convierte en un clásico de los sitios construidos con Framer.

FAQ

¿Por qué cada DockIcon necesita su propia ref?

La ref da acceso al bounding rect del icono dentro del callback de useTransform, de modo que el componente puede calcular la distancia real en píxeles entre el cursor y el centro de ese icono concreto. Sin ella, la magnificación no podría tener en cuenta la posición.

¿Puedo usar esto con Next.js Link en lugar de anchors normales?

Sí. Reemplaza `motion.a` por `motion(Link)` mediante la factory `motion()` de Framer Motion y pasa `href` y `ref` como de costumbre. Asegúrate de establecer `legacyBehavior={false}` (el valor por defecto en Next 13+) para que Link renderice un único elemento anchor.

¿Cómo añado más tipos de iconos más allá de la map integrada?

Extiende el objeto `ICON_MAP` con componentes Lucide adicionales (o cualquier SVG de React) indexados por un identificador string. Después pasa ese identificador en el campo `icon` de cada item del dock. El componente recurre al icono `Home` para las claves desconocidas.

¿La configuración del spring afecta a la fluidez percibida?

Mucho. Una stiffness más alta hace que los iconos salten más rápido a su tamaño objetivo; un damping más bajo añade oscilación. Los valores por defecto (stiffness 300, damping 25, mass 0.5) dan una respuesta ágil pero sin temblores. Para un dock más suave, prueba stiffness 150 y damping 20.

"use client";

import { useRef } from "react";
import { motion, useMotionValue, useSpring, useTransform } from "framer-motion";
import { Home, Briefcase, User, Mail, BookOpen, Settings } from "lucide-react";

interface DockItem {
  label: string;
  href: string;
  icon: string;
}

interface NavbarDockProps {
  items?: DockItem[];
}

const ICON_MAP: Record<string, React.ComponentType<{ style?: React.CSSProperties }>> = {
  home: Home,
  services: Briefcase,
  about: User,
  contact: Mail,
  blog: BookOpen,

Code complet réservé à Pro

Code source intégral, export multi-framework et playground.

Passer en Pro, 9,99€/mois

Reseñas

Navbar dock macOS en React, magnificación de iconos con