apx-dsv0.1Local renderer · live
K
Foundations4
  • Getting started
  • Theming
  • Templates
  • Icons
  • Avatar
  • Badge
  • DataGrid
  • Scheduler
  • Stat
  • Table
  • Timeline
  • TreeView
  • Accordion
  • Alert
  • EmptyState
  • Progress
  • Skeleton
  • Spinner
  • SplashScreen
  • Toast
  • ColorPicker
  • FileUpload
  • Form
  • Rating
  • TagsInput
  • Combobox
  • Field
  • Select
  • Toggle
  • Button
  • Calendar
  • Checkbox
  • DatePicker
  • Input
  • NumberInput
  • Radio
  • Slider
  • Switch
  • Textarea
  • AppShell
  • Div
  • Divider
  • Sidebar
  • Stack
  • Typography
  • Image
  • Breadcrumbs
  • Carousel
  • NavigationMenu
  • Pagination
  • Stepper
  • Tabs
  • Toolbar
  • CommandPalette
  • Confirm
  • Drawer
  • HoverCard
  • Menu
  • Modal
  • Popover
  • Tooltip
  • Icon
  • Card
  • PricingCard
60 componentsapx-ds/renderer
NavigationMenu
Variant↳ other

Navigation

NavigationMenu

Horizontal top-nav with dropdowns and mega-menus, with W3C Menubar keyboard support and animated active-state indicator.

NavigationMenu

<NavigationMenu /> is the horizontal top-nav primitive — the menubar that sits inside a marketing header or a SaaS app's chrome. It pairs flat links with hoverable / clickable dropdown panels, and ships with the W3C Menubar keyboard pattern, an animated active-state indicator, and mega-menu support out of the box.

Overview — horizontal nav with dropdown

Loading preview…
Overview.tsx
  • Compound primitive: NavigationMenu.Item, .Trigger, .Link, .Content, .Group, .Featured, .Indicator.
  • W3C Menubar keyboard pattern — Arrow Left/Right between items (vertical: Up/Down), ArrowDown to open a dropdown, ArrowUp to close, Home/End for first/last, Esc to close, type-to-search.
  • Hover + click triggers — trigger="both" is the default (mouse + touch + keyboard all work); pin to 'hover' or 'click' for power-user surfaces.
  • Mega-menu — <NavigationMenu.Content variant="mega" columns={3}> widens the panel and lays children in a grid. Use <NavigationMenu.Group> for labeled columns + <NavigationMenu.Featured> for a promo slot.
  • Animated indicator — indicator prop turns on a single absolutely-positioned <div> that slides between items via CSS transforms. Tracks (in priority): the open dropdown → the focused trigger → the activeHref-matched item.
  • Active-state matching at the root via activeHref + activeMatchStrategy (exact / prefix). Each Link self-decides aria-current="page" via the shared isActiveHref helper (same one Sidebar uses).
  • asChild on Link / Trigger for router-Link integration.
  • Mobile collapse — mobileBreakpoint="md" hides the menu under md; AppShell's hamburger + Drawer take over.
  • i18n — en / he / ar bundles, <I18nProvider>-aware. Override per-instance via translations.

Anatomy

tsx
import { NavigationMenu } from 'apx-ds';

function TopNav({ activeHref }: { activeHref: string }) {
  return (
    <NavigationMenu activeHref={activeHref} indicator>
      <NavigationMenu.Item>
        <NavigationMenu.Trigger>Product</NavigationMenu.Trigger>
        <NavigationMenu.Content variant="mega" columns={3}>
          <NavigationMenu.Group label="Build">
            <NavigationMenu.Link href="/dev">Developers</NavigationMenu.Link>
            <NavigationMenu.Link href="/themes">Designers</NavigationMenu.Link>
          </NavigationMenu.Group>
          <NavigationMenu.Group label="Resources">
            <NavigationMenu.Link href="/docs">Docs</NavigationMenu.Link>
          </NavigationMenu.Group>
          <NavigationMenu.Featured>
            <Card>…showcase content…</Card>
          </NavigationMenu.Featured>
        </NavigationMenu.Content>
      </NavigationMenu.Item>

      <NavigationMenu.Item>
        <NavigationMenu.Link href="/pricing">Pricing</NavigationMenu.Link>
      </NavigationMenu.Item>

      <NavigationMenu.Item>
        <NavigationMenu.Link href="/docs">Docs</NavigationMenu.Link>
      </NavigationMenu.Item>
    </NavigationMenu>
  );
}
import { NavigationMenu } from 'apx-ds';

