Fullscreen Menu Nav
Fullscreen menu navbar: a burger opens an overlay with giant links that reveal line by line and a project photo on hover.
- Navbars
- Architecture
- React only · 0 deps
- 1 file
Browser support · All evergreen browsers (clip-path inset animations, Intl time zones for the office clocks).
Install. One command, or copy the file.
$
npx shadcn@latest add https://freedesignmd.com/r/fullscreen-menu-nav.json- Byte-identical to the preview
- No Tailwind or config needed
- SSR-safe · keyboard accessible
- Respects reduced motion & transparency
components/navbars/fullscreen-menu-nav.tsx
1/**2 * FullscreenMenuNav, an architecture studio header whose burger opens a3 * fullscreen overlay. Giant stacked links reveal line by line through a4 * clip-path mask; hovering or focusing a link wipes in a project photograph5 * with its index number, name and year. The burger morphs into an X and the6 * "Menu" label rolls to "Close".7 *8 * Props: studio, tagline, offices (name + IANA time zone, shown as live9 * clocks), items (label, href, project { src, alt, name, place, year }),10 * contact lines.11 * CSS vars: --fd-fsm-paper, --fd-fsm-ink, --fd-fsm-night.12 *13 * Browser support: all evergreen browsers (clip-path inset).14 * Accessibility: the button has aria-expanded/aria-controls; the overlay is a15 * modal dialog with a focus trap, Escape closes it and returns focus. Photos16 * are decorative (the caption carries the information as text).17 * Reduced motion: overlay and links appear with a short fade, photos swap18 * without wiping.19 */20import { useEffect, useId, useRef, useState } from "react";21 22export interface FsmProject { src: string; alt: string; name: string; place: string; year: string }23export interface FsmItem { label: string; href: string; project: FsmProject }24export interface FullscreenMenuNavProps {25 studio?: string;26 tagline?: string;27 offices?: { name: string; tz: string }[];28 items?: FsmItem[];29 contact?: string[];30 className?: string;31}32 33const ITEMS: FsmItem[] = [34 { label: "Work", href: "#work", project: { src: "/img/halcyon/courtyard-pool-900.webp", alt: "", name: "Casa dei Limoni", place: "Praiano", year: "2024" } },35 { label: "Studio", href: "#studio", project: { src: "/img/halcyon/journals-900.webp", alt: "", name: "The drawing archive", place: "Via Roma 14", year: "1998" } },36 { label: "Practice", href: "#practice", project: { src: "/img/halcyon/ryokan-900.webp", alt: "", name: "Hanare guest house", place: "Kyoto", year: "2021" } },37 { label: "Journal", href: "#journal", project: { src: "/img/halcyon/suite-900.webp", alt: "", name: "Suite 9, Hotel Calce", place: "Positano", year: "2023" } },38 { label: "Contact", href: "#contact", project: { src: "/img/halcyon/positano-sunset-900.webp", alt: "", name: "Our terrace above the bay", place: "Praiano", year: "2026" } },39];40 41const OFFICES = [{ name: "Praiano", tz: "Europe/Rome" }, { name: "Kyoto", tz: "Asia/Tokyo" }];42const CONTACT = ["Via Roma 14, 84010 Praiano", "studio@morokessler.it", "+39 089 874 2210"];43 44export function FullscreenMenuNav({45 studio = "Moro Kessler",46 tagline = "Architects, Praiano & Kyoto",47 offices = OFFICES,48 items = ITEMS,49 contact = CONTACT,50 className,51}: FullscreenMenuNavProps) {52 const uid = useId();53 const [open, setOpen] = useState(false);54 const [shown, setShown] = useState(false);55 const [cur, setCur] = useState(0);56 const [prev, setPrev] = useState<number | null>(null);57 const [times, setTimes] = useState<string[]>(offices.map(() => "--:--"));58 const btn = useRef<HTMLButtonElement>(null);59 const panel = useRef<HTMLDivElement>(null);60 const root = useRef<HTMLElement>(null);61 62 // Live office clocks (client only).63 useEffect(() => {64 const fmt = offices.map((o) => new Intl.DateTimeFormat("en-GB", { hour: "2-digit", minute: "2-digit", hour12: false, timeZone: o.tz }));65 const tick = () => setTimes(fmt.map((f) => f.format(new Date())));66 tick();67 const t = window.setInterval(tick, 15000);68 return () => window.clearInterval(t);69 }, [offices.map((o) => o.tz).join()]); // eslint-disable-line react-hooks/exhaustive-deps70 71 // Bar gains a hairline once the page scrolls.72 useEffect(() => {73 const on = () => root.current?.toggleAttribute("data-scrolled", window.scrollY > 8);74 on();75 window.addEventListener("scroll", on, { passive: true });76 return () => window.removeEventListener("scroll", on);77 }, []);78 79 // Mount/unmount with an exit animation.80 useEffect(() => {81 if (open) {82 setShown(true);83 return;84 }85 if (!shown) return;86 const reduce = matchMedia("(prefers-reduced-motion: reduce)").matches;87 const t = window.setTimeout(() => setShown(false), reduce ? 0 : 520);88 return () => window.clearTimeout(t);89 }, [open]); // eslint-disable-line react-hooks/exhaustive-deps90 91 useEffect(() => {92 if (!open) return;93 const p = panel.current;94 const t = window.setTimeout(() => p?.querySelector<HTMLElement>(".fd-fsm-link")?.focus({ preventScroll: true }), 80);95 const prevOverflow = document.documentElement.style.overflow;96 document.documentElement.style.overflow = "hidden";97 const onKey = (e: KeyboardEvent) => {98 if (e.key === "Escape") {99 setOpen(false);100 btn.current?.focus();101 }102 if (e.key === "Tab" && p) {103 const f = [btn.current!, ...Array.from(p.querySelectorAll<HTMLElement>("a,button"))];104 const i = f.indexOf(document.activeElement as HTMLElement);105 if (e.shiftKey && i <= 0) {106 e.preventDefault();107 f[f.length - 1].focus();108 } else if (!e.shiftKey && i === f.length - 1) {109 e.preventDefault();110 f[0].focus();111 }112 }113 };114 document.addEventListener("keydown", onKey);115 return () => {116 window.clearTimeout(t);117 document.documentElement.style.overflow = prevOverflow;118 document.removeEventListener("keydown", onKey);119 };120 }, [open]);121 122 const pick = (i: number) => {123 if (i === cur) return;124 setPrev(cur);125 setCur(i);126 };127 128 const p = items[cur]?.project;129 const panelId = `${uid}-menu`;130 131 return (132 <header ref={root} className={`fd-fsm${className ? " " + className : ""}`} data-open={open ? "" : undefined}>133 <style>{css}</style>134 <div className="fd-fsm-bar">135 <a href="#top" className="fd-fsm-brand" aria-label={`${studio}, ${tagline}`}>136 <svg width="26" height="26" viewBox="0 0 26 26" aria-hidden="true"><path d="M1 25V9l12-8 12 8v16" fill="none" stroke="currentColor" strokeWidth="1.6" /><path d="M8 25V14h10v11" fill="none" stroke="currentColor" strokeWidth="1.6" /></svg>137 <span className="fd-fsm-name">{studio}</span>138 <span className="fd-fsm-tag">{tagline}</span>139 </a>140 <p className="fd-fsm-clocks" aria-label="Office hours">141 {offices.map((o, i) => (142 <span key={o.name}><b>{o.name}</b> {times[i]}</span>143 ))}144 </p>145 <button ref={btn} type="button" className="fd-fsm-btn" aria-expanded={open} aria-controls={panelId} onClick={() => setOpen((o) => !o)}>146 <span className="fd-fsm-roll" aria-hidden="true"><span>Menu</span><span>Close</span></span>147 <span className="fd-fsm-sr">{open ? "Close menu" : "Open menu"}</span>148 <span className="fd-fsm-lines" aria-hidden="true"><i /><i /></span>149 </button>150 </div>151 152 {shown && (153 <div ref={panel} id={panelId} className="fd-fsm-panel" role="dialog" aria-modal="true" aria-label="Site menu" data-state={open ? "open" : "closing"}>154 <nav className="fd-fsm-nav" aria-label="Primary">155 <ol>156 {items.map((it, i) => (157 <li key={it.href} style={{ ["--i" as string]: i }}>158 <a159 href={it.href}160 className="fd-fsm-link"161 data-on={cur === i ? "" : undefined}162 onPointerEnter={() => pick(i)}163 onFocus={() => pick(i)}164 onClick={() => setOpen(false)}165 >166 <span className="fd-fsm-idx">{String(i + 1).padStart(2, "0")}</span>167 <span className="fd-fsm-label">{it.label}</span>168 <span className="fd-fsm-myear">{it.project.year}</span>169 </a>170 </li>171 ))}172 </ol>173 </nav>174 <figure className="fd-fsm-fig" aria-hidden="true">175 <div className="fd-fsm-frame">176 {prev !== null && items[prev] && <img key={`p${prev}`} className="fd-fsm-img fd-fsm-under" src={items[prev].project.src} alt="" width={900} height={900} />}177 <img key={`c${cur}`} className="fd-fsm-img fd-fsm-over" src={p.src} alt={p.alt} width={900} height={900} />178 </div>179 <figcaption>180 <span className="fd-fsm-cn" key={`n${cur}`}>Nº {String(cur + 1).padStart(2, "0")}</span>181 <span className="fd-fsm-ct" key={`t${cur}`}>{p.name}, {p.place}</span>182 <span className="fd-fsm-cy" key={`y${cur}`}>{p.year}</span>183 </figcaption>184 </figure>185 <div className="fd-fsm-foot">186 {contact.map((c) => <span key={c}>{c}</span>)}187 <span className="fd-fsm-live"><i aria-hidden="true" />4 buildings on site this month</span>188 </div>189 </div>190 )}191 </header>192 );193}194 195const sans = `ui-sans-serif, -apple-system, BlinkMacSystemFont, "SF Pro Display", "Inter", "Segoe UI", Roboto, sans-serif`;196const mono = `ui-monospace, "SF Mono", "JetBrains Mono", Menlo, monospace`;197 198const css = `199.fd-fsm {200 --fd-ease-out: cubic-bezier(0.22, 1, 0.36, 1);201 --fd-ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);202 --fd-spring: cubic-bezier(0.34, 1.56, 0.64, 1);203 --fd-dur-1: 120ms; --fd-dur-2: 240ms; --fd-dur-3: 420ms; --fd-dur-4: 700ms;204 --fd-fsm-paper: #e9e5dc;205 --fd-fsm-ink: #171614;206 --fd-fsm-night: #141311;207 --fd-fsm-bone: #ebe6dc;208 position: sticky; top: 0; z-index: 50; display: block; margin: 0; padding: 0;209 font: 400 14px/1.4 ${sans};210 color: var(--fd-fsm-ink); background: var(--fd-fsm-paper);211 transition: box-shadow var(--fd-dur-2) linear;212}213.fd-fsm[data-scrolled] { box-shadow: 0 1px 0 rgba(23,22,20,0.16); }214.fd-fsm, .fd-fsm *, .fd-fsm *::before, .fd-fsm *::after { box-sizing: border-box; }215.fd-fsm a:focus-visible, .fd-fsm button:focus-visible { outline: 2px solid rgba(196,90,50,0.7); outline-offset: 3px; }216.fd-fsm-sr { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }217 218.fd-fsm-bar { position: relative; z-index: 3; display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; height: 72px; margin: 0; padding: 0 28px; color: var(--fd-fsm-ink); transition: color var(--fd-dur-3) var(--fd-ease-in-out); }219.fd-fsm[data-open] .fd-fsm-bar { color: var(--fd-fsm-bone); }220.fd-fsm-brand { display: inline-flex; align-items: center; gap: 12px; justify-self: start; margin: 0; padding: 0; color: inherit; text-decoration: none; }221.fd-fsm-brand svg { display: block; flex: none; }222.fd-fsm-name { font: 800 1.0625rem/1 ${sans}; letter-spacing: -0.03em; text-transform: uppercase; }223.fd-fsm-tag { font: 400 0.75rem/1 ${mono}; letter-spacing: 0; opacity: 0.66; }224.fd-fsm-clocks { display: flex; gap: 22px; margin: 0; padding: 0; font: 400 0.75rem/1 ${mono}; letter-spacing: 0.02em; font-variant-numeric: tabular-nums; }225.fd-fsm-clocks b { font-weight: 400; text-transform: uppercase; opacity: 0.55; margin-right: 4px; }226.fd-fsm-btn { justify-self: end; display: inline-flex; align-items: center; gap: 14px; height: 44px; margin: 0 -8px 0 0; padding: 0 8px 0 14px; border: 0; border-radius: 0; background: none; color: inherit; cursor: pointer; appearance: none; -webkit-appearance: none; font: 600 0.8125rem/1 ${mono}; letter-spacing: 0.08em; text-transform: uppercase; }227.fd-fsm-roll { position: relative; display: block; height: 14px; overflow: hidden; }228.fd-fsm-roll span { display: block; height: 14px; line-height: 14px; transition: transform var(--fd-dur-3) var(--fd-ease-out); }229.fd-fsm[data-open] .fd-fsm-roll span { transform: translateY(-100%); }230.fd-fsm-lines { position: relative; display: block; width: 30px; height: 30px; }231.fd-fsm-lines i { position: absolute; left: 3px; right: 3px; height: 1.5px; background: currentColor; transition: transform var(--fd-dur-3) var(--fd-spring), top var(--fd-dur-2) var(--fd-ease-out); }232.fd-fsm-lines i:nth-child(1) { top: 11px; }233.fd-fsm-lines i:nth-child(2) { top: 18px; transform-origin: center; }234.fd-fsm-btn:hover .fd-fsm-lines i:nth-child(2) { transform: scaleX(0.6) translateX(-33%); }235.fd-fsm[data-open] .fd-fsm-lines i:nth-child(1) { top: 14.5px; transform: rotate(45deg); }236.fd-fsm[data-open] .fd-fsm-lines i:nth-child(2) { top: 14.5px; transform: rotate(-45deg); }237 238.fd-fsm-panel { position: fixed; inset: 0; z-index: 2; display: grid; grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr); grid-template-rows: 1fr auto; gap: 0 56px; margin: 0; padding: 104px 28px 26px; background: var(--fd-fsm-night); color: var(--fd-fsm-bone); clip-path: inset(0 0 0 0); animation: fd-fsm-curtain var(--fd-dur-4) var(--fd-ease-out); overflow-y: auto; }239.fd-fsm-panel[data-state="closing"] { clip-path: inset(0 0 100% 0); transition: clip-path 520ms var(--fd-ease-in-out); }240@keyframes fd-fsm-curtain { from { clip-path: inset(0 0 100% 0); } }241 242.fd-fsm-nav { align-self: center; margin: 0; padding: 0; }243.fd-fsm-nav ol { margin: 0; padding: 0; list-style: none; }244.fd-fsm-nav li { margin: 0; padding: 0; overflow: hidden; clip-path: inset(0 0 100% 0); animation: fd-fsm-line var(--fd-dur-4) var(--fd-ease-out) forwards; animation-delay: calc(180ms + var(--i) * 70ms); }245.fd-fsm-panel[data-state="closing"] .fd-fsm-nav li { animation: none; clip-path: inset(0 0 0 0); }246@keyframes fd-fsm-line { to { clip-path: inset(0 0 0 0); } }247.fd-fsm-link { display: flex; align-items: flex-start; gap: 18px; margin: 0; padding: 0; color: var(--fd-fsm-bone); text-decoration: none; transform: translateY(70%); animation: fd-fsm-rise var(--fd-dur-4) var(--fd-ease-out) forwards; animation-delay: calc(180ms + var(--i) * 70ms); transition: opacity var(--fd-dur-2) linear; }248@keyframes fd-fsm-rise { to { transform: none; } }249.fd-fsm-nav ol:hover .fd-fsm-link, .fd-fsm-nav ol:focus-within .fd-fsm-link { opacity: 0.28; }250.fd-fsm-nav ol .fd-fsm-link[data-on] { opacity: 1; }251.fd-fsm-idx { flex: none; width: 2.4em; margin: 0; padding: 1.5em 0 0; font: 400 0.75rem/1 ${mono}; color: var(--fd-fsm-bone); opacity: 0.55; }252.fd-fsm-label { display: block; font: 800 clamp(3rem, 8.6vw, 8.25rem)/0.9 ${sans}; letter-spacing: -0.055em; text-transform: uppercase; padding: 0 0 0.04em; transition: transform var(--fd-dur-3) var(--fd-ease-out); }253.fd-fsm-link[data-on] .fd-fsm-label { transform: translateX(0.12em); }254.fd-fsm-link:focus-visible { outline-offset: -2px; }255.fd-fsm-myear { display: none; }256 257.fd-fsm-fig { align-self: center; justify-self: end; width: 100%; max-width: 460px; margin: 0; padding: 0; opacity: 0; animation: fd-fsm-fade var(--fd-dur-4) var(--fd-ease-out) 380ms forwards; }258@keyframes fd-fsm-fade { to { opacity: 1; } }259.fd-fsm-frame { position: relative; aspect-ratio: 4 / 5; overflow: hidden; background: #26241f; }260.fd-fsm-img { position: absolute; inset: 0; display: block; width: 100%; height: 100%; object-fit: cover; }261.fd-fsm-over { animation: fd-fsm-wipe var(--fd-dur-4) var(--fd-ease-out); }262@keyframes fd-fsm-wipe { from { clip-path: inset(100% 0 0 0); transform: scale(1.08); } to { clip-path: inset(0 0 0 0); transform: scale(1); } }263.fd-fsm-fig figcaption { display: grid; grid-template-columns: auto 1fr auto; align-items: baseline; gap: 14px; margin: 14px 0 0; padding: 12px 0 0; border-top: 1px solid rgba(235,230,220,0.22); }264.fd-fsm-cn, .fd-fsm-cy { font: 400 0.8125rem/1 ${mono}; color: var(--fd-fsm-bone); }265.fd-fsm-cy { font-size: 1.5rem; letter-spacing: -0.02em; }266.fd-fsm-ct { font: 500 0.9375rem/1.3 ${sans}; color: var(--fd-fsm-bone); opacity: 0.8; }267.fd-fsm-cn, .fd-fsm-ct, .fd-fsm-cy { animation: fd-fsm-up var(--fd-dur-3) var(--fd-ease-out); }268@keyframes fd-fsm-up { from { opacity: 0; transform: translateY(6px); } }269 270.fd-fsm-foot { grid-column: 1 / -1; display: flex; flex-wrap: wrap; gap: 8px 32px; align-items: center; margin: 28px 0 0; padding: 18px 0 0; border-top: 1px solid rgba(235,230,220,0.18); font: 400 0.75rem/1.3 ${mono}; color: rgba(235,230,220,0.7); opacity: 0; animation: fd-fsm-fade var(--fd-dur-4) var(--fd-ease-out) 520ms forwards; }271.fd-fsm-live { display: inline-flex; align-items: center; gap: 8px; margin-left: auto; color: var(--fd-fsm-bone); }272.fd-fsm-live i { display: block; width: 7px; height: 7px; border-radius: 9999px; background: #c45a32; }273 274@media (max-width: 860px) {275 .fd-fsm-clocks { display: none; }276 .fd-fsm-bar { grid-template-columns: 1fr auto; height: 64px; padding: 0 18px; }277 .fd-fsm-tag { display: none; }278 .fd-fsm-panel { grid-template-columns: 1fr; grid-template-rows: auto 1fr auto; padding: 88px 18px 22px; gap: 0; }279 .fd-fsm-fig { order: -1; justify-self: stretch; max-width: none; margin: 0 0 24px; }280 .fd-fsm-frame { aspect-ratio: 16 / 9; }281 .fd-fsm-fig figcaption { margin-top: 10px; padding-top: 8px; }282 .fd-fsm-cy { font-size: 1rem; }283 .fd-fsm-nav { align-self: start; }284 .fd-fsm-label { font-size: clamp(2.75rem, 14vw, 4.5rem); }285 .fd-fsm-myear { display: block; margin-left: auto; padding: 1.4em 0 0; font: 400 0.75rem/1 ${mono}; opacity: 0.55; }286 .fd-fsm-idx { width: 2em; padding-top: 1.2em; }287 .fd-fsm-live { margin-left: 0; }288}289@media (prefers-reduced-motion: reduce) {290 .fd-fsm-panel { animation: fd-fsm-fade var(--fd-dur-1) linear; }291 .fd-fsm-panel[data-state="closing"] { transition: none; }292 .fd-fsm-nav li, .fd-fsm-link { animation: none; clip-path: none; transform: none; }293 .fd-fsm-fig, .fd-fsm-foot { animation: none; opacity: 1; }294 .fd-fsm-over, .fd-fsm-cn, .fd-fsm-ct, .fd-fsm-cy { animation: none; }295 .fd-fsm-lines i, .fd-fsm-roll span, .fd-fsm-label { transition: none; }296}297`;298 299/* ── Demo ─────────────────────────────────────────────────────────────── */300 301const WORKS = [302 { n: "014", name: "Casa dei Limoni", place: "Praiano", type: "House, restoration", year: "2024" },303 { n: "013", name: "Suite 9, Hotel Calce", place: "Positano", type: "Interior", year: "2023" },304 { n: "012", name: "Villa Tre Pini pool", place: "Furore", type: "Landscape", year: "2022" },305 { n: "011", name: "Hanare guest house", place: "Kyoto", type: "Hospitality", year: "2021" },306 { n: "010", name: "Cantina Sciacca", place: "Ravello", type: "Winery, new build", year: "2019" },307];308 309export function Demo() {310 return (311 <div className="fd-fsm-demo">312 <style>{demoCss}</style>313 <FullscreenMenuNav />314 <main>315 <section className="fd-fsm-demo-hero">316 <p className="fd-fsm-demo-k">Since 1998 · 41 buildings · 3 of them still unfinished, on purpose</p>317 <h1>We build slowly, in stone, close to water.</h1>318 </section>319 <img className="fd-fsm-demo-img" src="/img/halcyon/pool-lemons.webp" alt="Pool terrace under lemon trees, Villa Tre Pini" width={1024} height={1024} />320 <section className="fd-fsm-demo-list" aria-label="Selected work">321 {WORKS.map((w) => (322 <a key={w.n} href="#work" className="fd-fsm-demo-row">323 <span>{w.n}</span><b>{w.name}</b><span>{w.place}</span><span>{w.type}</span><span>{w.year}</span>324 </a>325 ))}326 </section>327 </main>328 </div>329 );330}331 332const demoCss = `333.fd-fsm-demo { margin: 0; padding: 0; min-height: 100vh; background: #e9e5dc; color: #171614; font: 400 15px/1.5 ${sans}; }334.fd-fsm-demo *, .fd-fsm-demo *::before, .fd-fsm-demo *::after { box-sizing: border-box; }335.fd-fsm-demo main { display: block; margin: 0; padding: 0 28px 120px; }336.fd-fsm-demo-hero { display: grid; grid-template-columns: 1fr 3fr; gap: 28px; align-items: end; margin: 0; padding: 96px 0 48px; }337.fd-fsm-demo-k { margin: 0 0 12px; font: 400 0.75rem/1.5 ${mono}; color: #5f5b53; max-width: 26ch; }338.fd-fsm-demo h1 { margin: 0; font: 800 clamp(2.75rem, 7.4vw, 7rem)/0.9 ${sans}; letter-spacing: -0.055em; text-transform: uppercase; color: #171614; }339.fd-fsm-demo-img { display: block; width: 100%; height: 56vh; min-height: 320px; object-fit: cover; }340.fd-fsm-demo-list { margin: 48px 0 0; padding: 0; border-top: 1.5px solid #171614; }341.fd-fsm-demo-row { display: grid; grid-template-columns: 80px 2fr 1fr 1fr 80px; gap: 16px; align-items: baseline; padding: 18px 0; border-bottom: 1px solid rgba(23,22,20,0.2); color: #171614; text-decoration: none; font: 400 0.8125rem/1.3 ${mono}; transition: padding var(--fd-dur-2, 240ms) cubic-bezier(0.22, 1, 0.36, 1); }342.fd-fsm-demo-row b { font: 700 1.5rem/1.1 ${sans}; letter-spacing: -0.03em; }343.fd-fsm-demo-row span:last-child { text-align: right; }344.fd-fsm-demo-row:hover { background: #e2ddd2; }345@media (max-width: 860px) {346 .fd-fsm-demo main { padding: 0 18px 80px; }347 .fd-fsm-demo-hero { grid-template-columns: 1fr; padding: 48px 0 32px; }348 .fd-fsm-demo-row { grid-template-columns: 44px 1fr 48px; }349 .fd-fsm-demo-row span:nth-child(3), .fd-fsm-demo-row span:nth-child(4) { display: none; }350 .fd-fsm-demo-row b { font-size: 1.125rem; }351}352`;More Navbars. Same file contract.
Questions about Fullscreen Menu Nav
Run npx shadcn@latest add https://freedesignmd.com/r/fullscreen-menu-nav.json, or open the page and copy the file into your project. It has zero dependencies besides React. What you copy is the exact file that renders the live demo.
Fullscreen menu navbar: a burger opens an overlay with giant links that reveal line by line and a project photo on hover. It is a free, MIT-licensed React navbars component from the freedesignmd library.
Yes. It is free and MIT-licensed, use, modify and ship it in personal and commercial projects without attribution.
All evergreen browsers (clip-path inset animations, Intl time zones for the office clocks).
Yes. It is a plain React component with its own styles, so it runs in Next.js, Vite, Remix and Lovable projects, and it needs no Tailwind setup. It has zero dependencies besides React.


