Navbar Agent
NavigationMarketing navbar for an AI/agent product — a starburst wordmark, hover-dropdown links, a primary CTA with a light sweep, and an animated mobile sheet. The bar fades to blurred glass as you scroll. Self-contained (the logo is inline SVG, no image assets); wordmark via `label`. Sits fixed over a light hero.
1280pxOpen
components/blocks/navbar-agent.tsx
"use client";
import { useEffect, useState } from "react";
import { AnimatePresence, motion, useScroll, useSpring } from "motion/react";
import { ArrowRight, Menu, X } from "lucide-react";
/** The Aurio starburst mark, inline so the block ships with no image assets. */
function AurioLogo({ className }: { className?: string }) {
return (
<svg viewBox="0 0 100 100" fill="none" role="img" aria-label="Logo" className={className}>
<g stroke="currentColor" strokeWidth={9} strokeLinecap="round">
{[0, 30, 60, 90, 120, 150].map((deg) => (
<line key={deg} x1="50" y1="7" x2="50" y2="93" transform={`rotate(${deg} 50 50)`} />
))}
</g>
</svg>
);
}
type NavLink = { href: string; label: string; children?: { href: string; label: string }[] };
const navLinks: NavLink[] = [
{ href: "#", label: "AI Marketer", children: [{ href: "#", label: "AI Marketer" }, { href: "#", label: "Pricing" }] },
{ href: "#", label: "MCP" },
{ href: "#", label: "Agency" },
{ href: "#", label: "AI SEO" },
{ href: "#", label: "About Us", children: [{ href: "#", label: "Our Story" }, { href: "#", label: "Case Studies" }, { href: "#", label: "Community" }] },
];
/**
* Marketing navbar for an AI/agent product — a wordmark, hover-dropdown links, a
* primary CTA with a light sweep, and an animated mobile sheet. The bar fades to
* a blurred glass as you scroll. Self-contained (inline brand mark, no image
* assets); accent via `brand`, wordmark via `label`. Meant to sit `fixed` over a
* light hero.
*/
export function NavbarAgent({ label = "Aurio" }: { label?: string }) {
const [isScrolled, setIsScrolled] = useState(false);
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
const { scrollY } = useScroll();
const smoothScrollY = useSpring(scrollY, { stiffness: 100, damping: 20, restDelta: 0.5 });
useEffect(() => {
const unsubscribe = smoothScrollY.on("change", (latest) => setIsScrolled(latest > 20));
return () => unsubscribe();
}, [smoothScrollY]);
return (
<div>
<motion.header
className="fixed top-0 right-0 left-0 z-50 px-5 py-3 sm:px-9 md:px-14 lg:px-20"
initial={{ backgroundColor: "rgba(255,255,255,0)" }}
animate={{
backgroundColor: isScrolled ? "rgba(255,255,255,0.1)" : "rgba(255,255,255,0)",
backdropFilter: isScrolled ? "blur(12px)" : "blur(0px)",
}}
transition={{ type: "spring", stiffness: 200, damping: 25 }}
>
<div className="mx-auto flex max-w-7xl items-center justify-between">
<motion.a
href="#"
className="flex items-center gap-2.5"
aria-label={`${label} home`}
animate={{ scale: isScrolled ? 0.95 : 1 }}
transition={{ type: "spring", stiffness: 200, damping: 15 }}
>
<AurioLogo className="h-8 w-8 text-neutral-950" />
<span className="text-lg font-bold text-black sm:text-2xl">{label}</span>
</motion.a>
<motion.nav
className="hidden items-center gap-4 text-sm font-medium text-neutral-700 lg:flex lg:gap-6"
animate={{ scale: isScrolled ? 0.9 : 1, opacity: isScrolled ? 0.9 : 1 }}
transition={{ type: "spring", stiffness: 200, damping: 15 }}
>
{navLinks.map((link) => (
<div key={link.label} className="group relative">
<a
href={link.href}
className="inline-block text-sm font-medium tracking-wide transition duration-200 hover:-translate-y-0.5 hover:text-neutral-950 lg:text-base"
>
{link.label}
</a>
{link.children && (
<div className="pointer-events-none absolute top-full left-1/2 z-50 min-w-44 origin-top -translate-x-1/2 scale-90 pt-3 opacity-0 transition-all duration-200 ease-out group-hover:pointer-events-auto group-hover:scale-100 group-hover:opacity-100">
<div className="rounded-xl border border-neutral-200/60 bg-white/95 p-2 shadow-lg backdrop-blur-md">
{link.children.map((child) => (
<a
key={child.label}
href={child.href}
className="block rounded-lg px-3 py-2 text-sm font-medium text-neutral-700 transition hover:bg-neutral-100 hover:text-neutral-950"
>
{child.label}
</a>
))}
</div>
</div>
)}
</div>
))}
</motion.nav>
<motion.a
href="#start"
className="group relative hidden h-10 items-center gap-1 overflow-hidden rounded-lg bg-neutral-950 px-4 text-sm font-medium text-white transition hover:bg-neutral-800 sm:px-5 lg:inline-flex"
animate={{ scale: isScrolled ? 0.92 : 1 }}
transition={{ type: "spring", stiffness: 200, damping: 15 }}
whileHover={{ scale: 1.02 }}
whileTap={{ scale: 0.98 }}
>
<span className="pointer-events-none absolute inset-y-1 -left-10 w-10 rounded-full bg-white/40 opacity-0 blur-md transition-all duration-500 ease-out group-hover:left-[calc(100%+0.5rem)] group-hover:opacity-100" />
<span className="relative z-10">Start now</span>
<ArrowRight size={16} className="relative z-10 transition-transform duration-200 group-hover:translate-x-0.5" />
</motion.a>
<button
className="flex items-center justify-center p-2 text-neutral-700 lg:hidden"
onClick={() => setIsMobileMenuOpen(true)}
aria-label="Open menu"
>
<Menu size={24} />
</button>
</div>
</motion.header>
<AnimatePresence>
{isMobileMenuOpen && (
<motion.div
className="fixed inset-0 z-50 flex flex-col bg-white/60 px-5 py-6 pt-24 backdrop-blur-lg sm:px-9 md:px-14 lg:px-20"
initial={{ opacity: 0, y: -20 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -20 }}
transition={{ type: "spring", stiffness: 300, damping: 30 }}
>
<button
className="absolute top-6 right-5 p-2 text-neutral-700 sm:right-9 md:right-14 lg:right-20"
onClick={() => setIsMobileMenuOpen(false)}
aria-label="Close menu"
>
<X size={24} />
</button>
<nav className="flex flex-col items-start gap-3 text-base font-medium text-neutral-700">
{navLinks.map((link, index) => (
<motion.div
key={link.label}
className="flex flex-col items-start gap-2"
initial={{ opacity: 0, x: -20 }}
animate={{ opacity: 1, x: 0 }}
transition={{ type: "spring", stiffness: 300, damping: 30, delay: index * 0.05 }}
>
<a href={link.href} className="transition hover:text-neutral-950" onClick={() => setIsMobileMenuOpen(false)}>
{link.label}
</a>
{link.children && (
<div className="flex flex-col items-start gap-2 pl-4 text-sm text-neutral-600">
{link.children.map((child) => (
<a key={child.label} href={child.href} className="transition hover:text-neutral-950" onClick={() => setIsMobileMenuOpen(false)}>
{child.label}
</a>
))}
</div>
)}
</motion.div>
))}
<a
href="#start"
onClick={() => setIsMobileMenuOpen(false)}
className="mt-4 inline-flex h-10 items-center gap-1 rounded-lg bg-neutral-950 px-5 text-sm font-medium text-white transition hover:bg-neutral-800"
>
Start now
<ArrowRight size={16} />
</a>
</nav>
</motion.div>
)}
</AnimatePresence>
</div>
);
}Installation
Terminal
npx shadcn@latest add https://ui.saumyarex.xyz/r/navbar-agent.jsonInstalls the block and its component dependencies in one step.
Install dependencies
Terminal
npm install motion lucide-reactCopy the source
components/blocks/navbar-agent.tsx
"use client";
import { useEffect, useState } from "react";
import { AnimatePresence, motion, useScroll, useSpring } from "motion/react";
import { ArrowRight, Menu, X } from "lucide-react";
/** The Aurio starburst mark, inline so the block ships with no image assets. */
function AurioLogo({ className }: { className?: string }) {
return (
<svg viewBox="0 0 100 100" fill="none" role="img" aria-label="Logo" className={className}>
<g stroke="currentColor" strokeWidth={9} strokeLinecap="round">
{[0, 30, 60, 90, 120, 150].map((deg) => (
<line key={deg} x1="50" y1="7" x2="50" y2="93" transform={`rotate(${deg} 50 50)`} />
))}
</g>
</svg>
);
}
type NavLink = { href: string; label: string; children?: { href: string; label: string }[] };
const navLinks: NavLink[] = [
{ href: "#", label: "AI Marketer", children: [{ href: "#", label: "AI Marketer" }, { href: "#", label: "Pricing" }] },
{ href: "#", label: "MCP" },
{ href: "#", label: "Agency" },
{ href: "#", label: "AI SEO" },
{ href: "#", label: "About Us", children: [{ href: "#", label: "Our Story" }, { href: "#", label: "Case Studies" }, { href: "#", label: "Community" }] },
];
/**
* Marketing navbar for an AI/agent product — a wordmark, hover-dropdown links, a
* primary CTA with a light sweep, and an animated mobile sheet. The bar fades to
* a blurred glass as you scroll. Self-contained (inline brand mark, no image
* assets); accent via `brand`, wordmark via `label`. Meant to sit `fixed` over a
* light hero.
*/
export function NavbarAgent({ label = "Aurio" }: { label?: string }) {
const [isScrolled, setIsScrolled] = useState(false);
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
const { scrollY } = useScroll();
const smoothScrollY = useSpring(scrollY, { stiffness: 100, damping: 20, restDelta: 0.5 });
useEffect(() => {
const unsubscribe = smoothScrollY.on("change", (latest) => setIsScrolled(latest > 20));
return () => unsubscribe();
}, [smoothScrollY]);
return (
<div>
<motion.header
className="fixed top-0 right-0 left-0 z-50 px-5 py-3 sm:px-9 md:px-14 lg:px-20"
initial={{ backgroundColor: "rgba(255,255,255,0)" }}
animate={{
backgroundColor: isScrolled ? "rgba(255,255,255,0.1)" : "rgba(255,255,255,0)",
backdropFilter: isScrolled ? "blur(12px)" : "blur(0px)",
}}
transition={{ type: "spring", stiffness: 200, damping: 25 }}
>
<div className="mx-auto flex max-w-7xl items-center justify-between">
<motion.a
href="#"
className="flex items-center gap-2.5"
aria-label={`${label} home`}
animate={{ scale: isScrolled ? 0.95 : 1 }}
transition={{ type: "spring", stiffness: 200, damping: 15 }}
>
<AurioLogo className="h-8 w-8 text-neutral-950" />
<span className="text-lg font-bold text-black sm:text-2xl">{label}</span>
</motion.a>
<motion.nav
className="hidden items-center gap-4 text-sm font-medium text-neutral-700 lg:flex lg:gap-6"
animate={{ scale: isScrolled ? 0.9 : 1, opacity: isScrolled ? 0.9 : 1 }}
transition={{ type: "spring", stiffness: 200, damping: 15 }}
>
{navLinks.map((link) => (
<div key={link.label} className="group relative">
<a
href={link.href}
className="inline-block text-sm font-medium tracking-wide transition duration-200 hover:-translate-y-0.5 hover:text-neutral-950 lg:text-base"
>
{link.label}
</a>
{link.children && (
<div className="pointer-events-none absolute top-full left-1/2 z-50 min-w-44 origin-top -translate-x-1/2 scale-90 pt-3 opacity-0 transition-all duration-200 ease-out group-hover:pointer-events-auto group-hover:scale-100 group-hover:opacity-100">
<div className="rounded-xl border border-neutral-200/60 bg-white/95 p-2 shadow-lg backdrop-blur-md">
{link.children.map((child) => (
<a
key={child.label}
href={child.href}
className="block rounded-lg px-3 py-2 text-sm font-medium text-neutral-700 transition hover:bg-neutral-100 hover:text-neutral-950"
>
{child.label}
</a>
))}
</div>
</div>
)}
</div>
))}
</motion.nav>
<motion.a
href="#start"
className="group relative hidden h-10 items-center gap-1 overflow-hidden rounded-lg bg-neutral-950 px-4 text-sm font-medium text-white transition hover:bg-neutral-800 sm:px-5 lg:inline-flex"
animate={{ scale: isScrolled ? 0.92 : 1 }}
transition={{ type: "spring", stiffness: 200, damping: 15 }}
whileHover={{ scale: 1.02 }}
whileTap={{ scale: 0.98 }}
>
<span className="pointer-events-none absolute inset-y-1 -left-10 w-10 rounded-full bg-white/40 opacity-0 blur-md transition-all duration-500 ease-out group-hover:left-[calc(100%+0.5rem)] group-hover:opacity-100" />
<span className="relative z-10">Start now</span>
<ArrowRight size={16} className="relative z-10 transition-transform duration-200 group-hover:translate-x-0.5" />
</motion.a>
<button
className="flex items-center justify-center p-2 text-neutral-700 lg:hidden"
onClick={() => setIsMobileMenuOpen(true)}
aria-label="Open menu"
>
<Menu size={24} />
</button>
</div>
</motion.header>
<AnimatePresence>
{isMobileMenuOpen && (
<motion.div
className="fixed inset-0 z-50 flex flex-col bg-white/60 px-5 py-6 pt-24 backdrop-blur-lg sm:px-9 md:px-14 lg:px-20"
initial={{ opacity: 0, y: -20 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -20 }}
transition={{ type: "spring", stiffness: 300, damping: 30 }}
>
<button
className="absolute top-6 right-5 p-2 text-neutral-700 sm:right-9 md:right-14 lg:right-20"
onClick={() => setIsMobileMenuOpen(false)}
aria-label="Close menu"
>
<X size={24} />
</button>
<nav className="flex flex-col items-start gap-3 text-base font-medium text-neutral-700">
{navLinks.map((link, index) => (
<motion.div
key={link.label}
className="flex flex-col items-start gap-2"
initial={{ opacity: 0, x: -20 }}
animate={{ opacity: 1, x: 0 }}
transition={{ type: "spring", stiffness: 300, damping: 30, delay: index * 0.05 }}
>
<a href={link.href} className="transition hover:text-neutral-950" onClick={() => setIsMobileMenuOpen(false)}>
{link.label}
</a>
{link.children && (
<div className="flex flex-col items-start gap-2 pl-4 text-sm text-neutral-600">
{link.children.map((child) => (
<a key={child.label} href={child.href} className="transition hover:text-neutral-950" onClick={() => setIsMobileMenuOpen(false)}>
{child.label}
</a>
))}
</div>
)}
</motion.div>
))}
<a
href="#start"
onClick={() => setIsMobileMenuOpen(false)}
className="mt-4 inline-flex h-10 items-center gap-1 rounded-lg bg-neutral-950 px-5 text-sm font-medium text-white transition hover:bg-neutral-800"
>
Start now
<ArrowRight size={16} />
</a>
</nav>
</motion.div>
)}
</AnimatePresence>
</div>
);
}