Header
blockmarketingSite header collection: sticky top bar, dismissible announcement stack, centered-logo split, floating pill, full-width mega menu, inline search with command palette, and a transparent-over-hero scroll variant — each with a mobile sheet fallback.
Installation
$pnpm dlx shadcn@latest add https://uipkge.dev/r/react/header.json$npx shadcn@latest add https://uipkge.dev/r/react/header.json$yarn dlx shadcn@latest add https://uipkge.dev/r/react/header.json$bunx shadcn@latest add https://uipkge.dev/r/react/header.jsonNamed registry:
npx shadcn@latest add @uipkge-react/headerInstalls to:components/blocks/header/Variants
Loading interactive previews…
Loading interactive previews…
npm dependencies
Files installed (7)
components/blocks/header/Header01.tsx4.7 kB
'use client' import * as React from 'react' import { Boxes, Menu, X } from 'lucide-react' import { Button } from '@/components/ui/button' import { Sheet, SheetContent, SheetTrigger } from '@/components/ui/sheet' export function Header01() { const [mobileOpen, setMobileOpen] = React.useState(false) return ( <header data-slot="header-01" className="bg-background/80 supports-[backdrop-filter]:bg-background/60 sticky top-0 z-40 border-b backdrop-blur" > <div className="mx-auto flex h-16 max-w-6xl items-center justify-between px-6"> <a href="#" className="flex items-center gap-2"> <div className="bg-primary text-primary-foreground flex size-8 items-center justify-center rounded-md"> <Boxes className="size-4" /> </div> <span className="text-base font-semibold">Acme</span> </a> <nav className="hidden items-center gap-6 md:flex" aria-label="Primary"> <a href="#features" className="text-muted-foreground hover:text-foreground text-sm transition-colors"> Features </a> <a href="#pricing" className="text-muted-foreground hover:text-foreground text-sm transition-colors"> Pricing </a> <a href="#customers" className="text-muted-foreground hover:text-foreground text-sm transition-colors"> Customers </a> <a href="#docs" className="text-muted-foreground hover:text-foreground text-sm transition-colors"> Docs </a> <a href="#blog" className="text-muted-foreground hover:text-foreground text-sm transition-colors"> Blog </a> </nav> <div className="hidden items-center gap-2 md:flex"> <Button variant="ghost" size="sm"> Sign in </Button> <Button size="sm">Start free trial</Button> </div> <Sheet open={mobileOpen} onOpenChange={setMobileOpen}> <SheetTrigger asChild> <Button variant="ghost" size="icon" className="md:hidden" aria-label="Open menu"> <Menu className="size-5" /> </Button> </SheetTrigger> <SheetContent side="right" className="w-72"> <div className="flex h-full flex-col"> <div className="flex items-center justify-between border-b px-4 py-3"> <div className="flex items-center gap-2"> <div className="bg-primary text-primary-foreground flex size-7 items-center justify-center rounded-md"> <Boxes className="size-3.5" /> </div> <span className="text-sm font-semibold">Acme</span> </div> <Button variant="ghost" size="icon" className="size-8" aria-label="Close menu" onClick={() => setMobileOpen(false)} > <X className="size-4" /> </Button> </div> <nav className="flex flex-1 flex-col gap-1 p-4" aria-label="Mobile"> <a href="#features" className="hover:bg-muted rounded-md px-3 py-2 text-sm transition-colors" onClick={() => setMobileOpen(false)} > Features </a> <a href="#pricing" className="hover:bg-muted rounded-md px-3 py-2 text-sm transition-colors" onClick={() => setMobileOpen(false)} > Pricing </a> <a href="#customers" className="hover:bg-muted rounded-md px-3 py-2 text-sm transition-colors" onClick={() => setMobileOpen(false)} > Customers </a> <a href="#docs" className="hover:bg-muted rounded-md px-3 py-2 text-sm transition-colors" onClick={() => setMobileOpen(false)} > Docs </a> <a href="#blog" className="hover:bg-muted rounded-md px-3 py-2 text-sm transition-colors" onClick={() => setMobileOpen(false)} > Blog </a> </nav> <div className="flex flex-col gap-2 border-t p-4"> <Button variant="outline" className="w-full"> Sign in </Button> <Button className="w-full">Start free trial</Button> </div> </div> </SheetContent> </Sheet> </div> </header> ) }components/blocks/header/HeaderAnnouncementStack.tsx4.6 kB
'use client' import { useEffect, useState } from 'react' import { ArrowRight, Menu, Layers, X } from 'lucide-react' import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' import { Separator } from '@/components/ui/separator' import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger } from '@/components/ui/sheet' const STORAGE_KEY = 'uipkge:announcement-dismissed' const links = [ { label: 'Platform', href: '#platform' }, { label: 'Pricing', href: '#pricing' }, { label: 'Customers', href: '#customers' }, { label: 'Docs', href: '#docs' }, ] export function HeaderAnnouncementStack() { // Rendered on the server and dismissed only on the client, so there is no // flash of a strip that then vanishes. const [dismissed, setDismissed] = useState(false) const [open, setOpen] = useState(false) useEffect(() => { try { setDismissed(window.sessionStorage.getItem(STORAGE_KEY) === '1') } catch { setDismissed(false) } }, []) function dismiss() { setDismissed(true) try { window.sessionStorage.setItem(STORAGE_KEY, '1') } catch { // Blocked storage: the dismissal still holds for this page view. } } return ( <div data-slot="header-announcement-stack" className="sticky top-0 z-40"> {!dismissed && ( <div className="border-border bg-muted/60 border-b backdrop-blur"> <div className="mx-auto flex h-10 max-w-6xl items-center gap-3 px-6 text-sm"> <Badge variant="secondary" className="shrink-0"> New </Badge> <p className="min-w-0 truncate"> Row-level scoping now evaluates against SCIM groups.{' '} <a href="#changelog" className="hover:text-foreground underline underline-offset-4"> Read the changelog </a> </p> <ArrowRight className="text-muted-foreground hidden size-3.5 shrink-0 sm:block" aria-hidden="true" /> <Button variant="ghost" size="icon" className="ml-auto size-7 shrink-0" aria-label="Dismiss announcement" onClick={dismiss} > <X className="size-3.5" aria-hidden="true" /> </Button> </div> </div> )} <header className="border-border bg-background/90 border-b backdrop-blur"> <div className="mx-auto flex h-16 max-w-6xl items-center gap-6 px-6"> <a href="#top" className="flex shrink-0 items-center gap-2 font-semibold tracking-tight"> <Layers className="text-primary size-5" aria-hidden="true" /> Northwind </a> <nav className="hidden items-center gap-1 md:flex" aria-label="Primary"> {links.map((link) => ( <a key={link.href} href={link.href} className="text-muted-foreground hover:text-foreground hover:bg-muted focus-visible:ring-ring rounded-md px-3 py-1.5 text-sm font-medium transition-colors focus-visible:ring-2 focus-visible:outline-none" > {link.label} </a> ))} </nav> <div className="ml-auto hidden items-center gap-2 md:flex"> <Button variant="ghost" size="sm"> Sign in </Button> <Button size="sm">Book a demo</Button> </div> <Sheet open={open} onOpenChange={setOpen}> <SheetTrigger asChild> <Button variant="ghost" size="icon" className="ml-auto md:hidden" aria-label="Open navigation menu"> <Menu className="size-5" aria-hidden="true" /> </Button> </SheetTrigger> <SheetContent side="right" className="w-72"> <SheetHeader> <SheetTitle>Menu</SheetTitle> </SheetHeader> <nav className="mt-6 grid gap-1" aria-label="Mobile"> {links.map((link) => ( <a key={link.href} href={link.href} className="hover:bg-muted rounded-md px-3 py-2 text-sm font-medium transition-colors" onClick={() => setOpen(false)} > {link.label} </a> ))} </nav> <Separator className="my-5" /> <div className="grid gap-2"> <Button variant="outline">Sign in</Button> <Button>Book a demo</Button> </div> </SheetContent> </Sheet> </div> </header> </div> ) }components/blocks/header/HeaderCenteredLogo.tsx3.4 kB
'use client' import { useState } from 'react' import { Compass, Menu, ShoppingBag, User } from 'lucide-react' import { Button } from '@/components/ui/button' import { Separator } from '@/components/ui/separator' import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger } from '@/components/ui/sheet' const leftLinks = [ { label: 'Collections', href: '#collections' }, { label: 'New in', href: '#new' }, { label: 'Studio', href: '#studio' }, ] const rightLinks = [ { label: 'Journal', href: '#journal' }, { label: 'Stockists', href: '#stockists' }, { label: 'Contact', href: '#contact' }, ] const linkClass = 'text-muted-foreground hover:text-foreground focus-visible:ring-ring rounded-md px-3 py-1.5 text-sm font-medium transition-colors focus-visible:ring-2 focus-visible:outline-none' export function HeaderCenteredLogo() { const [open, setOpen] = useState(false) return ( <header data-slot="header-centered-logo" className="border-border bg-background border-b"> <div className="mx-auto flex h-16 max-w-6xl items-center px-6"> {/* Equal-basis flanks keep the wordmark optically centred regardless of how long the link labels are. */} <nav className="hidden flex-1 basis-0 items-center gap-1 lg:flex" aria-label="Primary left"> {leftLinks.map((link) => ( <a key={link.href} href={link.href} className={linkClass}> {link.label} </a> ))} </nav> <Sheet open={open} onOpenChange={setOpen}> <SheetTrigger asChild> <Button variant="ghost" size="icon" className="lg:hidden" aria-label="Open navigation menu"> <Menu className="size-5" aria-hidden="true" /> </Button> </SheetTrigger> <SheetContent side="left" className="w-72"> <SheetHeader> <SheetTitle>Menu</SheetTitle> </SheetHeader> <nav className="mt-6 grid gap-1" aria-label="Mobile"> {[...leftLinks, ...rightLinks].map((link) => ( <a key={link.href} href={link.href} className="hover:bg-muted rounded-md px-3 py-2 text-sm font-medium transition-colors" onClick={() => setOpen(false)} > {link.label} </a> ))} </nav> <Separator className="my-5" /> <Button className="w-full">Account</Button> </SheetContent> </Sheet> <a href="#top" className="mx-auto flex items-center gap-2 text-base font-semibold tracking-[0.18em] uppercase lg:mx-6" > <Compass className="text-primary size-4" aria-hidden="true" /> Halden </a> <nav className="hidden flex-1 basis-0 items-center justify-end gap-1 lg:flex" aria-label="Primary right"> {rightLinks.map((link) => ( <a key={link.href} href={link.href} className={linkClass}> {link.label} </a> ))} </nav> <div className="flex items-center gap-1 lg:ml-4"> <Button variant="ghost" size="icon" aria-label="Account"> <User className="size-4" aria-hidden="true" /> </Button> <Button variant="ghost" size="icon" aria-label="Bag"> <ShoppingBag className="size-4" aria-hidden="true" /> </Button> </div> </div> </header> ) }components/blocks/header/HeaderFloatingPill.tsx4 kB
'use client' import { useCallback, useEffect, useRef, useState } from 'react' import { CircleDot, Menu } from 'lucide-react' import { Button } from '@/components/ui/button' import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger } from '@/components/ui/sheet' const links = [ { label: 'Product', href: '#product' }, { label: 'Pricing', href: '#pricing' }, { label: 'Customers', href: '#customers' }, { label: 'Docs', href: '#docs' }, ] export function HeaderFloatingPill() { const [active, setActive] = useState(0) const [open, setOpen] = useState(false) const navRef = useRef<HTMLElement | null>(null) // Measured from the live element, so the indicator fits any label length or // font — no hard-coded widths to drift out of sync with the copy. const [indicator, setIndicator] = useState({ left: 0, width: 0 }) const measure = useCallback( (index = active) => { const el = navRef.current?.querySelectorAll<HTMLElement>('[data-pill-link]')[index] if (el) setIndicator({ left: el.offsetLeft, width: el.offsetWidth }) }, [active], ) useEffect(() => { measure() const nav = navRef.current if (!nav || typeof ResizeObserver === 'undefined') return const observer = new ResizeObserver(() => measure()) observer.observe(nav) return () => observer.disconnect() }, [measure]) return ( <div data-slot="header-floating-pill" className="pointer-events-none sticky top-0 z-40 px-4 pt-4"> <header className="border-border bg-card/85 pointer-events-auto mx-auto flex h-14 max-w-4xl items-center gap-3 rounded-full border px-3 shadow-sm backdrop-blur"> <a href="#top" className="flex shrink-0 items-center gap-2 pl-2 font-semibold tracking-tight"> <CircleDot className="text-primary size-4" aria-hidden="true" /> Verity </a> <nav ref={navRef} className="relative hidden items-center md:flex" aria-label="Primary"> <span className="bg-muted absolute inset-y-1 rounded-full transition-colors duration-200 ease-out" style={{ left: `${indicator.left}px`, width: `${indicator.width}px` }} aria-hidden="true" /> {links.map((link, index) => ( <a key={link.href} href={link.href} data-pill-link className={`focus-visible:ring-ring relative rounded-full px-3.5 py-1.5 text-sm font-medium transition-colors focus-visible:ring-2 focus-visible:outline-none ${ index === active ? 'text-foreground' : 'text-muted-foreground hover:text-foreground' }`} aria-current={index === active ? 'page' : undefined} onMouseEnter={() => measure(index)} onMouseLeave={() => measure()} onFocus={() => measure(index)} onBlur={() => measure()} onClick={() => setActive(index)} > {link.label} </a> ))} </nav> <Button size="sm" className="ml-auto rounded-full"> Start free </Button> <Sheet open={open} onOpenChange={setOpen}> <SheetTrigger asChild> <Button variant="ghost" size="icon" className="rounded-full md:hidden" aria-label="Open navigation menu"> <Menu className="size-5" aria-hidden="true" /> </Button> </SheetTrigger> <SheetContent side="top"> <SheetHeader> <SheetTitle>Menu</SheetTitle> </SheetHeader> <nav className="mt-6 grid gap-1" aria-label="Mobile"> {links.map((link) => ( <a key={link.href} href={link.href} className="hover:bg-muted rounded-md px-3 py-2 text-sm font-medium transition-colors" onClick={() => setOpen(false)} > {link.label} </a> ))} </nav> </SheetContent> </Sheet> </header> </div> ) }components/blocks/header/HeaderMegaMenu.tsx8.4 kB
'use client' import { useState } from 'react' import { ArrowRight, BarChart3, BookOpen, Boxes, LifeBuoy, Lock, Menu, Layers, Workflow } from 'lucide-react' import { Button } from '@/components/ui/button' import { NavigationMenu, NavigationMenuContent, NavigationMenuItem, NavigationMenuList, NavigationMenuTrigger, navigationMenuTriggerStyle, } from '@/components/ui/navigation-menu' import { Separator } from '@/components/ui/separator' import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger } from '@/components/ui/sheet' const menus = [ { label: 'Product', groups: [ { heading: 'Core', items: [ { icon: Boxes, title: 'Metric layer', body: 'Versioned definitions your whole org shares.' }, { icon: BarChart3, title: 'Dashboards', body: 'Composed from certified metrics, not raw SQL.' }, { icon: Workflow, title: 'Pipelines', body: 'Scheduled materialisation with cost ceilings.' }, ], }, { heading: 'Governance', items: [ { icon: Lock, title: 'Row-level access', body: 'Scope evaluated per query, per identity.' }, { icon: BookOpen, title: 'Change history', body: 'Every definition edit reviewed and revertible.' }, { icon: LifeBuoy, title: 'Audit exports', body: 'Generated from the same history, not by hand.' }, ], }, ], highlight: { title: 'Ship your first dashboard today', body: 'Connect a warehouse, publish one certified metric, and invite the team. No migration required.', cta: 'Start the walkthrough', }, }, { label: 'Resources', groups: [ { heading: 'Learn', items: [ { icon: BookOpen, title: 'Documentation', body: 'Setup, modelling, and the access model.' }, { icon: Layers, title: 'Guides', body: 'Reconciliation and first-close checklists.' }, { icon: BarChart3, title: 'Benchmarks', body: 'Close speed across 240 finance teams.' }, ], }, { heading: 'Support', items: [ { icon: LifeBuoy, title: 'Help centre', body: 'Answers to the questions support gets most.' }, { icon: Workflow, title: 'Status', body: 'Live uptime and incident history.' }, { icon: Lock, title: 'Trust centre', body: 'SOC 2, subprocessors, and data residency.' }, ], }, ], highlight: { title: 'Read the rollout plan', body: 'The five-week implementation we run for every customer, written down so you can run it yourself.', cta: 'Open the plan', }, }, ] const plainLinks = [ { label: 'Pricing', href: '#pricing' }, { label: 'Customers', href: '#customers' }, ] export function HeaderMegaMenu() { const [open, setOpen] = useState(false) return ( <header data-slot="header-mega-menu" className="border-border bg-background/90 border-b backdrop-blur"> <div className="mx-auto flex h-16 max-w-6xl items-center gap-6 px-6"> <a href="#top" className="flex shrink-0 items-center gap-2 font-semibold tracking-tight"> <Layers className="text-primary size-5" aria-hidden="true" /> Northwind </a> <NavigationMenu className="hidden lg:flex"> <NavigationMenuList> {menus.map((menu) => ( <NavigationMenuItem key={menu.label}> <NavigationMenuTrigger>{menu.label}</NavigationMenuTrigger> <NavigationMenuContent> <div className="grid w-[46rem] grid-cols-[1fr_1fr_16rem] gap-6 p-6"> {menu.groups.map((group) => ( <div key={group.heading}> <p className="text-muted-foreground font-mono text-xs tracking-[0.14em] uppercase"> {group.heading} </p> <ul className="mt-3 space-y-1"> {group.items.map((item) => ( <li key={item.title}> <a href="#" className="hover:bg-muted focus-visible:ring-ring flex gap-3 rounded-md p-2 transition-colors focus-visible:ring-2 focus-visible:outline-none" > <item.icon className="text-muted-foreground mt-0.5 size-4 shrink-0" aria-hidden="true" /> <span className="min-w-0"> <span className="block text-sm font-medium">{item.title}</span> <span className="text-muted-foreground block text-xs leading-snug">{item.body}</span> </span> </a> </li> ))} </ul> </div> ))} {/* Highlight rail: one promoted destination per panel, on the muted surface so it reads as an aside, not a sixth link. */} <div className="bg-muted/50 flex flex-col rounded-lg p-4"> <p className="text-sm font-semibold">{menu.highlight.title}</p> <p className="text-muted-foreground mt-2 text-xs leading-relaxed">{menu.highlight.body}</p> <Button variant="link" className="mt-auto h-auto justify-start p-0 pt-4 text-xs"> {menu.highlight.cta} <ArrowRight className="ml-1 size-3" aria-hidden="true" /> </Button> </div> </div> </NavigationMenuContent> </NavigationMenuItem> ))} {plainLinks.map((link) => ( <NavigationMenuItem key={link.href}> <a href={link.href} className={navigationMenuTriggerStyle()}> {link.label} </a> </NavigationMenuItem> ))} </NavigationMenuList> </NavigationMenu> <div className="ml-auto flex items-center gap-2"> <Button variant="ghost" size="sm" className="hidden sm:inline-flex"> Sign in </Button> <Separator orientation="vertical" className="hidden h-5 sm:block" /> <Button size="sm">Book a demo</Button> </div> <Sheet open={open} onOpenChange={setOpen}> <SheetTrigger asChild> <Button variant="ghost" size="icon" className="ml-auto lg:hidden" aria-label="Open navigation menu"> <Menu className="size-5" aria-hidden="true" /> </Button> </SheetTrigger> <SheetContent side="right" className="w-72 overflow-y-auto"> <SheetHeader> <SheetTitle>Menu</SheetTitle> </SheetHeader> <nav className="mt-6 grid gap-5" aria-label="Mobile"> {menus.map((menu) => ( <div key={menu.label}> <p className="text-muted-foreground/70 text-xs font-medium tracking-wide uppercase">{menu.label}</p> <ul className="mt-2 grid gap-1"> {menu.groups.map((group) => group.items.map((item) => ( <li key={item.title}> <a href="#" className="hover:bg-muted block rounded-md px-3 py-2 text-sm font-medium transition-colors" onClick={() => setOpen(false)} > {item.title} </a> </li> )), )} </ul> </div> ))} <Separator /> {plainLinks.map((link) => ( <a key={link.href} href={link.href} className="hover:bg-muted rounded-md px-3 py-2 text-sm font-medium transition-colors" onClick={() => setOpen(false)} > {link.label} </a> ))} <Separator /> <div className="grid gap-2"> <Button variant="outline">Sign in</Button> <Button>Book a demo</Button> </div> </nav> </SheetContent> </Sheet> </div> </header> ) }components/blocks/header/HeaderSearchCommand.tsx5.1 kB
'use client' import { useEffect, useState } from 'react' import { BarChart3, BookOpen, Compass, FileText, History, Menu, Search, Users } from 'lucide-react' import { Button } from '@/components/ui/button' import { CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, } from '@/components/ui/command' import { Kbd } from '@/components/ui/kbd' import { Separator } from '@/components/ui/separator' import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger } from '@/components/ui/sheet' const links = [ { label: 'Product', href: '#product' }, { label: 'Pricing', href: '#pricing' }, { label: 'Docs', href: '#docs' }, ] const groups = [ { heading: 'Documentation', items: [ { icon: BookOpen, label: 'Connect a warehouse' }, { icon: FileText, label: 'Define your first metric' }, { icon: BarChart3, label: 'Publish a dashboard' }, ], }, { heading: 'Company', items: [ { icon: Users, label: 'Customer stories' }, { icon: History, label: 'Changelog' }, ], }, ] export function HeaderSearchCommand() { const [open, setOpen] = useState(false) const [menuOpen, setMenuOpen] = useState(false) useEffect(() => { const onKeydown = (event: KeyboardEvent) => { if (event.key.toLowerCase() !== 'k' || !(event.metaKey || event.ctrlKey)) return event.preventDefault() setOpen((value) => !value) } window.addEventListener('keydown', onKeydown) return () => window.removeEventListener('keydown', onKeydown) }, []) return ( <header data-slot="header-search-command" className="border-border bg-background/90 border-b backdrop-blur"> <div className="mx-auto flex h-16 max-w-6xl items-center gap-4 px-6"> <a href="#top" className="flex shrink-0 items-center gap-2 font-semibold tracking-tight"> <Compass className="text-primary size-5" aria-hidden="true" /> Halden </a> <nav className="hidden items-center gap-1 md:flex" aria-label="Primary"> {links.map((link) => ( <a key={link.href} href={link.href} className="text-muted-foreground hover:text-foreground hover:bg-muted focus-visible:ring-ring rounded-md px-3 py-1.5 text-sm font-medium transition-colors focus-visible:ring-2 focus-visible:outline-none" > {link.label} </a> ))} </nav> {/* Trigger is a button, not an input: the real field lives in the dialog, so focus lands there and the shortcut hint stays visible until then. */} <button type="button" className="border-border bg-muted/40 text-muted-foreground hover:bg-muted focus-visible:ring-ring ml-auto flex h-9 w-full max-w-64 items-center gap-2 rounded-md border px-3 text-sm transition-colors focus-visible:ring-2 focus-visible:outline-none" onClick={() => setOpen(true)} > <Search className="size-4 shrink-0" aria-hidden="true" /> <span className="truncate">Search docs…</span> <Kbd className="ml-auto hidden sm:inline-flex">⌘K</Kbd> </button> <Separator orientation="vertical" className="hidden h-5 md:block" /> <Button size="sm" className="hidden shrink-0 sm:inline-flex"> Start free </Button> <Sheet open={menuOpen} onOpenChange={setMenuOpen}> <SheetTrigger asChild> <Button variant="ghost" size="icon" className="shrink-0 md:hidden" aria-label="Open navigation menu"> <Menu className="size-5" aria-hidden="true" /> </Button> </SheetTrigger> <SheetContent side="right" className="w-72"> <SheetHeader> <SheetTitle>Menu</SheetTitle> </SheetHeader> <nav className="mt-6 grid gap-1" aria-label="Mobile"> {links.map((link) => ( <a key={link.href} href={link.href} className="hover:bg-muted rounded-md px-3 py-2 text-sm font-medium transition-colors" onClick={() => setMenuOpen(false)} > {link.label} </a> ))} </nav> <Separator className="my-5" /> <div className="grid gap-2"> <Button variant="outline">Sign in</Button> <Button>Start free</Button> </div> </SheetContent> </Sheet> </div> <CommandDialog open={open} onOpenChange={setOpen}> <CommandInput placeholder="Search documentation, guides, and stories…" /> <CommandList> <CommandEmpty>No results.</CommandEmpty> {groups.map((group) => ( <CommandGroup key={group.heading} heading={group.heading}> {group.items.map((item) => ( <CommandItem key={item.label} value={item.label}> <item.icon className="text-muted-foreground mr-2 size-4" aria-hidden="true" /> {item.label} </CommandItem> ))} </CommandGroup> ))} </CommandList> </CommandDialog> </header> ) }components/blocks/header/HeaderTransparentScroll.tsx3.4 kB
'use client' import { useEffect, useState } from 'react' import { Menu, Layers } from 'lucide-react' import { Button } from '@/components/ui/button' import { Separator } from '@/components/ui/separator' import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger } from '@/components/ui/sheet' const links = [ { label: 'Product', href: '#product' }, { label: 'Solutions', href: '#solutions' }, { label: 'Pricing', href: '#pricing' }, { label: 'Docs', href: '#docs' }, ] export function HeaderTransparentScroll() { // Starts unscrolled so server and first client paint agree; the listener is // the only thing that swaps in the solid surface. const [scrolled, setScrolled] = useState(false) const [open, setOpen] = useState(false) useEffect(() => { const onScroll = () => setScrolled(window.scrollY > 24) onScroll() window.addEventListener('scroll', onScroll, { passive: true }) return () => window.removeEventListener('scroll', onScroll) }, []) return ( <header data-slot="header-transparent-scroll" className={`fixed inset-x-0 top-0 z-40 transition-colors duration-200 ${ scrolled ? 'border-border bg-background/85 border-b backdrop-blur' : 'border-b border-transparent' }`} > <div className="mx-auto flex h-16 max-w-6xl items-center gap-6 px-6"> <a href="#top" className="flex items-center gap-2 font-semibold tracking-tight"> <Layers className="text-primary size-5" aria-hidden="true" /> Northwind </a> <nav className="hidden items-center gap-1 md:flex" aria-label="Primary"> {links.map((link) => ( <a key={link.href} href={link.href} className="text-muted-foreground hover:text-foreground hover:bg-muted focus-visible:ring-ring rounded-md px-3 py-1.5 text-sm font-medium transition-colors focus-visible:ring-2 focus-visible:outline-none" > {link.label} </a> ))} </nav> <div className="ml-auto hidden items-center gap-2 md:flex"> <Button variant="ghost" size="sm"> Sign in </Button> <Button size="sm">Start free</Button> </div> <Sheet open={open} onOpenChange={setOpen}> <SheetTrigger asChild> <Button variant="ghost" size="icon" className="ml-auto md:hidden" aria-label="Open navigation menu"> <Menu className="size-5" aria-hidden="true" /> </Button> </SheetTrigger> <SheetContent side="right" className="w-72"> <SheetHeader> <SheetTitle>Menu</SheetTitle> </SheetHeader> <nav className="mt-6 grid gap-1" aria-label="Mobile"> {links.map((link) => ( <a key={link.href} href={link.href} className="hover:bg-muted rounded-md px-3 py-2 text-sm font-medium transition-colors" onClick={() => setOpen(false)} > {link.label} </a> ))} </nav> <Separator className="my-5" /> <div className="grid gap-2"> <Button variant="outline">Sign in</Button> <Button>Start free</Button> </div> </SheetContent> </Sheet> </div> </header> ) }
Raw manifest:https://uipkge.dev/r/react/header.json