Navigation menu
Mega-menu navigation with popover panels, submenus, and anchor positioning.
The navigation menu pairs triggers (popovertarget) with .navigation-menu__popover panels.
A .navigation-menu__list holds each .navigation-menu__item, whose .navigation-menu__trigger
opens a panel. Panels wrap a .navigation-menu__viewport grid of .navigation-menu__link rows
(title + description, filling with muted on hover), can nest flyout submenus via
.navigation-menu__submenu / .navigation-menu__submenu-trigger, and animate in. A "Featured"
callout is not a dedicated part — it is plain utilities, e.g.
bg-muted hover:opacity-75 rounded-sm p-sm with a .text-eyebrow label.
Default
<header class="w-full"> <nav class="navigation-menu container"> <menu class="navigation-menu__list"> <!-- Rich panel — featured callout + link grid --> <li class="navigation-menu__item"> <button class="button navigation-menu__trigger" data-variant="ghost" type="button" popovertarget="nav-dropdown-1" > Platform <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"> <rect width="256" height="256" fill="none" /> <polyline points="208 96 128 176 48 96" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" /> </svg> </button> <div id="nav-dropdown-1" class="navigation-menu__popover" popover="auto" data-animation="slide-down" > <div class="navigation-menu__viewport grid grid-cols-3"> <div class="grid py-xs pl-xs"> <a href="#" class="flex flex-col items-start justify-end bg-muted transition hover:opacity-75 rounded-sm p-sm" > <span class="text-eyebrow text-muted-foreground mb-xs">Featured</span> <span class="text-md font-strong">Platform</span> <span class="text-sm text-muted-foreground text-pretty"> Everything you need to design, build, and ship. </span> </a> </div> <div class="flex flex-col gap-px py-xs pr-xs col-span-2"> <a href="#" class="navigation-menu__link"> <span class="text-sm font-strong">Analytics</span> <span class="text-sm text-muted-foreground" >Real-time insights into product usage.</span > </a> <a href="#" class="navigation-menu__link"> <span class="text-sm font-strong">Automation</span> <span class="text-sm text-muted-foreground">Workflows that run themselves.</span> </a> <a href="#" class="navigation-menu__link"> <span class="text-sm font-strong">Integrations</span> <span class="text-sm text-muted-foreground" >Connect the tools your team already uses.</span > </a> <a href="#" class="navigation-menu__link"> <span class="text-sm font-strong">Features</span> <span class="text-sm text-muted-foreground" >Everything you need to design, build, and ship.</span > </a> </div> </div> </div> </li> <!-- Simple panel — single-column link list --> <li class="navigation-menu__item"> <button class="button navigation-menu__trigger" data-variant="ghost" type="button" popovertarget="nav-dropdown-2" > Resources <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"> <rect width="256" height="256" fill="none" /> <polyline points="208 96 128 176 48 96" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" /> </svg> </button> <div id="nav-dropdown-2" class="navigation-menu__popover" data-align="start" popover="auto" data-animation="slide-down" > <div class="navigation-menu__viewport"> <div class="flex flex-col gap-px p-xs"> <a href="#" class="navigation-menu__link"> <span class="text-sm font-strong">Documentation</span> <span class="text-sm text-muted-foreground">Guides and API references.</span> </a> <a href="#" class="navigation-menu__link"> <span class="text-sm font-strong">Blog</span> <span class="text-sm text-muted-foreground" >Product news and engineering notes.</span > </a> <a href="#" class="navigation-menu__link"> <span class="text-sm font-strong">Community</span> <span class="text-sm text-muted-foreground" >Join the conversation and get help.</span > </a> </div> </div> </div> </li> <!-- Submenu panel — categories whose products fly out to the right --> <li class="navigation-menu__item"> <button class="button navigation-menu__trigger" data-variant="ghost" type="button" popovertarget="nav-dropdown-3" > Products <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"> <rect width="256" height="256" fill="none" /> <polyline points="208 96 128 176 48 96" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" /> </svg> </button> <div id="nav-dropdown-3" class="navigation-menu__popover" popover="auto" data-animation="slide-down" > <div class="navigation-menu__viewport"> <div class="flex flex-col gap-px p-xs"> <!-- Category — opens its product list to the right --> <div class="navigation-menu__submenu"> <button class="navigation-menu__submenu-trigger" type="button" popovertarget="nav-submenu-1" > <span class="text-sm font-strong">Design</span> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"> <rect width="256" height="256" fill="none" /> <polyline points="96 48 176 128 96 208" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" /> </svg> </button> <div id="nav-submenu-1" class="navigation-menu__popover" data-variant="submenu" popover="auto" > <div class="navigation-menu__viewport"> <div class="flex flex-col gap-px p-xs"> <a href="#" class="navigation-menu__link"> <span class="text-sm font-strong">Figma Kit</span> <span class="text-sm text-muted-foreground" >Variables, styles, and components.</span > </a> <a href="#" class="navigation-menu__link"> <span class="text-sm font-strong">Color Generator</span> <span class="text-sm text-muted-foreground" >OKLCH scales from a single brand hex.</span > </a> <a href="#" class="navigation-menu__link"> <span class="text-sm font-strong">Type Scale</span> <span class="text-sm text-muted-foreground" >Fluid sizes tuned with Utopia.</span > </a> <a href="#" class="navigation-menu__link"> <span class="text-sm font-strong">Icon Set</span> <span class="text-sm text-muted-foreground" >A consistent, lightweight icon library.</span > </a> </div> </div> </div> </div> <!-- Category — opens its product list to the right --> <div class="navigation-menu__submenu"> <button class="navigation-menu__submenu-trigger" type="button" popovertarget="nav-submenu-2" > <span class="text-sm font-strong">Development</span> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"> <rect width="256" height="256" fill="none" /> <polyline points="96 48 176 128 96 208" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" /> </svg> </button> <div id="nav-submenu-2" class="navigation-menu__popover" data-variant="submenu" popover="auto" > <div class="navigation-menu__viewport"> <div class="flex flex-col gap-px p-xs"> <a href="#" class="navigation-menu__link"> <span class="text-sm font-strong">CLI</span> <span class="text-sm text-muted-foreground" >Scaffold and ship from the terminal.</span > </a> <a href="#" class="navigation-menu__link"> <span class="text-sm font-strong">React Components</span> <span class="text-sm text-muted-foreground" >Token-driven primitives for your app.</span > </a> <a href="#" class="navigation-menu__link"> <span class="text-sm font-strong">REST API</span> <span class="text-sm text-muted-foreground" >Programmatic access to your design data.</span > </a> <a href="#" class="navigation-menu__link"> <span class="text-sm font-strong">Webhooks</span> <span class="text-sm text-muted-foreground" >React to changes in real time.</span > </a> </div> </div> </div> </div> <!-- Category — opens its product list to the right --> <div class="navigation-menu__submenu"> <button class="navigation-menu__submenu-trigger" type="button" popovertarget="nav-submenu-3" > <span class="text-sm font-strong">Content</span> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"> <rect width="256" height="256" fill="none" /> <polyline points="96 48 176 128 96 208" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" /> </svg> </button> <div id="nav-submenu-3" class="navigation-menu__popover" data-variant="submenu" popover="auto" > <div class="navigation-menu__viewport"> <div class="flex flex-col gap-px p-xs"> <a href="#" class="navigation-menu__link"> <span class="text-sm font-strong">CMS</span> <span class="text-sm text-muted-foreground" >Structured content for any surface.</span > </a> <a href="#" class="navigation-menu__link"> <span class="text-sm font-strong">Localization</span> <span class="text-sm text-muted-foreground" >Ship in every language your users speak.</span > </a> <a href="#" class="navigation-menu__link"> <span class="text-sm font-strong">Media Library</span> <span class="text-sm text-muted-foreground" >Optimized assets, delivered fast.</span > </a> </div> </div> </div> </div> </div> </div> </div> </li> <li class="navigation-menu__item"> <button class="button navigation-menu__trigger" data-variant="ghost" type="button" popovertarget="nav-megamenu-1" > Megamenu <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"> <rect width="256" height="256" fill="none" /> <polyline points="208 96 128 176 48 96" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" /> </svg> </button> <div id="nav-megamenu-1" class="navigation-menu__popover" popover="auto" data-size="container" data-animation="slide-down" > <div class="navigation-menu__viewport"> <div class="grid" style="min-block-size: 16rem"> <div class="flex flex-col gap-px p-xs"> <!-- Tabs vertical START --> <div class="tabs h-full flex flex-col @xs:grid @xs:grid-cols-2 @md:grid-cols-4 gap-sm" data-orientation="vertical" > <div class="tabs__list rounded-sm w-full @xs:w-auto @xs:col-span-2 @md:col-span-1 @md:h-full grid @sm:flex flex-col" role="tablist" > <div class="tabs__indicator rounded-xs" aria-hidden="true"></div> <input type="radio" role="tab" name="tabs-megamenu-group-1" id="tab-megamenu-1" checked /> <label for="tab-megamenu-1" class="tabs__label grid justify-start p-sm flex-1"> <span class="text-md font-strong">Women</span> <span class="text-sm font-weight-body text-muted-foreground" >Dresses, tops, bottoms, and shoes.</span > </label> <input type="radio" role="tab" name="tabs-megamenu-group-1" id="tab-megamenu-2" /> <label for="tab-megamenu-2" class="tabs__label grid justify-start p-sm flex-1"> <span class="text-md font-strong">Men</span> <span class="text-sm font-weight-body text-muted-foreground" >Shirts, pants, outerwear, and shoes.</span > </label> <input type="radio" role="tab" name="tabs-megamenu-group-1" id="tab-megamenu-3" /> <label for="tab-megamenu-3" class="tabs__label grid justify-start p-sm flex-1"> <span class="text-md font-strong">Home</span> <span class="text-sm font-weight-body text-muted-foreground" >Bedding, kitchen, dining, and decor.</span > </label> </div> <div class="tabs__panel flex flex-col @xs:grid @xs:grid-cols-subgrid @xs:col-span-2 @md:col-span-3 gap-sm" role="tabpanel" > <div class="grid gap-px"> <span class="text-eyebrow text-muted-foreground pt-xs pb-xs">Dresses</span> <a href="#" class="navigation-menu__link flex-1"> <span class="text-sm font-strong">Mini & Midi</span> <span class="text-sm text-muted-foreground" >Everyday lengths for work and weekends.</span > </a> <a href="#" class="navigation-menu__link flex-1"> <span class="text-sm font-strong">Maxi Dresses</span> <span class="text-sm text-muted-foreground" >Flowing silhouettes in linen and cotton.</span > </a> <a href="#" class="navigation-menu__link flex-1"> <span class="text-sm font-strong">Jumpsuits</span> <span class="text-sm text-muted-foreground" >One-piece outfits, easy to style.</span > </a> <a href="#" class="navigation-menu__link flex-1"> <span class="text-sm font-strong">Shop all dresses</span> <span class="text-sm text-muted-foreground" >Browse the full collection.</span > </a> </div> <div class="grid gap-px"> <span class="text-eyebrow text-muted-foreground pt-xs pb-xs">Tops</span> <a href="#" class="navigation-menu__link flex-1"> <span class="text-sm font-strong">T-shirts & Tanks</span> <span class="text-sm text-muted-foreground" >Basics in organic cotton blends.</span > </a> <a href="#" class="navigation-menu__link flex-1"> <span class="text-sm font-strong">Blouses & Shirts</span> <span class="text-sm text-muted-foreground" >Office-ready and off-duty styles.</span > </a> <a href="#" class="navigation-menu__link flex-1"> <span class="text-sm font-strong">Sweaters & Cardigans</span> <span class="text-sm text-muted-foreground" >Layering pieces for cooler days.</span > </a> <a href="#" class="navigation-menu__link flex-1"> <span class="text-sm font-strong">Activewear</span> <span class="text-sm text-muted-foreground" >Leggings, sports bras, and sets.</span > </a> </div> <div class="grid gap-px"> <span class="text-eyebrow text-muted-foreground pt-xs pb-xs" >Bottoms & Shoes</span > <a href="#" class="navigation-menu__link flex-1"> <span class="text-sm font-strong">Jeans & Denim</span> <span class="text-sm text-muted-foreground" >Straight, wide-leg, and high-rise fits.</span > </a> <a href="#" class="navigation-menu__link flex-1"> <span class="text-sm font-strong">Trousers & Skirts</span> <span class="text-sm text-muted-foreground" >Tailored pants and A-line skirts.</span > </a> <a href="#" class="navigation-menu__link flex-1"> <span class="text-sm font-strong">Sneakers & Flats</span> <span class="text-sm text-muted-foreground" >Comfort-first everyday footwear.</span > </a> <a href="#" class="navigation-menu__link flex-1"> <span class="text-sm font-strong">Boots & Heels</span> <span class="text-sm text-muted-foreground" >Seasonal styles for dress-up moments.</span > </a> </div> </div> <div class="tabs__panel flex flex-col @xs:grid @xs:grid-cols-subgrid @xs:col-span-2 @md:col-span-3 gap-sm" role="tabpanel" > <div class="grid gap-px"> <span class="text-eyebrow text-muted-foreground pt-xs pb-xs">Shirts</span> <a href="#" class="navigation-menu__link flex-1"> <span class="text-sm font-strong">T-shirts & Polos</span> <span class="text-sm text-muted-foreground" >Classic fits in breathable fabrics.</span > </a> <a href="#" class="navigation-menu__link flex-1"> <span class="text-sm font-strong">Oxford & Dress Shirts</span> <span class="text-sm text-muted-foreground" >Collared styles for work and events.</span > </a> <a href="#" class="navigation-menu__link flex-1"> <span class="text-sm font-strong">Henleys & Sweaters</span> <span class="text-sm text-muted-foreground" >Casual layers for transitional weather.</span > </a> <a href="#" class="navigation-menu__link flex-1"> <span class="text-sm font-strong">Shop all shirts</span> <span class="text-sm text-muted-foreground">See every cut and color.</span> </a> </div> <div class="grid gap-px"> <span class="text-eyebrow text-muted-foreground pt-xs pb-xs" >Pants & Shorts</span > <a href="#" class="navigation-menu__link flex-1"> <span class="text-sm font-strong">Chinos & Trousers</span> <span class="text-sm text-muted-foreground" >Smart casual staples in neutral tones.</span > </a> <a href="#" class="navigation-menu__link flex-1"> <span class="text-sm font-strong">Jeans</span> <span class="text-sm text-muted-foreground" >Slim, relaxed, and straight-leg denim.</span > </a> <a href="#" class="navigation-menu__link flex-1"> <span class="text-sm font-strong">Joggers & Sweatpants</span> <span class="text-sm text-muted-foreground" >Loungewear you can wear out.</span > </a> <a href="#" class="navigation-menu__link flex-1"> <span class="text-sm font-strong">Shorts</span> <span class="text-sm text-muted-foreground" >Chino, cargo, and athletic cuts.</span > </a> </div> <div class="grid gap-px"> <span class="text-eyebrow text-muted-foreground pt-xs pb-xs" >Outerwear & Shoes</span > <a href="#" class="navigation-menu__link flex-1"> <span class="text-sm font-strong">Jackets & Coats</span> <span class="text-sm text-muted-foreground" >Bombers, parkas, and wool overcoats.</span > </a> <a href="#" class="navigation-menu__link flex-1"> <span class="text-sm font-strong">Sneakers</span> <span class="text-sm text-muted-foreground" >Low-top and high-top everyday pairs.</span > </a> <a href="#" class="navigation-menu__link flex-1"> <span class="text-sm font-strong">Boots & Loafers</span> <span class="text-sm text-muted-foreground" >Leather and suede dress-casual options.</span > </a> <a href="#" class="navigation-menu__link flex-1"> <span class="text-sm font-strong">Accessories</span> <span class="text-sm text-muted-foreground" >Belts, wallets, and winter essentials.</span > </a> </div> </div> <div class="tabs__panel flex flex-col @xs:grid @xs:grid-cols-subgrid @xs:col-span-2 @md:col-span-3 gap-sm" role="tabpanel" > <div class="grid gap-px"> <span class="text-eyebrow text-muted-foreground pt-xs pb-xs">Bedding</span> <a href="#" class="navigation-menu__link flex-1"> <span class="text-sm font-strong">Sheet Sets</span> <span class="text-sm text-muted-foreground" >Percale, sateen, and linen weaves.</span > </a> <a href="#" class="navigation-menu__link flex-1"> <span class="text-sm font-strong">Duvets & Comforters</span> <span class="text-sm text-muted-foreground" >All-season weights and down alternatives.</span > </a> <a href="#" class="navigation-menu__link flex-1"> <span class="text-sm font-strong">Pillows & Throws</span> <span class="text-sm text-muted-foreground" >Accent layers for beds and sofas.</span > </a> <a href="#" class="navigation-menu__link flex-1"> <span class="text-sm font-strong">Shop all bedding</span> <span class="text-sm text-muted-foreground" >Build a complete sleep setup.</span > </a> </div> <div class="grid gap-px"> <span class="text-eyebrow text-muted-foreground pt-xs pb-xs" >Kitchen & Dining</span > <a href="#" class="navigation-menu__link flex-1"> <span class="text-sm font-strong">Cookware</span> <span class="text-sm text-muted-foreground" >Pots, pans, and non-stick sets.</span > </a> <a href="#" class="navigation-menu__link flex-1"> <span class="text-sm font-strong">Tableware</span> <span class="text-sm text-muted-foreground" >Plates, bowls, and flatware collections.</span > </a> <a href="#" class="navigation-menu__link flex-1"> <span class="text-sm font-strong">Glassware & Bar</span> <span class="text-sm text-muted-foreground" >Tumblers, wine glasses, and decanters.</span > </a> <a href="#" class="navigation-menu__link flex-1"> <span class="text-sm font-strong">Storage & Organization</span> <span class="text-sm text-muted-foreground" >Pantry jars, bins, and drawer inserts.</span > </a> </div> <div class="grid gap-px"> <span class="text-eyebrow text-muted-foreground pt-xs pb-xs" >Decor & Furniture</span > <a href="#" class="navigation-menu__link flex-1"> <span class="text-sm font-strong">Lighting</span> <span class="text-sm text-muted-foreground" >Floor lamps, pendants, and table lights.</span > </a> <a href="#" class="navigation-menu__link flex-1"> <span class="text-sm font-strong">Rugs & Curtains</span> <span class="text-sm text-muted-foreground" >Textiles to anchor and soften a room.</span > </a> <a href="#" class="navigation-menu__link flex-1"> <span class="text-sm font-strong">Seating & Tables</span> <span class="text-sm text-muted-foreground" >Chairs, side tables, and accent pieces.</span > </a> <a href="#" class="navigation-menu__link flex-1"> <span class="text-sm font-strong">Wall Art & Mirrors</span> <span class="text-sm text-muted-foreground" >Prints, frames, and statement mirrors.</span > </a> </div> </div> <!-- Tabs vertical END --> </div> </div> </div> </div> </div> </li> <li class="navigation-menu__item ml-auto mr-xs"> <!-- Form dialog START --> <button class="button" type="button" data-variant="ghost" command="show-modal" commandfor="form-sign-in-1" > Sign in <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"> <rect width="256" height="256" fill="none" /> <line x1="24" y1="128" x2="136" y2="128" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" /> <polyline points="96 88 136 128 96 168" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" /> <polyline points="136 40 200 40 200 216 136 216" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" /> </svg> </button> <dialog id="form-sign-in-1" class="dialog" closedby="any"> <form method="dialog" class="dialog__content"> <header class="dialog__header"> <h2 class="text-lg font-heading font-strong">Sign in</h2> <p class="text-muted-foreground">Enter your email and password to sign in.</p> </header> <div class="dialog__body flex flex-col gap-md"> <fieldset class="field-group"> <legend class="sr-only">Sign in</legend> <div class="grid gap-xs"> <div class="field"> <label class="field__label" for="fd-email">Email</label> <input class="input" id="fd-email" name="email" type="email" inputmode="email" required placeholder="you@example.com" autocomplete="email" aria-describedby="fd-email-hint" /> <div class="field__description"> <span class="field__hint" id="fd-email-hint" >We'll only use this to send receipts.</span > <span class="field__error" role="alert" >Please enter a valid email address.</span > </div> </div> <!-- Password START --> <div class="field"> <label class="field__label" for="f-login-password">Password</label> <input-password> <label class="password-group"> <input class="input" id="f-login-password" name="password" type="password" autocomplete="new-password" minlength="8" required placeholder="••••••••" aria-describedby="f-login-password-hint f-login-password-warning" /> <span class="password-group__addon" data-align="inline-end"> <button class="button password-group__toggle" id="f-login-password-toggle" data-variant="ghost" data-size="icon-sm" type="button" aria-pressed="false" aria-label="Show password" aria-describedby="f-login-password-warning" > <svg class="password-group__icon password-group__icon--show" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" aria-hidden="true" > <rect width="256" height="256" fill="none" /> <path d="M128,56C48,56,16,128,16,128s32,72,112,72,112-72,112-72S208,56,128,56Z" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" /> <circle cx="128" cy="128" r="40" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" /> </svg> <svg class="password-group__icon password-group__icon--hide" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" aria-hidden="true" > <rect width="256" height="256" fill="none" /> <line x1="48" y1="40" x2="208" y2="216" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" /> <path d="M154.9,157.6A40,40,0,0,1,101,98.4" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" /> <path d="M73.8,69.7C33.6,90.6,16,128,16,128s32,72,112,72a118.1,118.1,0,0,0,54.1-12.8" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" /> <path d="M208.6,169.1C229.8,149.1,240,128,240,128S208,56,128,56a126,126,0,0,0-20.5,1.6" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" /> </svg> </button> </span> </label> </input-password> <div class="field__description"> <span class="field__error" role="alert">Incorrect email or password.</span> </div> <span class="sr-only" id="f-login-password-warning" >Warning: showing the password makes it visible to anyone near your screen.</span > </div> <!-- Password END --> </div> </fieldset> </div> <footer class="dialog__footer"> <button class="button" type="button" value="cancel" commandfor="form-sign-in-1" command="close" > Cancel </button> <button class="button" data-variant="primary" type="submit" value="save"> Sign in </button> </footer> </form> <button class="button dialog__close" data-size="icon" data-variant="ghost" type="button" commandfor="form-sign-in-1" command="close" aria-label="Close dialog" > <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"> <rect width="256" height="256" fill="none" /> <line x1="200" y1="56" x2="56" y2="200" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" /> <line x1="200" y1="200" x2="56" y2="56" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" /> </svg> </button> </dialog> <!-- Form dialog END --> </li> <!-- Plain CTA — no popover --> <li class="navigation-menu__item"> <a href="#" class="button" data-variant="primary">Get started</a> </li> </menu> </nav></header>// password.js"use strict";/** * @fileoverview `<input-password>` — HTML web component for password visibility. * @description Light-DOM custom element that adds show/hide behavior to a * standard password field. Wrap the existing `.password-group` markup — the * element finds the input and the `.password-group__toggle` button, flips the * input between `type="password"` and `type="text"` on click, and keeps * `aria-pressed` and `aria-label` in sync. The icon swap is pure CSS, driven * by `aria-pressed` (see _password-group.css). * * Without JavaScript the field degrades to a regular password input; the * toggle button simply does nothing. * * Configuration (attributes on `<input-password>`): * - `label-show`: Toggle label while the password is hidden (default "Show password"). * - `label-hide`: Toggle label while the password is visible (default "Hide password"). * * @example * <input-password> * <label class="password-group"> * <input class="input" type="password" autocomplete="current-password" /> * <span class="password-group__addon" data-align="inline-end"> * <button class="button password-group__toggle" type="button" * aria-pressed="false" aria-label="Show password">…</button> * </span> * </label> * </input-password> */class InputPassword extends HTMLElement { /** @type {AbortController|null} */ #controller = null; connectedCallback() { if (this.#controller) return; const input = this.querySelector('input[type="password"], input[type="text"]'); const toggle = this.querySelector(".password-group__toggle"); if (!(input instanceof HTMLInputElement) || !(toggle instanceof HTMLElement)) return; this.#controller = new AbortController(); toggle.addEventListener( "click", () => { const reveal = input.type === "password"; input.type = reveal ? "text" : "password"; toggle.setAttribute("aria-pressed", String(reveal)); toggle.setAttribute( "aria-label", reveal ? this.getAttribute("label-hide") || "Hide password" : this.getAttribute("label-show") || "Show password", ); }, { signal: this.#controller.signal }, ); } disconnectedCallback() { this.#controller?.abort(); this.#controller = null; }}// Register the element (guarded against double script loads)if (typeof window !== "undefined" && !customElements.get("input-password")) { customElements.define("input-password", InputPassword);}// Attach to window for parity with the other component scripts, and export for// module consumers (loaded for its side effect — the custom-element registration).if (typeof window !== "undefined") { window.InputPassword = InputPassword;}export { InputPassword };/** * _navigation-menu.css — Navigation menu (.navigation-menu) * * @layer variables, components * @requires layers.css, _variables.css, _popover.css, _button.css * @uses [popover] + nested popovers — megamenu panels and flyout submenus * @uses anchor-name, anchor-scope, position-anchor, anchor-size() — panel * sizing and positioning (Chromium 125+ for anchor-size) * @uses :has(:popover-open) — chevron rotation without JS * @uses view-transition-name — stable header across navigations * @uses @starting-style — slide-down viewport reveal * @tokens --navigation-* (@layer variables) */@layer variables { :root { --navigation-icon-transition: transform var(--default-transition-duration) var(--default-transition-timing-function); --navigation-icon-transform: rotate(-180deg); --navigation-popover-shadow: var(--shadow-md); --navigation-popover-child-radius: var(--radius-sm); --navigation-popover-gap: var(--step-1_5); --navigation-popover-inline-size: min(var(--breakpoint-xs), 100% - var(--gap-md)); --navigation-popover-viewport-display: grid; --navigation-popover-viewport-align-items: stretch; --navigation-popover-viewport-justify-items: stretch; --navigation-popover-viewport-template-columns: 1fr; --navigation-popover-viewport-gap: var(--step-1_5); --navigation-popover-viewport-min-inline-size: var(--step-52); }}@layer zazz.components { .navigation-menu { /* View transitions - keeps the header stable when navigating between pages */ --popover-shadow: var(--navigation-popover-shadow); --popover-child-radius: var(--navigation-popover-child-radius); --popover-gap: var(--navigation-popover-gap); --popover-inline-size: var(--navigation-popover-inline-size); --popover-viewport-display: var(--navigation-popover-viewport-display); --popover-viewport-align-items: var(--navigation-popover-viewport-align-items); --popover-viewport-justify-items: var(--navigation-popover-viewport-justify-items); --popover-viewport-template-columns: var(--navigation-popover-viewport-template-columns); --popover-viewport-gap: var(--navigation-popover-viewport-gap); --popover-viewport-min-inline-size: var(--navigation-popover-viewport-min-inline-size); display: inline-flex; position: relative; anchor-name: --navigation-menu-root; isolation: isolate; } .navigation-menu__list { display: flex; flex-direction: row; align-items: center; gap: var(--popover-gap); anchor-name: --navigation-menu-list; } /* Each item scopes its own anchor name so triggers can share one name */ .navigation-menu__item { anchor-scope: --navigation-menu-trigger; position: relative; } .navigation-menu__trigger { anchor-name: --navigation-menu-trigger; } /* Chevron points down by default, flips up while its popover is open (no JS) */ .navigation-menu__trigger > svg { inline-size: var(--gap-sm); block-size: var(--gap-sm); transition: var(--navigation-icon-transition); } .navigation-menu__item:has(.navigation-menu__popover:where(:popover-open, .\:popover-open)) .navigation-menu__trigger > svg { transform: var(--navigation-icon-transform); } /* =========================================================================== POPOVER — inherits --popover-* from _popover.css; panel layout overrides here =========================================================================== */ .navigation-menu__popover { position-anchor: --navigation-menu-trigger; max-inline-size: var(--popover-inline-size); --popover-padding: 0; --popover-min-inline-size: auto; /* Default: open below the trigger, aligned to its start edge */ --popover-position-area: block-end span-inline-end; --popover-origin: top center; --popover-margin-block: var(--step-1_5); } .navigation-menu__popover .button { --button-radius: var(--radius-xs); } /* =========================================================================== ALIGNMENT — nav menus only open downward, so just align along the inline axis =========================================================================== */ .navigation-menu__popover[data-align="center"] { --popover-position-area: block-end span-all; --popover-origin: top center; } .navigation-menu__popover[data-align="end"] { --popover-position-area: block-end span-inline-start; --popover-origin: top right; } /* =========================================================================== SUBMENU — categories inside a panel whose product lists fly out to the right. Native nested popovers: each sub-trigger's popovertarget lives inside the parent panel, so opening a submenu keeps the panel open (ancestor chain, no JS). =========================================================================== */ /* Each category scopes its own anchor so every sub-trigger reuses one name */ .navigation-menu__submenu { anchor-scope: --navigation-menu-subtrigger; position: relative; } /* Category row — a full-width link row with a trailing caret */ .navigation-menu__submenu-trigger { anchor-name: --navigation-menu-subtrigger; display: flex; align-items: center; justify-content: space-between; gap: var(--gap-sm); inline-size: 100%; padding: var(--popover-gap); border: 0; border-radius: var(--popover-child-radius); color: inherit; font: inherit; text-align: start; cursor: pointer; } /* Highlight the row on hover and while its submenu is open */ .navigation-menu__submenu-trigger:hover, .navigation-menu__submenu:has( .navigation-menu__popover[data-variant="submenu"]:where(:popover-open, .\:popover-open) ) .navigation-menu__submenu-trigger { background-color: var(--muted); } /* Caret points right — the direction the submenu opens */ .navigation-menu__submenu-trigger > svg { inline-size: var(--gap-sm); block-size: var(--gap-sm); flex: 0 0 auto; color: var(--muted-foreground); } /* Submenu (data-variant="submenu") inherits all base .navigation-menu__popover styling; only the anchor and open direction differ — it flies out to the inline-end edge, top-aligned, flipping leftward near the viewport's edge. */ .navigation-menu__popover[data-variant="submenu"] { position-anchor: --navigation-menu-subtrigger; --popover-position-area: inline-end span-block-start; --popover-origin: left top; --popover-margin-block: 0; --popover-margin-inline: var(--step-1_5); --popover-position-try-fallbacks: flip-inline, flip-block, flip-inline flip-block; } /* =========================================================================== PANEL CONTENT =========================================================================== */ .navigation-menu__viewport { display: var(--popover-viewport-display); grid-template-columns: var(--popover-viewport-template-columns); align-items: var(--popover-viewport-align-items); justify-items: var(--popover-viewport-justify-items); gap: var(--popover-viewport-gap); min-inline-size: var(--popover-viewport-min-inline-size); } /* Rich link row: title + description, hover fills with muted */ .navigation-menu__link { display: flex; flex-direction: column; padding: var(--popover-gap); border-radius: var(--popover-child-radius); text-decoration: none; transition: background-color var(--default-transition-duration) var(--default-transition-timing-function); } .navigation-menu__link:hover { background-color: var(--muted); } /* =========================================================================== MEGAMENU ANIMATION =========================================================================== */ /* Slide-down: accordion-style block-size reveal on the viewport (not scaleY). */ .navigation-menu__popover[data-size="screen"][data-animation="slide-down"] { --popover-scale--start: 1; } .navigation-menu__popover[data-animation="slide-down"] > .navigation-menu__viewport { overflow: clip; block-size: 0; transform: translateY(0.5rem); transform-origin: top center; transition: block-size var(--default-transition-duration) var(--default-transition-timing-function), transform var(--default-transition-duration) var(--default-transition-timing-function), padding var(--default-transition-duration) var(--default-transition-timing-function); } .navigation-menu__popover[data-animation="slide-down"]:where(:popover-open, .\:popover-open) { opacity: var(--popover-opacity--end); transform: scale(var(--popover-scale--end)) translate3d(var(--popover-translate--end)); @starting-style { opacity: var(--popover-opacity--start); transform: scale(var(--popover-scale--start)) translate3d(var(--popover-translate--start)); } } .navigation-menu__popover[data-animation="slide-down"]:where(:popover-open, .\:popover-open) .navigation-menu__viewport { block-size: auto; transform: scale(1) translateY(0); @starting-style { block-size: 0; transform: translateY(0.5rem); } } /* =========================================================================== SIZING VARIANTS =========================================================================== */ .navigation-menu__popover[data-size="container"] { position-anchor: --navigation-menu-list; --popover-inline-size: anchor-size(); --popover-position-area: block-end span-all; inline-size: var(--popover-inline-size); } .navigation-menu__popover[data-size="root"] { position-anchor: --navigation-menu-root; --popover-inline-size: anchor-size(); --popover-position-area: block-end span-all; inline-size: var(--popover-inline-size); } .navigation-menu__popover[data-size="screen"] { position-anchor: --navigation-menu-root; --popover-inline-size: 100vi; --popover-position-area: block-end span-all; inline-size: var(--popover-inline-size); }}The sign-in dialog in this example uses <input-password> for the password field's
show/hide toggle; open the JS tab to inspect that enhancement.
API
| Attribute | Where | Values |
|---|---|---|
popovertarget | trigger | id of the panel |
data-align | .navigation-menu__popover | center, end |
data-variant | .navigation-menu__popover | submenu |
data-size | .navigation-menu__popover | root, container, screen |
data-animation | .navigation-menu__popover | slide-down |