Oblivion
Oblivion
Docs
Go back
Component by
OV
Oblivion
TSX
mac-dock
"use client"

import React, { useRef } from "react"
import { motion, useMotionValue, useSpring, useTransform } from "framer-motion"
import { Home, Search, Bell, Settings, User } from "lucide-react"

export const componentMeta = {
  name: "Mac-Style Dock",
  description: "An interactive navigation dock where icons physically react and scale based on cursor proximity.",
  props: {}
}

interface DockItemProps {
  icon: React.ElementType
  mouseX: any // MotionValue<number> but easier to use any if user hasn't typed their project
}

function DockItem({ icon: Icon, mouseX }: DockItemProps) {
  const ref = useRef<HTMLDivElement>(null)

  // We calculate distance from the center of this specific icon 
  const distance = useTransform(mouseX, (val: number) => {
    const rect = ref.current?.getBoundingClientRect() ?? { x: 0, width: 0 }
    return val - rect.x - rect.width / 2
  })

  // Width transformation based on proximity mapping
  const widthSync = useTransform(distance, [-150, 0, 150], [40, 80, 40])
  const width = useSpring(widthSync, { mass: 0.1, stiffness: 150, damping: 12 })

  return (
    <motion.div
      ref={ref}
      style={{ width }}
      className="flex aspect-square items-center justify-center rounded-full bg-white dark:bg-zinc-800 border border-black/5 dark:border-white/10 shadow-sm transition-colors hover:bg-neutral-50 dark:hover:bg-zinc-700 mx-1"
    >
      <Icon className="h-2/5 w-2/5 text-neutral-600 dark:text-neutral-300" />
    </motion.div>
  )
}

export default function MacDock() {
  const mouseX = useMotionValue(Infinity)
  const items = [Home, Search, Bell, Settings, User]

  return (
    <div className="flex items-center justify-center w-full py-12">
      <motion.div
        onMouseMove={(e: React.MouseEvent) => mouseX.set(e.pageX)}
        onMouseLeave={() => mouseX.set(Infinity)}
        className="flex h-16 items-end rounded-2xl bg-white/50 dark:bg-zinc-900/50 backdrop-blur-xl border border-white dark:border-white/10 px-3 pb-3 pt-3 shadow-[0_0_20px_rgba(0,0,0,0.05)]"
      >
        {items.map((Icon, i) => (
          <DockItem key={i} icon={Icon} mouseX={mouseX} />
        ))}
      </motion.div>
    </div>
  )
}
Save to favoritesCopy to Figma
React

Mac-Style Dock

An interactive navigation dock where icons physically react and scale based on cursor proximity.

Installation

$ npx @cosmoo/oblivion add mac-dock
Dependenciesnpm install framer-motion lucide-react

Usage Example

tsx
import MacDock from "@/components/oblivion/mac-dock"

export default function Demo() {
  return (
    <div className="p-10 flex justify-center">
      <MacDock />
    </div>
  )
}