function TopNav({ activeHref }: { activeHref: string }) {
  return (
    <NavigationMenu activeHref={activeHref} indicator>
      <NavigationMenu.Item>
        <NavigationMenu.Trigger>Product</NavigationMenu.Trigger>
        <NavigationMenu.Content variant="mega" columns={3}>
          <NavigationMenu.Group label="Build">
            <NavigationMenu.Link href="/dev">Developers</NavigationMenu.Link>
            <NavigationMenu.Link href="/themes">Designers</NavigationMenu.Link>
          </NavigationMenu.Group>
          <NavigationMenu.Group label="Resources">
            <NavigationMenu.Link href="/docs">Docs</NavigationMenu.Link>
          </NavigationMenu.Group>
          <NavigationMenu.Featured>
            <Card>…showcase content…</Card>
          </NavigationMenu.Featured>
        </NavigationMenu.Content>
      </NavigationMenu.Item>

      <NavigationMenu.Item>
        <NavigationMenu.Link href="/pricing">Pricing</NavigationMenu.Link>
      </NavigationMenu.Item>

      <NavigationMenu.Item>
        <NavigationMenu.Link href="/docs">Docs</NavigationMenu.Link>
      </NavigationMenu.Item>
    </NavigationMenu>
  );
}

API — <NavigationMenu> root

PropTypeDefaultNotes
variantdefault · ghost · pilldefaultVisual chrome family.
sizesm · md · lgmdPropagates to subparts.
orientationhorizontal · verticalhorizontalLayout axis — keyboard arrows swap accordingly.
triggerclick · hover · bothbothDropdown interaction mode.
hoverDelaynumber150Ms before opening on pointer-enter.
closeDelaynumber250Ms before closing on pointer-leave.
indicatorbooleanfalseRender the animated underline / pill / bar.
indicatorVariantunderline · pill · barunderlineIndicator visual.
activeHrefstring—Current URL path.
activeMatchStrategyexact · prefixexactHow Links decide they're active.
valuestring · null—Controlled open dropdown id.
defaultValuestring—Initial open dropdown id.
onValueChange(value: string | null) => void—Fires when the open dropdown changes.
mobileBreakpointsm · md · lg · xl—Hide under this breakpoint (AppShell handoff).
translationsPartial<NavigationMenuTranslations>—Hard-coded translation override.
ariaLabelstring"Main navigation"<nav> accessible name.
ariaLabelledBystring—Alternative to ariaLabel.

Subparts

ComponentElementNotes
<NavigationMenu.Item><li role="none">Wraps a top-level entry. Auto-detects whether it has a Trigger / Link child.
<NavigationMenu.Trigger><button>Focusable dropdown opener; auto-renders a chevron. Supports asChild.
<NavigationMenu.Link><a>Top-level or panel link. Sets aria-current="page" when active. Supports asChild.
<NavigationMenu.Content><div role="menu">Portalled dropdown panel. variant="mega" switches to grid layout.
<NavigationMenu.Group><div> + <ul>Labeled column inside a mega-menu. Renders an <h3> for the visible label.
<NavigationMenu.Featured><div>Promo / showcase slot inside a mega-menu.
<NavigationMenu.Indicator><div>Auto-rendered when the root's indicator prop is on. Slides between items.

Keyboard

Top-level (focus on a Trigger or Link):

KeyAction
ArrowLeft / ArrowRight (LTR)Previous / next item. Wraps. Direction flips under RTL.
ArrowDownIf item has a dropdown → open + focus first link. Otherwise no-op.
ArrowUpIf a dropdown is open under this item → close it.
Home / EndFirst / last item.
Enter / SpaceActivate link / toggle dropdown.
EscClose any open dropdown; focus stays on trigger.
TabLeave NavigationMenu (single tab stop for the entire menubar).
Type-to-searchType letters within 500ms to jump to a matching item.

Inside an open dropdown:

KeyAction
ArrowDown / ArrowUpNext / previous link in the panel.
ArrowLeft / ArrowRightClose + focus previous / next top-level item.
Enter / SpaceActivate the focused link.
EscClose the panel; return focus to the trigger.
TabClose the panel; let the browser's natural tab order take over.

