Site Header
atroui/site-headerFreeBlock
Sticky site header with editable NAV and CTA.
Install it
npx shadcn@latest add https://atroui.com/r/site-header.jsonSource
1"use client"23import { ArrowRight, Menu, X } from "lucide-react"4import { AnimatePresence, motion, useReducedMotion } from "motion/react"5import Link from "next/link"6import { usePathname } from "next/navigation"7import { useEffect, useState } from "react"8import { createPortal } from "react-dom"910import { LogoWordmark } from "@/components/brand/logo"11import { getBrand } from "@/lib/brand"12import { cn } from "@/lib/utils"13import { ThemeToggle } from "@/components/ui/theme-toggle"1415/** Edit nav labels and hrefs freely after install. */16const NAV = [17 { label: "Work", href: "/work" },18 { label: "Tools", href: "/tools" },19 { label: "Services", href: "/services" },20 { label: "Journal", href: "/journal" },21 { label: "About", href: "/about" },22] as const2324const CTA = { label: "Hire us", href: "/contact" }2526const panelEase = [0.32, 0.72, 0, 1] as const // easeOutSoft — match apps/docs/lib/motion.ts2728function isActive(pathname: string, href: string) {29 return pathname === href || pathname.startsWith(`${href}/`)30}3132/**33 * iOS-safe lock — same contract as apps/docs/hooks/use-body-scroll-lock.ts.34 * Inlined so the registry item stays self-contained after install.35 */36function useBodyScrollLock(locked: boolean) {37 useEffect(() => {38 if (!locked) return39 const y = window.scrollY40 const { style } = document.body41 const prev = {42 overflow: style.overflow,43 position: style.position,44 top: style.top,45 width: style.width,46 left: style.left,47 right: style.right,48 }49 style.overflow = "hidden"50 style.position = "fixed"51 style.top = `-${y}px`52 style.left = "0"53 style.right = "0"54 style.width = "100%"55 return () => {56 style.overflow = prev.overflow57 style.position = prev.position58 style.top = prev.top59 style.width = prev.width60 style.left = prev.left61 style.right = prev.right62 window.scrollTo(0, y)63 }64 }, [locked])65}6667export function SiteHeader() {68 const pathname = usePathname()69 const [open, setOpen] = useState(false)70 const [mounted, setMounted] = useState(false)71 const [scrolled, setScrolled] = useState(false)72 const reduce = useReducedMotion()73 const brandName = getBrand().name7475 useEffect(() => {76 setMounted(true)77 }, [])7879 useEffect(() => {80 setOpen(false)81 }, [pathname])8283 useEffect(() => {84 const onScroll = () => setScrolled(window.scrollY > 8)85 onScroll()86 window.addEventListener("scroll", onScroll, { passive: true })87// … truncated
What it pulls in
npm packages
Other registry items
Files it writes
More from atroui
All 82 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Analytics Provideranalytics-provider | atroui | Blocks | Free | 1 dep | |
| AR Portfolioar-portfolio | atroui | Blocks | Free | 1 dep | |
| Before / Afterbefore-after-slider | atroui | Blocks | Free | no deps | |
| Calendly Embedcalendly-embed | atroui | Blocks | Free | 1 dep | |
| Changelogchangelog | atroui | Blocks | Free | no deps | |
| Command Menucommand-menu | atroui | Blocks | Free | 4 deps | |
| Contact Formcontact-form | atroui | Blocks | Free | 2 deps | |
| Contextual CTAcontextual-cta | atroui | Blocks | Free | 2 deps |
