Component

navigation menu

dx components add navigation_menu

A collection of links and disclosure panels for site navigation.

Installation

Use the CLI command for the common path, or copy the component files manually.

Manual installation files

Copy the component source and CSS into your app. Import the shared theme CSS once near your app root.

use dioxus::prelude::*;
use dioxus_icons::lucide::ChevronDown;
use dioxus_primitives::navigation_menu::{
    self, NavigationMenuContentProps, NavigationMenuItemProps, NavigationMenuLinkProps,
    NavigationMenuListProps, NavigationMenuProps, NavigationMenuTriggerProps,
};

#[component]
pub fn NavigationMenu(props: NavigationMenuProps) -> Element {
    rsx! {
        document::Link { rel: "stylesheet", href: asset!("/src/components/navigation_menu/style.css") }
        navigation_menu::NavigationMenu {
            class: "dx-navigation-menu",
            disabled: props.disabled,
            attributes: props.attributes,
            {props.children}
        }
    }
}

#[component]
pub fn NavigationMenuList(props: NavigationMenuListProps) -> Element {
    rsx! {
        document::Link { rel: "stylesheet", href: asset!("/src/components/navigation_menu/style.css") }
        navigation_menu::NavigationMenuList {
            class: "dx-navigation-menu-list",
            attributes: props.attributes,
            {props.children}
        }
    }
}

#[component]
pub fn NavigationMenuItem(props: NavigationMenuItemProps) -> Element {
    rsx! {
        document::Link { rel: "stylesheet", href: asset!("/src/components/navigation_menu/style.css") }
        navigation_menu::NavigationMenuItem {
            class: "dx-navigation-menu-item",
            index: props.index,
            disabled: props.disabled,
            attributes: props.attributes,
            {props.children}
        }
    }
}

#[component]
pub fn NavigationMenuTrigger(props: NavigationMenuTriggerProps) -> Element {
    rsx! {
        document::Link { rel: "stylesheet", href: asset!("/src/components/navigation_menu/style.css") }
        navigation_menu::NavigationMenuTrigger {
            class: "dx-navigation-menu-trigger",
            id: props.id,
            attributes: props.attributes,
            {props.children}
            ChevronDown {
                class: "dx-navigation-menu-expand-icon",
                size: "16px",
                stroke: "currentColor",
            }
        }
    }
}

#[component]
pub fn NavigationMenuContent(props: NavigationMenuContentProps) -> Element {
    rsx! {
        document::Link { rel: "stylesheet", href: asset!("/src/components/navigation_menu/style.css") }
        navigation_menu::NavigationMenuContent {
            class: "dx-navigation-menu-content",
            id: props.id,
            attributes: props.attributes,
            {props.children}
        }
    }
}

#[component]
pub fn NavigationMenuLink(props: NavigationMenuLinkProps) -> Element {
    rsx! {
        document::Link { rel: "stylesheet", href: asset!("/src/components/navigation_menu/style.css") }
        navigation_menu::NavigationMenuLink {
            class: "dx-navigation-menu-link",
            active: props.active,
            disabled: props.disabled,
            content_index: props.content_index,
            onclick: props.onclick,
            attributes: props.attributes,
            {props.children}
        }
    }
}

Usage notes

The NavigationMenu component displays a collection of links and disclosure panels for site navigation.

Unlike Navbar, which implements the APG Menu and Menubar pattern (role="menubar"/"menu"/"menuitem", roving tabindex), NavigationMenu implements the APG Disclosure (Show/Hide) Navigation pattern: plain links and button[aria-expanded][aria-controls] disclosure triggers, with no menu role anywhere. Every trigger and link keeps its native tab stop, so Tab/Shift+Tab move through them (and, once a panel is open, through its links) in DOM order -- there is no roving-focus collection to manage. Use this component for real site navigation; use Navbar (or Menubar) when you need the fuller menu-button keyboard contract.

Component Structure

// The NavigationMenu component wraps the whole nav landmark. It needs an
// accessible name -- pass `aria_label` or `aria_labelledby`.
NavigationMenu {
    aria_label: "Main",
    // The NavigationMenuList is the `ul` that holds the top-level items.
    NavigationMenuList {
        // Each NavigationMenuItem is one top-level entry, in order of its index.
        NavigationMenuItem {
            index: 0usize,
            // A trigger discloses a panel of links on click or hover.
            NavigationMenuTrigger { "Components" }
            NavigationMenuContent {
                // Compose any markup here -- typically a grid of links.
                NavigationMenuLink { href: "/component/?name=accordion", "Accordion" }
                NavigationMenuLink { href: "/component/?name=dialog", "Dialog" }
            }
        }
        NavigationMenuItem {
            index: 1usize,
            // Or an item can be a single plain link with no panel.
            NavigationMenuLink { href: "/docs", "Docs" }
        }
    }
}

Keyboard interaction

  • Enter / Space: activates a focused trigger, toggling its panel.
  • Escape: closes the open panel and returns focus to its trigger.
  • Tab / Shift+Tab: move through every top-level trigger/link, and (once a panel is open) through its links, in page order.
  • Left / Right arrow (optional in APG, supported here): move between top-level items.
  • Home / End (optional in APG, supported here): move to the first/last top-level item.
  • Down arrow on a trigger: opens its panel (if not already open) and moves focus into its first link.
  • Up / Down arrow on a link inside an open panel (optional in APG, supported here): move to the previous/next link in that panel, stopping at the first/last link rather than wrapping.
  • Moving focus out of the whole navigation menu closes an open panel.