Ghost Dock
It is a stylish, interactive navigation bar built with Framer Motion and Tailwind CSS. It features a responsive, sliding background glow effect that tracks the active tab and supports custom icons.
Live Preview
Dependencies
npm install
framer-motionlucide-reactCode
"use client";
import { motion, AnimatePresence } from "framer-motion";
import {
Home,
Bell,
User,
Hash,
AlarmClock,
BellOff,
Menu,
X,
} from "lucide-react";
import { ReactNode, useState } from "react";
type NavItem = {
id: string;
icon: ReactNode;
label: string;
};
const NAV_ITEMS: NavItem[] = [
{ id: "home", icon: <Home size={20} />, label: "Home" },
{ id: "explore", icon: <Hash size={20} />, label: "Explore" },
{ id: "alerts", icon: <Bell size={20} />, label: "Alerts" },
{ id: "profile", icon: <User size={20} />, label: "Profile" },
{ id: "alarm", icon: <AlarmClock size={20} />, label: "Alarm" },
{ id: "silent", icon: <BellOff size={20} />, label: "Silent" },
];
export default function GhostDock({ items = NAV_ITEMS }) {
const [active, setActive] = useState("home");
const [isOpen, setIsOpen] = useState(false);
return (
<div className="relative">
<AnimatePresence>
{isOpen && (
<motion.div
initial={{ opacity: 0, y: 10, scale: 0.95 }}
animate={{ opacity: 1, y: 0, scale: 1 }}
exit={{ opacity: 0, y: 10, scale: 0.95 }}
transition={{ type: "spring", bounce: 0.2, duration: 0.6 }}
className="absolute bottom-full left-1/2 -translate-x-1/2 mb-3 flex flex-col items-center gap-2 p-2 shadow-[inset_0_2px_4px_rgba(0,0,0,0.3)] dark:shadow-[inset_0_2px_4px_rgba(255,255,255,0.3)] rounded-[2rem] bg-zinc-900/5 dark:bg-zinc-100/5 ring-2 ring-zinc-200 dark:ring-zinc-800 backdrop-blur-md md:hidden"
>
{items.map((item: NavItem, idx: number) => (
<button
key={idx}
onClick={() => {
setActive(item.id);
setIsOpen(false);
}}
className="relative p-4 rounded-2xl text-zinc-500 hover:text-zinc-900 dark:hover:text-white transition-colors cursor-pointer"
>
{active === item.id && (
<motion.div
layoutId="dock-glow"
className="absolute inset-0 shadow-[inset_0_2px_4px_rgba(0,0,0,0.3)] dark:shadow-[inset_0_2px_4px_rgba(255,255,255,0.3)] bg-white dark:bg-zinc-800 rounded-3xl z-0"
transition={{ type: "spring", bounce: 0.2, duration: 0.6 }}
/>
)}
<span className="relative z-10">{item.icon}</span>
</button>
))}
</motion.div>
)}
</AnimatePresence>
<div className="flex items-center gap-2 p-2 shadow-[inset_0_2px_4px_rgba(0,0,0,0.3)] dark:shadow-[inset_0_2px_4px_rgba(255,255,255,0.3)] rounded-[2rem] bg-zinc-900/5 dark:bg-zinc-100/5 ring-2 ring-zinc-200 dark:ring-zinc-800 backdrop-blur-md">
<div className="hidden md:flex items-center gap-2">
{items.map((item: NavItem, idx: number) => (
<button
key={idx}
onClick={() => setActive(item.id)}
className="relative p-4 rounded-2xl text-zinc-500 hover:text-zinc-900 dark:hover:text-white transition-colors cursor-pointer"
>
{active === item.id && (
<motion.div
layoutId="dock-glow"
className="absolute inset-0 shadow-[inset_0_2px_4px_rgba(0,0,0,0.3)] dark:shadow-[inset_0_2px_4px_rgba(255,255,255,0.3)] bg-white dark:bg-zinc-800 rounded-3xl z-0"
transition={{ type: "spring", bounce: 0.2, duration: 0.6 }}
/>
)}
<span className="relative z-10">{item.icon}</span>
</button>
))}
</div>
<div className="md:hidden flex items-center">
<button
onClick={() => setIsOpen(!isOpen)}
className="relative p-4 rounded-2xl text-zinc-500 hover:text-zinc-900 dark:hover:text-white transition-colors cursor-pointer"
>
<span className="relative z-10 flex items-center justify-center">
{isOpen ? <X size={20} /> : <Menu size={20} />}
</span>
</button>
</div>
</div>
</div>
);
}
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| items | NavItem[] | NAV_ITEMS | An array of navigation items, each containing an ID, icon element, and label to populate the dock. |
Features
Fluid Animations
Powered by Framer Motion's layoutId for smooth, spring-based transitions between active states.
Adaptive Styling
Features a polished, glassmorphic design with Tailwind CSS and backdrop blur for modern aesthetics.
Dark Mode Ready
Seamlessly adapts to both light and dark themes with dedicated shadow and background styles.
Interactive Navigation
Click an item to activate it, updating the layout while keeping navigation elements responsive.
Compact Footprint
Designed to be responsive and space-efficient, fitting easily into various screen sizes and UI layouts.