Accessibility

  • Root: <nav aria-label="Main navigation"> (i18n-driven label) wrapping <ul role="menubar">.
  • Item: <li role="none"> — purely structural, not focusable.
  • Trigger: <button role="menuitem" aria-haspopup="menu" aria-expanded={open} aria-controls={contentId}>.
  • Link: <a role="menuitem" aria-current={isActive ? "page" : undefined}>.
  • Content: <div role="menu" aria-labelledby={triggerId}> portalled at the body root.
  • Roving tabindex across all top-level items — exactly one is in the tab order at a time.
  • Indicator is aria-hidden="true".
  • axe-core: 0 violations across all variants and orientations.

RTL

  • flex-direction: row flips browser-natively.
  • ArrowLeft / ArrowRight semantically swap.
  • Indicator x calculation handles RTL math (uses logical start / end).
  • Dropdown anchoring inherits Floating UI's RTL handling.
  • Logical-only padding / margin classes (ms-*, me-*, start-*, end-*).

i18n

Three bundles ship out of the box: DEFAULT_NAVIGATION_MENU_TRANSLATIONS (en), HE_NAVIGATION_MENU_TRANSLATIONS, AR_NAVIGATION_MENU_TRANSLATIONS. Wire them via <I18nProvider messages={{ navigationMenu: HE_NAVIGATION_MENU_TRANSLATIONS }}> or pass them directly via <NavigationMenu translations={…}>.

KeyDefault (en)Notes
label"Main navigation"<nav> accessible name.
toggleSection"Toggle menu"Trigger sr-only label (only used when label is non-string).
activeItem"current page"sr-only suffix after the active link.

Examples

Overview

Loading preview…
Overview.tsx

Basic links — flat nav with activeHref

Loading preview…
BasicLinks.tsx

With dropdown — trigger + content panel

Loading preview…
WithDropdown.tsx

Mega menu — multi-column grid layout

Loading preview…
MegaMenu.tsx

Mega menu with featured promo slot

Loading preview…
MegaMenuWithFeatured.tsx

Stripe-like demo — full marketing header

Loading preview…
StripeLikeDemo.tsx

Active indicator — underline / pill / bar

Loading preview…
ActiveIndicator.tsx

Indicator pill variant

Loading preview…
IndicatorPill.tsx

Variants — default / ghost / pill

Loading preview…
Variants.tsx

Sizes — sm / md / lg

Loading preview…
Sizes.tsx

Vertical orientation — side-rail nav

Loading preview…
Vertical.tsx

Hover only — pointer-enter trigger

Loading preview…
HoverOnly.tsx

Click only — intentional open

Loading preview…
ClickOnly.tsx

Hover vs click vs both

Loading preview…
HoverVsClick.tsx

Controlled activeHref

Loading preview…
ActiveHrefControlled.tsx

Mobile collapse — hide below breakpoint

Loading preview…
MobileCollapse.tsx

Router link integration — asChild

Loading preview…
RouterLinkIntegration.tsx

More examples

_icons

Loading preview…
_icons.tsx

Props

PropTypeDefaultDescription
activeHrefstring—The current page's URL — items self-compare against this to set `aria-current`.
activeMatchStrategyenum—Active matching strategy. Default: `'exact'`.
ariaLabelstring—Override the `<nav>` aria-label. Default: `translations.label` ("Main navigation" in en).
ariaLabelledBystring—Override the `<nav>` aria-labelledby (in place of `ariaLabel`).
classNamestring——
closeDelaynumber—Close delay (ms) for hover trigger. Default: `250`.
defaultValuestring—Initial open dropdown id (uncontrolled).
hoverDelaynumber—Open delay (ms) for hover trigger. Default: `150`.
indicatorboolean—Render an animated indicator under the active / focused item. Default: `false`.
indicatorVariantenum—Indicator variant. Default: `'underline'`.
mobileBreakpointenum—Below this breakpoint the menu collapses (renders nothing). Default: undefined (always visible).
onValueChange(value: string | null) => void—Fires whenever the open dropdown id changes.
orientationenum—Layout axis. Default: `'horizontal'`.
sizeenum—Size scale propagated to subparts. Default: `'md'`.
styleCSSProperties——
sxSx——
translationsPartial<NavigationMenuTranslations>—Override translations directly (skips `<I18nProvider>` lookup).
triggerenum—Trigger interaction mode. Default: `'both'`.
valuestring | null—Controlled open dropdown id (or `null` for closed).
variantenum—Visual chrome family. Default: `'default'`.