Overview of the Phoenix and LiveView Headless Navigation Menu Component
The Mishka Chelekom Headless Navigation Menu
ships zero opinionated styling
- only the semantic markup and full WAI-ARIA
wiring. Every
:item
with body content gets a trigger
and a hidden stored content
panel; a single shared positioner
to popup
to viewport
is rendered once and the engine moves the active
item's content into it, morphing the popup's width and height and sliding the
content via
data-activation-direction
.
Hover opens after a configurable delay; label-only or
href
items render a plain link. Every part - list, item, link, trigger, icon, content, positioner, popup,
viewport
and arrow
- is addressable through a
*_class
attribute, so you style it entirely with your own Tailwind
classes while
the accessibility and behavior keep working underneath.
Base UI Navigation Menu example - hero (Phoenix headless)
<.navigation_menu id="baseui-navigation_menu-hero" style="--duration: 0.35s; --easing: cubic-bezier(0.22, 1, 0.36, 1);" class="min-w-max text-neutral-950 dark:text-white" list_class="relative flex gap-px" trigger_class="flex h-8 items-center justify-center gap-1.5 bg-transparent px-2 text-sm font-normal text-neutral-950 no-underline select-none min-[501px]:px-3 hover:bg-neutral-100 data-[popup-open]:bg-neutral-100 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:text-white dark:hover:bg-neutral-800 dark:data-[popup-open]:bg-neutral-800" link_class="flex h-8 items-center justify-center gap-1.5 bg-transparent px-2 text-sm font-normal text-neutral-950 no-underline select-none min-[501px]:px-3 hover:bg-neutral-100 data-[popup-open]:bg-neutral-100 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:text-white dark:hover:bg-neutral-800 dark:data-[popup-open]:bg-neutral-800" icon_class="transition-transform duration-200 ease-[ease] data-[open]:rotate-180" positioner_class="h-[var(--positioner-height)] w-[var(--positioner-width)] max-w-[var(--available-width)] transition-[top,left,right,bottom] duration-[var(--duration)] ease-[var(--easing)] before:absolute before:content-[''] data-[instant]:transition-none data-[side=bottom]:before:top-[-10px] data-[side=bottom]:before:right-0 data-[side=bottom]:before:left-0 data-[side=bottom]:before:h-2.5 data-[side=left]:before:top-0 data-[side=left]:before:right-[-10px] data-[side=left]:before:bottom-0 data-[side=left]:before:w-2.5 data-[side=right]:before:top-0 data-[side=right]:before:bottom-0 data-[side=right]:before:left-[-10px] data-[side=right]:before:w-2.5 data-[side=top]:before:right-0 data-[side=top]:before:bottom-[-10px] data-[side=top]:before:left-0 data-[side=top]:before:h-2.5" popup_class="relative h-[var(--popup-height)] w-[var(--popup-width)] origin-[var(--transform-origin)] border border-neutral-950 bg-white text-neutral-950 shadow-[0.25rem_0.25rem_0] shadow-black/12 outline-none transition-[opacity,transform,width,height,scale] duration-[var(--duration)] ease-[var(--easing)] data-[ending-style]:scale-90 data-[ending-style]:opacity-0 data-[ending-style]:duration-150 data-[ending-style]:ease-[ease] data-[starting-style]:scale-90 data-[starting-style]:opacity-0 dark:border-white dark:bg-neutral-950 dark:text-white dark:shadow-none" arrow_class="relative block h-1.5 w-3 overflow-clip transition-[left,right] duration-[var(--duration)] ease-[var(--easing)] before:absolute before:bottom-0 before:left-1/2 before:block before:h-[calc(6px*sqrt(2))] before:w-[calc(6px*sqrt(2))] before:-translate-x-1/2 before:translate-y-1/2 before:rotate-45 before:border before:border-neutral-950 before:bg-white before:content-[''] data-[side=bottom]:top-[-6px] data-[side=left]:right-[-9px] data-[side=left]:rotate-90 data-[side=right]:left-[-9px] data-[side=right]:-rotate-90 data-[side=top]:bottom-[-6px] data-[side=top]:rotate-180 dark:before:border-white dark:before:bg-neutral-950" viewport_class="relative h-full w-full overflow-hidden" content_class="h-full w-[calc(100vw-40px)] p-2 min-[500px]:w-max min-[500px]:max-w-[400px] transition-[opacity,transform,translate] duration-[var(--duration)] ease-[var(--easing)] data-[starting-style]:opacity-0 data-[ending-style]:opacity-0 data-[starting-style]:data-[activation-direction=left]:translate-x-[-50%] data-[starting-style]:data-[activation-direction=right]:translate-x-[50%] data-[ending-style]:data-[activation-direction=left]:translate-x-[50%] data-[ending-style]:data-[activation-direction=right]:translate-x-[-50%]" > <:icon> <svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor" class="block"> <path d="M12 6H4l4 4.5z" /> </svg> </:icon> <:item label="Overview"> <ul class="m-0 grid list-none grid-cols-2 p-0 max-[500px]:grid-cols-1"> <li> <a href="#" class="relative block h-full w-full border-0 bg-transparent p-2 text-left text-inherit no-underline hover:bg-neutral-100 data-[popup-open]:bg-neutral-100 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:hover:bg-neutral-800 dark:data-[popup-open]:bg-neutral-800" > <h3 class="m-0 mb-1 text-sm leading-4 font-normal">Quick Start</h3> <p class="m-0 text-sm text-neutral-500 dark:text-neutral-400"> Install and assemble your first component. </p> </a> </li> <li> <a href="#" class="relative block h-full w-full border-0 bg-transparent p-2 text-left text-inherit no-underline hover:bg-neutral-100 data-[popup-open]:bg-neutral-100 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:hover:bg-neutral-800 dark:data-[popup-open]:bg-neutral-800" > <h3 class="m-0 mb-1 text-sm leading-4 font-normal">Accessibility</h3> <p class="m-0 text-sm text-neutral-500 dark:text-neutral-400"> Learn how we build accessible components. </p> </a> </li> <li> <a href="#" class="relative block h-full w-full border-0 bg-transparent p-2 text-left text-inherit no-underline hover:bg-neutral-100 data-[popup-open]:bg-neutral-100 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:hover:bg-neutral-800 dark:data-[popup-open]:bg-neutral-800" > <h3 class="m-0 mb-1 text-sm leading-4 font-normal">Releases</h3> <p class="m-0 text-sm text-neutral-500 dark:text-neutral-400"> See what's new in the latest Base UI versions. </p> </a> </li> <li> <a href="#" class="relative block h-full w-full border-0 bg-transparent p-2 text-left text-inherit no-underline hover:bg-neutral-100 data-[popup-open]:bg-neutral-100 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:hover:bg-neutral-800 dark:data-[popup-open]:bg-neutral-800" > <h3 class="m-0 mb-1 text-sm leading-4 font-normal">About</h3> <p class="m-0 text-sm text-neutral-500 dark:text-neutral-400"> Learn more about Base UI and our mission. </p> </a> </li> </ul> </:item> <:item label="Handbook"> <ul class="m-0 flex max-w-[400px] list-none flex-col justify-center p-0"> <li> <a href="#" class="relative block h-full w-full border-0 bg-transparent p-2 text-left text-inherit no-underline hover:bg-neutral-100 data-[popup-open]:bg-neutral-100 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:hover:bg-neutral-800 dark:data-[popup-open]:bg-neutral-800" > <h3 class="m-0 mb-1 text-sm leading-4 font-normal">Styling</h3> <p class="m-0 text-sm text-neutral-500 dark:text-neutral-400"> Base UI components can be styled with plain CSS, Tailwind CSS, CSS-in-JS, or CSS Modules. </p> </a> </li> <li> <a href="#" class="relative block h-full w-full border-0 bg-transparent p-2 text-left text-inherit no-underline hover:bg-neutral-100 data-[popup-open]:bg-neutral-100 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:hover:bg-neutral-800 dark:data-[popup-open]:bg-neutral-800" > <h3 class="m-0 mb-1 text-sm leading-4 font-normal">Animation</h3> <p class="m-0 text-sm text-neutral-500 dark:text-neutral-400"> Base UI components can be animated with CSS transitions, CSS animations, or JavaScript libraries. </p> </a> </li> <li> <a href="#" class="relative block h-full w-full border-0 bg-transparent p-2 text-left text-inherit no-underline hover:bg-neutral-100 data-[popup-open]:bg-neutral-100 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:hover:bg-neutral-800 dark:data-[popup-open]:bg-neutral-800" > <h3 class="m-0 mb-1 text-sm leading-4 font-normal">Composition</h3> <p class="m-0 text-sm text-neutral-500 dark:text-neutral-400"> Base UI components can be replaced and composed with your own existing components. </p> </a> </li> </ul> </:item> <:item label="GitHub" href="#" /> </.navigation_menu>
Base UI Navigation Menu example - nested (Phoenix headless)
<.navigation_menu id="baseui-navigation_menu-nested" style="--duration: 0.35s; --easing: cubic-bezier(0.22, 1, 0.36, 1);" class="min-w-max text-neutral-950 dark:text-white" list_class="relative flex gap-px" trigger_class="flex h-8 items-center justify-center gap-1.5 bg-transparent px-2 text-sm font-normal text-neutral-950 no-underline select-none min-[501px]:px-3 hover:bg-neutral-100 data-[popup-open]:bg-neutral-100 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:text-white dark:hover:bg-neutral-800 dark:data-[popup-open]:bg-neutral-800" icon_class="transition-transform duration-200 ease-[ease] data-[open]:rotate-180" positioner_class="h-[var(--positioner-height)] w-[var(--positioner-width)] max-w-[var(--available-width)] transition-[top,left,right,bottom] duration-[var(--duration)] ease-[var(--easing)] before:absolute before:content-[''] data-[instant]:transition-none data-[side=bottom]:before:top-[-10px] data-[side=bottom]:before:right-0 data-[side=bottom]:before:left-0 data-[side=bottom]:before:h-2.5 data-[side=left]:before:top-0 data-[side=left]:before:right-[-10px] data-[side=left]:before:bottom-0 data-[side=left]:before:w-2.5 data-[side=right]:before:top-0 data-[side=right]:before:bottom-0 data-[side=right]:before:left-[-10px] data-[side=right]:before:w-2.5 data-[side=top]:before:right-0 data-[side=top]:before:bottom-[-10px] data-[side=top]:before:left-0 data-[side=top]:before:h-2.5" popup_class="relative h-[var(--popup-height)] w-[var(--popup-width)] origin-[var(--transform-origin)] border border-neutral-950 bg-white text-neutral-950 shadow-[0.25rem_0.25rem_0] shadow-black/12 outline-none transition-[opacity,transform,width,height,scale] duration-[var(--duration)] ease-[var(--easing)] data-[ending-style]:scale-90 data-[ending-style]:opacity-0 data-[ending-style]:duration-150 data-[ending-style]:ease-[ease] data-[starting-style]:scale-90 data-[starting-style]:opacity-0 dark:border-white dark:bg-neutral-950 dark:text-white dark:shadow-none" arrow_class="relative block h-1.5 w-3 overflow-clip transition-[left,right] duration-[var(--duration)] ease-[var(--easing)] before:absolute before:bottom-0 before:left-1/2 before:block before:h-[calc(6px*sqrt(2))] before:w-[calc(6px*sqrt(2))] before:-translate-x-1/2 before:translate-y-1/2 before:rotate-45 before:border before:border-neutral-950 before:bg-white before:content-[''] data-[side=bottom]:top-[-6px] data-[side=left]:right-[-9px] data-[side=left]:rotate-90 data-[side=right]:left-[-9px] data-[side=right]:-rotate-90 data-[side=top]:bottom-[-6px] data-[side=top]:rotate-180 dark:before:border-white dark:before:bg-neutral-950" viewport_class="relative h-full w-full overflow-hidden" content_class="h-full w-[calc(100vw-40px)] p-2 min-[500px]:w-max min-[500px]:min-w-[400px] transition-[opacity,transform,translate] duration-[var(--duration)] ease-[var(--easing)] data-[starting-style]:opacity-0 data-[ending-style]:opacity-0 data-[starting-style]:data-[activation-direction=left]:translate-x-[-50%] data-[starting-style]:data-[activation-direction=right]:translate-x-[50%] data-[ending-style]:data-[activation-direction=left]:translate-x-[50%] data-[ending-style]:data-[activation-direction=right]:translate-x-[-50%]" > <:icon> <svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor" class="block"> <path d="M12 6H4l4 4.5z" /> </svg> </:icon> <:item label="Overview"> <ul class="m-0 grid list-none grid-cols-2 p-0 min-[640px]:grid-cols-[12rem_12rem]"> <li> <a href="#" class="relative block h-full w-full border-0 bg-transparent p-2 text-left text-inherit no-underline hover:bg-neutral-100 data-[popup-open]:bg-neutral-100 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:hover:bg-neutral-800 dark:data-[popup-open]:bg-neutral-800" > <h3 class="m-0 mb-1 text-sm leading-4 font-normal">Quick Start</h3> <p class="m-0 text-sm text-neutral-500 dark:text-neutral-400"> Install and assemble your first component. </p> </a> </li> <li> <a href="#" class="relative block h-full w-full border-0 bg-transparent p-2 text-left text-inherit no-underline hover:bg-neutral-100 data-[popup-open]:bg-neutral-100 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:hover:bg-neutral-800 dark:data-[popup-open]:bg-neutral-800" > <h3 class="m-0 mb-1 text-sm leading-4 font-normal">Accessibility</h3> <p class="m-0 text-sm text-neutral-500 dark:text-neutral-400"> Learn how we build accessible components. </p> </a> </li> <li> <a href="#" class="relative block h-full w-full border-0 bg-transparent p-2 text-left text-inherit no-underline hover:bg-neutral-100 data-[popup-open]:bg-neutral-100 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:hover:bg-neutral-800 dark:data-[popup-open]:bg-neutral-800" > <h3 class="m-0 mb-1 text-sm leading-4 font-normal">Releases</h3> <p class="m-0 text-sm text-neutral-500 dark:text-neutral-400"> See what's new in the latest Base UI versions. </p> </a> </li> <li class="relative"> <div class="m-0 flex w-full min-w-[10rem] flex-col items-start gap-1 border-0 bg-transparent p-2 text-left text-inherit hover:bg-neutral-100 data-[popup-open]:bg-neutral-100 dark:hover:bg-neutral-800 dark:data-[popup-open]:bg-neutral-800"> <span class="m-0 mb-1 text-sm leading-4 font-normal">Handbook</span> <p class="m-0 text-sm text-neutral-500 dark:text-neutral-400"> How to use Base UI effectively. </p> </div> <ul class="m-0 flex list-none flex-col justify-center p-0"> <li> <a href="#" class="relative block h-full w-full border-0 bg-transparent p-2 text-left text-inherit no-underline hover:bg-neutral-100 data-[popup-open]:bg-neutral-100 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:hover:bg-neutral-800 dark:data-[popup-open]:bg-neutral-800" > <h3 class="m-0 mb-1 text-sm leading-4 font-normal">Styling</h3> <p class="m-0 text-sm text-neutral-500 dark:text-neutral-400"> Base UI components can be styled with plain CSS, Tailwind CSS, CSS-in-JS, or CSS Modules. </p> </a> </li> <li> <a href="#" class="relative block h-full w-full border-0 bg-transparent p-2 text-left text-inherit no-underline hover:bg-neutral-100 data-[popup-open]:bg-neutral-100 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:hover:bg-neutral-800 dark:data-[popup-open]:bg-neutral-800" > <h3 class="m-0 mb-1 text-sm leading-4 font-normal">Animation</h3> <p class="m-0 text-sm text-neutral-500 dark:text-neutral-400"> Base UI components can be animated with CSS transitions, CSS animations, or JavaScript libraries. </p> </a> </li> <li> <a href="#" class="relative block h-full w-full border-0 bg-transparent p-2 text-left text-inherit no-underline hover:bg-neutral-100 data-[popup-open]:bg-neutral-100 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:hover:bg-neutral-800 dark:data-[popup-open]:bg-neutral-800" > <h3 class="m-0 mb-1 text-sm leading-4 font-normal">Composition</h3> <p class="m-0 text-sm text-neutral-500 dark:text-neutral-400"> Base UI components can be replaced and composed with your own existing components. </p> </a> </li> </ul> </li> </ul> </:item> </.navigation_menu>
Base UI Navigation Menu example - nested inline (Phoenix headless)
<.navigation_menu id="baseui-navigation_menu-nested-inline" style="--duration: 0.35s; --easing: cubic-bezier(0.22, 1, 0.36, 1);" class="min-w-max text-neutral-950 dark:text-white" list_class="relative flex gap-px" trigger_class="flex h-8 items-center justify-center gap-1.5 bg-transparent px-2 text-sm font-normal text-neutral-950 no-underline select-none min-[501px]:px-3 hover:bg-neutral-100 data-[popup-open]:bg-neutral-100 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:text-white dark:hover:bg-neutral-800 dark:data-[popup-open]:bg-neutral-800" link_class="flex h-8 items-center justify-center gap-1.5 bg-transparent px-2 text-sm font-normal text-neutral-950 no-underline select-none min-[501px]:px-3 hover:bg-neutral-100 data-[popup-open]:bg-neutral-100 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:text-white dark:hover:bg-neutral-800 dark:data-[popup-open]:bg-neutral-800" icon_class="transition-transform duration-200 ease-[ease] data-[open]:rotate-180" positioner_class="h-[var(--positioner-height)] w-[var(--positioner-width)] max-w-[var(--available-width)] transition-[top,left,right,bottom] duration-[var(--duration)] ease-[var(--easing)] before:absolute before:content-[''] data-[instant]:transition-none data-[side=bottom]:before:top-[-10px] data-[side=bottom]:before:right-0 data-[side=bottom]:before:left-0 data-[side=bottom]:before:h-2.5 data-[side=left]:before:top-0 data-[side=left]:before:right-[-10px] data-[side=left]:before:bottom-0 data-[side=left]:before:w-2.5 data-[side=right]:before:top-0 data-[side=right]:before:bottom-0 data-[side=right]:before:left-[-10px] data-[side=right]:before:w-2.5 data-[side=top]:before:right-0 data-[side=top]:before:bottom-[-10px] data-[side=top]:before:left-0 data-[side=top]:before:h-2.5" popup_class="relative h-[var(--popup-height)] w-[var(--popup-width)] origin-[var(--transform-origin)] border border-neutral-950 bg-white text-neutral-950 shadow-[0.25rem_0.25rem_0] shadow-black/12 outline-none transition-[opacity,transform,width,height,scale] duration-[var(--duration)] ease-[var(--easing)] data-[ending-style]:scale-90 data-[ending-style]:opacity-0 data-[ending-style]:duration-150 data-[ending-style]:ease-[ease] data-[ending-style]:transition-[opacity,scale] data-[starting-style]:scale-90 data-[starting-style]:opacity-0 dark:border-white dark:bg-neutral-950 dark:text-white dark:shadow-none" arrow_class="relative block h-1.5 w-3 overflow-clip transition-[left,right] duration-[var(--duration)] ease-[var(--easing)] before:absolute before:bottom-0 before:left-1/2 before:block before:h-[calc(6px*sqrt(2))] before:w-[calc(6px*sqrt(2))] before:-translate-x-1/2 before:translate-y-1/2 before:rotate-45 before:border before:border-neutral-950 before:bg-white before:content-[''] data-[side=bottom]:top-[-6px] data-[side=left]:right-[-9px] data-[side=left]:rotate-90 data-[side=right]:left-[-9px] data-[side=right]:-rotate-90 data-[side=top]:bottom-[-6px] data-[side=top]:rotate-180 dark:before:border-white dark:before:bg-neutral-950" viewport_class="relative h-full w-full overflow-hidden" content_class="h-full p-0 min-[700px]:[width:min(675px,calc(100vw-40px))] transition-[opacity,translate] duration-[calc(var(--duration)*0.5),var(--duration)] ease-[ease,cubic-bezier(0.4,0,0.2,1)] data-[starting-style]:data-[activation-direction=left]:opacity-0 data-[starting-style]:data-[activation-direction=right]:opacity-0 data-[ending-style]:opacity-0 data-[ending-style]:duration-[calc(var(--duration)*0.5)] data-[ending-style]:ease-[ease] data-[starting-style]:data-[activation-direction=left]:translate-x-[-2rem] data-[starting-style]:data-[activation-direction=right]:translate-x-[2rem] data-[ending-style]:data-[activation-direction=left]:translate-x-[2rem] data-[ending-style]:data-[activation-direction=right]:translate-x-[-2rem]" > <:icon> <svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor" class="block"> <path d="M12 6H4l4 4.5z" /> </svg> </:icon> <:item label="Product"> <div class="grid grid-cols-1 overflow-hidden overflow-clip min-[700px]:grid-cols-[13rem_minmax(0,1fr)]"> <ul class="m-0 flex list-none flex-row gap-1 overflow-x-auto p-2 min-[700px]:flex-col min-[700px]:gap-px min-[700px]:overflow-x-visible min-[700px]:overflow-y-clip min-[700px]:border-r min-[700px]:border-r-neutral-950 dark:min-[700px]:border-r-white"> <li> <div class="m-0 flex w-full min-w-[10rem] flex-col items-start gap-1 border-0 bg-transparent p-2 text-left text-inherit hover:bg-neutral-100 data-[popup-open]:bg-neutral-100 dark:hover:bg-neutral-800 dark:data-[popup-open]:bg-neutral-800"> <span class="text-sm leading-4 font-normal text-neutral-950 dark:text-white"> Developers </span> <span class="text-sm text-neutral-500 dark:text-neutral-400"> Go from idea to UI faster. </span> </div> </li> <li> <div class="m-0 flex w-full min-w-[10rem] flex-col items-start gap-1 border-0 bg-transparent p-2 text-left text-inherit hover:bg-neutral-100 data-[popup-open]:bg-neutral-100 dark:hover:bg-neutral-800 dark:data-[popup-open]:bg-neutral-800"> <span class="text-sm leading-4 font-normal text-neutral-950 dark:text-white"> Design Systems </span> <span class="text-sm text-neutral-500 dark:text-neutral-400"> Keep patterns aligned across teams. </span> </div> </li> <li> <div class="m-0 flex w-full min-w-[10rem] flex-col items-start gap-1 border-0 bg-transparent p-2 text-left text-inherit hover:bg-neutral-100 data-[popup-open]:bg-neutral-100 dark:hover:bg-neutral-800 dark:data-[popup-open]:bg-neutral-800"> <span class="text-sm leading-4 font-normal text-neutral-950 dark:text-white"> Engineering Leads </span> <span class="text-sm text-neutral-500 dark:text-neutral-400"> Roll out shared UI without drag. </span> </div> </li> <li> <div class="m-0 flex w-full min-w-[10rem] flex-col items-start gap-1 border-0 bg-transparent p-2 text-left text-inherit hover:bg-neutral-100 data-[popup-open]:bg-neutral-100 dark:hover:bg-neutral-800 dark:data-[popup-open]:bg-neutral-800"> <span class="text-sm leading-4 font-normal text-neutral-950 dark:text-white"> Startups </span> <span class="text-sm text-neutral-500 dark:text-neutral-400"> Ship polished basics while things change. </span> </div> </li> </ul> <div class="relative min-h-[16.5rem] overflow-hidden border-t border-neutral-950 min-[700px]:border-t-0 dark:border-white"> <div class="flex h-full flex-col gap-4 p-4"> <div> <h4 class="m-0 text-base leading-5 font-normal"> Build product UI without giving up control </h4> <p class="m-0 mt-1 text-sm text-neutral-500 dark:text-neutral-400"> Start with accessible parts and shape them to your app instead of working around a preset design system. </p> </div> <ul class="-mx-2 m-0 flex list-none flex-col gap-0 p-0"> <li> <a href="#" class="relative block h-full w-full border-0 bg-transparent p-2 text-left text-inherit no-underline hover:bg-neutral-100 data-[popup-open]:bg-neutral-100 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:hover:bg-neutral-800 dark:data-[popup-open]:bg-neutral-800" > <h5 class="m-0 text-sm leading-4 font-normal">Quick start</h5> <p class="m-0 text-sm text-neutral-500 dark:text-neutral-400"> Install Base UI and get your first interactive primitive on screen fast. </p> </a> </li> <li> <a href="#" class="relative block h-full w-full border-0 bg-transparent p-2 text-left text-inherit no-underline hover:bg-neutral-100 data-[popup-open]:bg-neutral-100 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:hover:bg-neutral-800 dark:data-[popup-open]:bg-neutral-800" > <h5 class="m-0 text-sm leading-4 font-normal">Composition</h5> <p class="m-0 text-sm text-neutral-500 dark:text-neutral-400"> Wrap and combine parts to match your product structure without hacks. </p> </a> </li> </ul> </div> </div> </div> </:item> <:item label="Learn"> <div class="flex flex-col gap-4 p-4 text-neutral-950 dark:text-white"> <div> <h4 class="m-0 text-base leading-5 font-normal">Where teams usually start</h4> <p class="m-0 mt-1 text-sm text-neutral-500 dark:text-neutral-400"> These are the docs people reach for first when they are turning a prototype into shared UI. </p> </div> <ul class="-mx-2 m-0 flex list-none flex-col gap-0 p-0"> <li> <a href="#" class="relative block h-full w-full border-0 bg-transparent p-2 text-left text-inherit no-underline hover:bg-neutral-100 data-[popup-open]:bg-neutral-100 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:hover:bg-neutral-800 dark:data-[popup-open]:bg-neutral-800" > <h5 class="m-0 text-sm leading-4 font-normal">Accessibility handbook</h5> <p class="m-0 text-sm text-neutral-500 dark:text-neutral-400"> Take a practical pass over focus order, semantics, and keyboard support. </p> </a> </li> <li> <a href="#" class="relative block h-full w-full border-0 bg-transparent p-2 text-left text-inherit no-underline hover:bg-neutral-100 data-[popup-open]:bg-neutral-100 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:hover:bg-neutral-800 dark:data-[popup-open]:bg-neutral-800" > <h5 class="m-0 text-sm leading-4 font-normal">Composition handbook</h5> <p class="m-0 text-sm text-neutral-500 dark:text-neutral-400"> Learn when to wrap parts, share behavior, and expose flexible APIs. </p> </a> </li> <li> <a href="#" class="relative block h-full w-full border-0 bg-transparent p-2 text-left text-inherit no-underline hover:bg-neutral-100 data-[popup-open]:bg-neutral-100 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:hover:bg-neutral-800 dark:data-[popup-open]:bg-neutral-800" > <h5 class="m-0 text-sm leading-4 font-normal">Styling handbook</h5> <p class="m-0 text-sm text-neutral-500 dark:text-neutral-400"> Apply tokens and state styles without fighting the underlying markup. </p> </a> </li> </ul> </div> </:item> <:item label="Releases" href="#" /> <:item label="GitHub" href="#" /> </.navigation_menu>
Parts & data attributes
Each part carries a stable
data-part
and a structural
chelekom-navigation_menu__*
class you can target, plus paired-presence state for open/closed transitions and
side/align placement.
Accessibility
Base UI's Navigation Menu has no dedicated WAI-ARIA pattern of its own, so this
component is built menubar-like, following the
WAI-ARIA Menubar pattern
. Arrow keys move focus between triggers along the configured orientation, a
cross-axis arrow or Enter/Space opens the dropdown, and
Escape
closes it, restoring focus to the trigger and tabbing out closes it as well.