Full Page Navbar
fullpageA dramatic full-screen overlay navigation with image previews and smooth reveal animations. Perfect for creative agencies and portfolios.
#fullpage#overlay#creative#animated
Preview
full-page-navbar
Interactive Preview
Studio.
New York • 12:00 PM
Creative Agency
Architects of modern digital experiences & brand identities.
© 2025 Studio Inc.Click Menu to toggle full-screen overlay
Click the hamburger icon to reveal full-screen overlay navigation.fullpage
Installation
Add this navbar component directly to your project using the shadcn CLI:
$npx shadcn@latest add https://navcn-phi.vercel.app/r/full-page-navbar.json
The component source code is added directly to your project so you can customize it freely.
Source Code
src/components/previews/full-page-navbar.tsxtsx
"use client";
import React, { useState, useEffect } from "react";
import { motion, AnimatePresence } from "motion/react";
import { ChevronRight, ArrowUpRight, X } from "lucide-react";
import Image from "next/image";
interface NavItem {
label: string;
href: string;
image: string;
}
const navItems: NavItem[] = [
{
label: "Work",
href: "#work",
image:
"https://images.unsplash.com/photo-1618005182384-a83a8bd57fbe?w=800&h=600&fit=crop",
},
{
label: "About",
href: "#about",
image:
"https://images.unsplash.com/photo-1618556450994-a6a128ef0d9d?w=800&h=600&fit=crop",
},
{
label: "Services",
href: "#services",
image:
"https://images.unsplash.com/photo-1618556450991-2f1af64e8191?w=800&h=600&fit=crop",
},
{
label: "Contact",
href: "#contact",
image:
"https://images.unsplash.com/photo-1618005198919-d3d4b5a92ead?w=800&h=600&fit=crop",
},
];
export function FullPageNavbar() {
const [isMenuOpen, setIsMenuOpen] = useState(false);
const [hoveredItem, setHoveredItem] = useState<string | null>(null);
const [activeLink, setActiveLink] = useState(navItems[0].href);
const [timeString, setTimeString] = useState("");
useEffect(() => {
const updateTime = () => {
setTimeString(
new Date().toLocaleTimeString([], {
hour: "2-digit",
minute: "2-digit",
hour12: true,
})
);
};
updateTime();
const interval = setInterval(updateTime, 1000);
return () => clearInterval(interval);
}, []);
const toggleMenu = () => setIsMenuOpen((s) => !s);
const handleLinkClick = (href: string) => {
setActiveLink(href);
setIsMenuOpen(false);
};
return (
<div className="relative w-full min-h-[360px] sm:min-h-[420px] rounded-3xl border border-border/80 bg-neutral-950 text-white overflow-hidden flex flex-col justify-between p-6 sm:p-8 select-none shadow-xl">
{/* Background ambient lighting */}
<div className="absolute inset-0 bg-[radial-gradient(ellipse_at_top_right,_var(--tw-gradient-stops))] from-neutral-800/40 via-neutral-950 to-neutral-950 -z-10" />
{/* ── CLOSED STATE HERO / HEADER ───────────────────────────────── */}
<div className="w-full flex items-center justify-between z-10">
<span className="text-xl font-bold tracking-tight text-white font-sans">
Studio<span className="text-neutral-500">.</span>
</span>
<div className="hidden sm:flex items-center gap-2 text-xs text-neutral-400 font-mono">
<span className="w-2 h-2 rounded-full bg-emerald-500 animate-pulse" />
<span>New York • {timeString || "12:00 PM"}</span>
</div>
{/* Hamburger trigger */}
<motion.button
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
onClick={toggleMenu}
aria-label={isMenuOpen ? "Close menu" : "Open menu"}
className="flex items-center gap-2 px-3 py-1.5 rounded-full border border-neutral-700 bg-neutral-900/80 hover:bg-neutral-800 text-xs font-medium transition-colors cursor-pointer"
>
<span>Menu</span>
<div className="w-4 h-3 flex flex-col justify-between">
<span className="w-full h-0.5 bg-white rounded-full" />
<span className="w-full h-0.5 bg-white rounded-full" />
</div>
</motion.button>
</div>
{/* Hero stage content inside preview */}
<div className="my-auto py-8 z-10">
<span className="text-[11px] font-mono uppercase tracking-widest text-neutral-500 mb-2 block">
Creative Agency
</span>
<h3 className="text-2xl sm:text-3xl font-light text-neutral-200 leading-tight max-w-lg mb-4">
Architects of modern digital experiences & brand identities.
</h3>
<button
onClick={toggleMenu}
className="inline-flex items-center gap-2 text-xs font-medium text-neutral-300 hover:text-white underline underline-offset-4 cursor-pointer"
>
Explore Navigation Overlay
<ArrowUpRight size={14} />
</button>
</div>
<div className="w-full flex items-center justify-between text-xs text-neutral-500 border-t border-neutral-800/80 pt-4 z-10 font-mono">
<span>© 2025 Studio Inc.</span>
<span className="hidden sm:inline-block">Click Menu to toggle full-screen overlay</span>
</div>
{/* ── FULL-PAGE OVERLAY ────────────────────────────────────────── */}
<AnimatePresence>
{isMenuOpen && (
<motion.div
initial={{ opacity: 0, y: "-100%" }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: "-100%" }}
transition={{ duration: 0.45, ease: [0.16, 1, 0.3, 1] }}
className="absolute inset-0 z-30 bg-neutral-950 text-white p-6 sm:p-8 flex flex-col justify-between overflow-hidden"
>
{/* Overlay Header */}
<div className="w-full flex items-center justify-between border-b border-neutral-800/80 pb-4">
<span className="text-xl font-bold tracking-tight text-white">
Studio<span className="text-neutral-500">.</span>
</span>
<div className="hidden sm:flex items-center gap-2 text-xs text-neutral-400 font-mono">
<span>New York • {timeString || "12:00 PM"}</span>
</div>
<motion.button
whileHover={{ scale: 1.08 }}
whileTap={{ scale: 0.95 }}
onClick={toggleMenu}
aria-label="Close menu"
className="flex items-center gap-2 px-3 py-1.5 rounded-full border border-neutral-700 bg-neutral-900 text-xs font-medium text-white hover:bg-neutral-800 transition-colors cursor-pointer"
>
<span>Close</span>
<X size={14} />
</motion.button>
</div>
{/* Overlay Content Grid */}
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6 items-center my-auto py-4">
{/* Left — Nav Items */}
<div className="space-y-2 sm:space-y-3">
{navItems.map((item, index) => {
const isHovered = hoveredItem === item.label;
const isActive = activeLink === item.href;
return (
<motion.div
key={item.label}
initial={{ opacity: 0, x: -20 }}
animate={{ opacity: 1, x: 0 }}
transition={{ delay: 0.08 + index * 0.05 }}
onMouseEnter={() => setHoveredItem(item.label)}
onMouseLeave={() => setHoveredItem(null)}
>
<button
onClick={() => handleLinkClick(item.href)}
className={`group flex items-center gap-3 text-2xl sm:text-3xl font-light transition-all cursor-pointer ${
isHovered || isActive
? "text-white font-normal translate-x-2"
: "text-neutral-500 hover:text-neutral-300"
}`}
>
<span>{item.label}</span>
<ChevronRight className={`w-5 h-5 transition-transform ${isHovered ? "translate-x-1 text-white" : "opacity-0"}`} />
</button>
</motion.div>
);
})}
</div>
{/* Right — Image Preview (Desktop) */}
<div className="hidden lg:block relative w-full h-48 xl:h-56 rounded-2xl overflow-hidden border border-neutral-800 bg-neutral-900">
<AnimatePresence mode="wait">
<motion.div
key={hoveredItem || activeLink}
initial={{ opacity: 0, scale: 0.95 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.95 }}
transition={{ duration: 0.25 }}
className="absolute inset-0"
>
<Image
src={
navItems.find(
(item) =>
item.label === hoveredItem ||
item.href === activeLink
)?.image || navItems[0].image
}
alt={hoveredItem || "Preview"}
fill
className="object-cover rounded-2xl"
sizes="(max-width: 1024px) 0px, 40vw"
/>
</motion.div>
</AnimatePresence>
</div>
</div>
{/* Overlay Footer */}
<div className="w-full flex items-center justify-between text-xs text-neutral-500 border-t border-neutral-800/80 pt-4 font-mono">
<span>hello@studio-agency.com</span>
<span className="hidden sm:inline-block">Click any item to select link</span>
</div>
</motion.div>
)}
</AnimatePresence>
</div>
);
}
export default FullPageNavbar;
This is the exact source file installed into your project. You own and control the code.