MobileNavigationRoot
Full-screen fixed overlay that hosts the mobile navigation; hidden from lg up.
Carries modal-dialog semantics: focus is trapped inside the overlay while it is
mounted, cycles with Tab, and returns to the trigger once it unmounts. Pressing
Escape invokes onClose. The accessible name defaults to "Navigation menu" and
can be overridden via aria-label.
Renders an m.div, so consumers can drive enter/exit motion (e.g. a slide) by
passing initial/animate/exit/transition and wrapping in AnimatePresence.
With no motion props it renders statically. Horizontal overflow is clipped
(overflow-x-clip) so a nested drill-in view sliding off-screen never spawns a
horizontal scrollbar; vertical content still scrolls.
Usage
import { mobileNavigationAnatomy, MobileNavigationAppHeader, MobileNavigationBrandLockup, MobileNavigationBrandTrigger, MobileNavigationCenteredPanel, MobileNavigationCenteredText, MobileNavigationContent, MobileNavigationDrawerContent, MobileNavigationDrawerProfile, MobileNavigationDrawerProfileProps, MobileNavigationDrawerSection, MobileNavigationDrawerStack, MobileNavigationFrame, MobileNavigationFullWidthAction, MobileNavigationHeader, MobileNavigationHeaderAction, MobileNavigationHeaderSearchSlot, MobileNavigationItem, MobileNavigationItemProps, MobileNavigationList, MobileNavigationProfileAction, MobileNavigationProfileActionProps, MobileNavigationProjectItem, MobileNavigationProjectItemProps, MobileNavigationRoot, MobileNavigationSeparator, MobileNavigationSlottedText } from "@desk/ui/components/mobile-navigation";Best practices
Wire
onCloseto your open-state setter — the overlay traps focus and fires it on Escape, but you own mounting/unmounting.It's
role="dialog"+aria-modaland hidden fromlgup, so pair it with a desktop nav rather than showing both at once.Override the default "Navigation menu" accessible name via
aria-labelwhen the drawer's purpose is more specific.
Props
MobileNavigationBrandLockup
| Prop | Type | Default | Description |
|---|---|---|---|
| align | ResponsiveValue<FlexAlign> | "stretch" | Cross-axis alignment. Accepts a per-breakpoint responsive object. |
| as | "div" | "li" | "nav" | "ol" | "span" | "ul" | "article" | "aside" | "figcaption" | "figure" | "footer" | "header" | "main" | "section" | Render as a different host element from the closed layout vocabulary
({@link LayoutElement}). The set is deliberately closed: | |
| direction | ResponsiveValue<FlexDirection> | "row" | Main-axis direction. Accepts a per-breakpoint responsive object. |
| gap | ResponsiveValue<"base" | "none" | "2xs" | "xs" | "sm" | "lg" | "xl" | "2xl" | "3xl" | "3xs"> | Gap between items, from the spacing scale. Accepts a per-breakpoint responsive object. | |
| guidelines | boolean | false | Show dashed outline guidelines during development. |
| inline | boolean | false | Render as inline-flex instead of flex. |
| justify | ResponsiveValue<FlexJustify> | "flex-start" | Main-axis distribution. Accepts a per-breakpoint responsive object. |
| responsiveMode | ResponsiveMode | "screen" | Whether responsive values resolve against the viewport ("screen") or nearest container ("container"). |
| wrap | ResponsiveValue<FlexWrap> | "nowrap" | Wrap behavior. Accepts a per-breakpoint responsive object. |
MobileNavigationBrandTrigger
| Prop | Type | Default | Description |
|---|---|---|---|
| asChild | boolean | undefined | false | Merge props and styling onto the single child element via Slot. |
| tone | "neutral" | "brand" | "danger" | null | undefined | ||
| radius | "rounded" | "square" | "full" | null | undefined | ||
| size | ButtonSizeProp | "base" | Size token; |
| dot | string | undefined | CSS colour for a status dot; empty/undefined renders no dot. | |
| loading | boolean | undefined | false | Show a spinner and disable interaction. |
| square | boolean | null | undefined | ||
| emphasis | "link" | "outline" | "solid" | "ghost" | "soft" | "transparent" | null | undefined | ||
| asInput | boolean | null | undefined | ||
| align | "center" | "end" | "start" | null | undefined | ||
| pressed | boolean | null | undefined | ||
| testId | string | ||
| suffixIcon | IconComponent | undefined | Trailing icon (Lucide or SVG component) rendered at the end. | |
| loadingLabel | string | undefined | Label shown in place of | |
| iconClassName | string | undefined | Extra classes for the leading icon. | |
| suffixIconClassName | string | undefined | Extra classes for the trailing icon. | |
| dotPlacement | "end" | "start" | undefined | "start" | Dot position relative to content. |
| expandable | boolean | undefined | false | Icon-only at rest; expands on hover/focus-visible to reveal the label
to the right of the icon. Collapsed geometry equals the matching icon-*
size, expanded equals the text button of that size — so pass a text
size ( |
| focused | boolean | undefined | Force the focus ring on — for documentation/testing only. | |
| hovered | boolean | undefined | Force the hover state on — for documentation/testing only. |
MobileNavigationCenteredPanel
| Prop | Type | Default | Description |
|---|---|---|---|
| asChild | boolean | false | Merge props onto the single child element instead of rendering a div. |
| gap | ResponsiveValue<"base" | "none" | "2xs" | "xs" | "sm" | "lg" | "xl" | "2xl" | "3xl" | "3xs"> | "base" | Gap between items, from the spacing scale. Accepts a per-breakpoint responsive object. |
| align | ResponsiveValue<FlexAlign> | "stretch" | Cross-axis alignment. Accepts a per-breakpoint responsive object. |
| justify | ResponsiveValue<FlexJustify> | "flex-start" | Main-axis distribution. Accepts a per-breakpoint responsive object. |
| responsiveMode | ResponsiveMode | "screen" | Whether responsive values resolve against the viewport ("screen") or nearest container ("container"). |
| as | "div" | "li" | "nav" | "ol" | "span" | "ul" | "article" | "aside" | "figcaption" | "figure" | "footer" | "header" | "main" | "section" | Render as a different host element from the closed layout vocabulary
({@link LayoutElement}). The set is deliberately closed: | |
| guidelines | boolean | false | Show dashed outline guidelines during development. |
MobileNavigationCenteredText
| Prop | Type | Default | Description |
|---|---|---|---|
| as | "li" | "p" | "span" | "dd" | "dt" | "figcaption" | "legend" | Render as a different host element from the closed text vocabulary
({@link TextElement}). The set is deliberately closed and text-only:
| |
| size | ResponsiveValue<"base" | "2xs" | "xs" | "sm" | "lg" | "xl" | "2xl" | "3xl"> | Text size — accepts a static size or responsive object like | |
| variant | "default" | "muted" | "accent" | Text color variant | |
| weight | "normal" | "medium" | "semibold" | Font weight | |
| asChild | boolean | Merge props onto child element using Slot |
MobileNavigationDrawerContent
| Prop | Type | Default | Description |
|---|---|---|---|
| showHandle | boolean | true | Show the drag handle (bottom drawers). |
MobileNavigationDrawerProfile
| Prop | Type | Default | Description |
|---|---|---|---|
| displayName | string | ||
string | undefined | Secondary line under the name; hidden when absent. | ||
| userAvatarName | string | undefined | Name used to derive the avatar initials fallback. | |
| userAvatarUrl | string | null | undefined | Avatar image URL; falls back to initials when absent. |
MobileNavigationDrawerSection
| Prop | Type | Default | Description |
|---|---|---|---|
| asChild | boolean | false | Merge props onto the single child element instead of rendering a div. |
| gap | ResponsiveValue<"base" | "none" | "2xs" | "xs" | "sm" | "lg" | "xl" | "2xl" | "3xl" | "3xs"> | "base" | Gap between items, from the spacing scale. Accepts a per-breakpoint responsive object. |
| align | ResponsiveValue<FlexAlign> | "stretch" | Cross-axis alignment. Accepts a per-breakpoint responsive object. |
| justify | ResponsiveValue<FlexJustify> | "flex-start" | Main-axis distribution. Accepts a per-breakpoint responsive object. |
| responsiveMode | ResponsiveMode | "screen" | Whether responsive values resolve against the viewport ("screen") or nearest container ("container"). |
| as | "div" | "li" | "nav" | "ol" | "span" | "ul" | "article" | "aside" | "figcaption" | "figure" | "footer" | "header" | "main" | "section" | Render as a different host element from the closed layout vocabulary
({@link LayoutElement}). The set is deliberately closed: | |
| guidelines | boolean | false | Show dashed outline guidelines during development. |
MobileNavigationDrawerStack
| Prop | Type | Default | Description |
|---|---|---|---|
| asChild | boolean | false | Merge props onto the single child element instead of rendering a div. |
| gap | ResponsiveValue<"base" | "none" | "2xs" | "xs" | "sm" | "lg" | "xl" | "2xl" | "3xl" | "3xs"> | "base" | Gap between items, from the spacing scale. Accepts a per-breakpoint responsive object. |
| align | ResponsiveValue<FlexAlign> | "stretch" | Cross-axis alignment. Accepts a per-breakpoint responsive object. |
| justify | ResponsiveValue<FlexJustify> | "flex-start" | Main-axis distribution. Accepts a per-breakpoint responsive object. |
| responsiveMode | ResponsiveMode | "screen" | Whether responsive values resolve against the viewport ("screen") or nearest container ("container"). |
| as | "div" | "li" | "nav" | "ol" | "span" | "ul" | "article" | "aside" | "figcaption" | "figure" | "footer" | "header" | "main" | "section" | Render as a different host element from the closed layout vocabulary
({@link LayoutElement}). The set is deliberately closed: | |
| guidelines | boolean | false | Show dashed outline guidelines during development. |
MobileNavigationFrame
| Prop | Type | Default | Description |
|---|---|---|---|
| asChild | boolean | false | Merge props onto the single child element instead of rendering a div. |
| gap | ResponsiveValue<"base" | "none" | "2xs" | "xs" | "sm" | "lg" | "xl" | "2xl" | "3xl" | "3xs"> | "base" | Gap between items, from the spacing scale. Accepts a per-breakpoint responsive object. |
| align | ResponsiveValue<FlexAlign> | "stretch" | Cross-axis alignment. Accepts a per-breakpoint responsive object. |
| justify | ResponsiveValue<FlexJustify> | "flex-start" | Main-axis distribution. Accepts a per-breakpoint responsive object. |
| responsiveMode | ResponsiveMode | "screen" | Whether responsive values resolve against the viewport ("screen") or nearest container ("container"). |
| as | "div" | "li" | "nav" | "ol" | "span" | "ul" | "article" | "aside" | "figcaption" | "figure" | "footer" | "header" | "main" | "section" | Render as a different host element from the closed layout vocabulary
({@link LayoutElement}). The set is deliberately closed: | |
| guidelines | boolean | false | Show dashed outline guidelines during development. |
MobileNavigationFullWidthAction
| Prop | Type | Default | Description |
|---|---|---|---|
| tone | "neutral" | "brand" | "danger" | null | undefined | ||
| radius | "rounded" | "square" | "full" | null | undefined | ||
| square | boolean | null | undefined | ||
| emphasis | "link" | "outline" | "solid" | "ghost" | "soft" | "transparent" | null | undefined | ||
| asInput | boolean | null | undefined | ||
| align | "center" | "end" | "start" | null | undefined | ||
| pressed | boolean | null | undefined | ||
| size | ButtonSizeProp | "base" | Size token; |
| asChild | boolean | undefined | false | Merge props and styling onto the single child element via Slot. |
| loading | boolean | undefined | false | Show a spinner and disable interaction. |
| loadingLabel | string | undefined | Label shown in place of | |
| icon | IconComponent | undefined | Leading icon (Lucide or SVG component); with no children it becomes an icon-only button. | |
| iconClassName | string | undefined | Extra classes for the leading icon. | |
| suffixIcon | IconComponent | undefined | Trailing icon (Lucide or SVG component) rendered at the end. | |
| suffixIconClassName | string | undefined | Extra classes for the trailing icon. | |
| dot | string | undefined | CSS colour for a status dot; empty/undefined renders no dot. | |
| dotPlacement | "end" | "start" | undefined | "start" | Dot position relative to content. |
| expandable | boolean | undefined | false | Icon-only at rest; expands on hover/focus-visible to reveal the label
to the right of the icon. Collapsed geometry equals the matching icon-*
size, expanded equals the text button of that size — so pass a text
size ( |
| focused | boolean | undefined | Force the focus ring on — for documentation/testing only. | |
| hovered | boolean | undefined | Force the hover state on — for documentation/testing only. | |
| testId | string |
MobileNavigationHeader
| Prop | Type | Default | Description |
|---|---|---|---|
| direction | ResponsiveValue<FlexDirection> | "row" | Main-axis direction. Accepts a per-breakpoint responsive object. |
| gap | ResponsiveValue<"base" | "none" | "2xs" | "xs" | "sm" | "lg" | "xl" | "2xl" | "3xl" | "3xs"> | Gap between items, from the spacing scale. Accepts a per-breakpoint responsive object. | |
| inline | boolean | false | Render as inline-flex instead of flex. |
| wrap | ResponsiveValue<FlexWrap> | "nowrap" | Wrap behavior. Accepts a per-breakpoint responsive object. |
| align | ResponsiveValue<FlexAlign> | "stretch" | Cross-axis alignment. Accepts a per-breakpoint responsive object. |
| justify | ResponsiveValue<FlexJustify> | "flex-start" | Main-axis distribution. Accepts a per-breakpoint responsive object. |
| responsiveMode | ResponsiveMode | "screen" | Whether responsive values resolve against the viewport ("screen") or nearest container ("container"). |
| as | "div" | "li" | "nav" | "ol" | "span" | "ul" | "article" | "aside" | "figcaption" | "figure" | "footer" | "header" | "main" | "section" | Render as a different host element from the closed layout vocabulary
({@link LayoutElement}). The set is deliberately closed: | |
| guidelines | boolean | false | Show dashed outline guidelines during development. |
| onClose | () => void |
MobileNavigationHeaderAction
| Prop | Type | Default | Description |
|---|---|---|---|
| asChild | boolean | undefined | false | Merge props and styling onto the single child element via Slot. |
| tone | "neutral" | "brand" | "danger" | null | undefined | ||
| radius | "rounded" | "square" | "full" | null | undefined | ||
| size | ButtonSizeProp | "base" | Size token; |
| dot | string | undefined | CSS colour for a status dot; empty/undefined renders no dot. | |
| loading | boolean | undefined | false | Show a spinner and disable interaction. |
| square | boolean | null | undefined | ||
| icon | IconComponent | undefined | Leading icon (Lucide or SVG component); with no children it becomes an icon-only button. | |
| emphasis | "link" | "outline" | "solid" | "ghost" | "soft" | "transparent" | null | undefined | ||
| asInput | boolean | null | undefined | ||
| align | "center" | "end" | "start" | null | undefined | ||
| pressed | boolean | null | undefined | ||
| testId | string | ||
| suffixIcon | IconComponent | undefined | Trailing icon (Lucide or SVG component) rendered at the end. | |
| loadingLabel | string | undefined | Label shown in place of | |
| iconClassName | string | undefined | Extra classes for the leading icon. | |
| suffixIconClassName | string | undefined | Extra classes for the trailing icon. | |
| dotPlacement | "end" | "start" | undefined | "start" | Dot position relative to content. |
| expandable | boolean | undefined | false | Icon-only at rest; expands on hover/focus-visible to reveal the label
to the right of the icon. Collapsed geometry equals the matching icon-*
size, expanded equals the text button of that size — so pass a text
size ( |
| focused | boolean | undefined | Force the focus ring on — for documentation/testing only. | |
| hovered | boolean | undefined | Force the hover state on — for documentation/testing only. |
MobileNavigationItem
| Prop | Type | Default | Description |
|---|---|---|---|
| active | boolean | Mark the row as the current location (adds a filled background). | |
| asChild | boolean | false | Render as the single child element (e.g. a link) instead of a button. |
| children | React.ReactNode | ||
| destructive | boolean | Render the label in the destructive color. | |
| dot | boolean | "neutral" | "brand" | "danger" | "warning" | "success" | "info" | Show a status dot in place of the leading icon. | |
| icon | import("../../tokens/icon-component").IconComponent | Leading icon; omit to reserve leading space with no glyph. | |
| label | React.ReactNode | Row text (required). | |
| suffixIcon | import("../../tokens/icon-component").IconComponent | Trailing icon shown after the label. | |
| tone | "neutral" | "brand" | "danger" | null | undefined | ||
| radius | "rounded" | "square" | "full" | null | undefined | ||
| size | ButtonSizeProp | "base" | Size token; |
| loading | boolean | undefined | false | Show a spinner and disable interaction. |
| square | boolean | null | undefined | ||
| emphasis | "link" | "outline" | "solid" | "ghost" | "soft" | "transparent" | null | undefined | ||
| asInput | boolean | null | undefined | ||
| align | "center" | "end" | "start" | null | undefined | ||
| pressed | boolean | null | undefined | ||
| testId | string | ||
| loadingLabel | string | undefined | Label shown in place of | |
| iconClassName | string | undefined | Extra classes for the leading icon. | |
| suffixIconClassName | string | undefined | Extra classes for the trailing icon. | |
| dotPlacement | "end" | "start" | undefined | "start" | Dot position relative to content. |
| expandable | boolean | undefined | false | Icon-only at rest; expands on hover/focus-visible to reveal the label
to the right of the icon. Collapsed geometry equals the matching icon-*
size, expanded equals the text button of that size — so pass a text
size ( |
| focused | boolean | undefined | Force the focus ring on — for documentation/testing only. | |
| hovered | boolean | undefined | Force the hover state on — for documentation/testing only. |
MobileNavigationList
| Prop | Type | Default | Description |
|---|---|---|---|
| asChild | boolean | false | Merge props onto the single child element instead of rendering a div. |
| gap | ResponsiveValue<"base" | "none" | "2xs" | "xs" | "sm" | "lg" | "xl" | "2xl" | "3xl" | "3xs"> | "base" | Gap between items, from the spacing scale. Accepts a per-breakpoint responsive object. |
| align | ResponsiveValue<FlexAlign> | "stretch" | Cross-axis alignment. Accepts a per-breakpoint responsive object. |
| justify | ResponsiveValue<FlexJustify> | "flex-start" | Main-axis distribution. Accepts a per-breakpoint responsive object. |
| responsiveMode | ResponsiveMode | "screen" | Whether responsive values resolve against the viewport ("screen") or nearest container ("container"). |
| as | "div" | "li" | "nav" | "ol" | "span" | "ul" | "article" | "aside" | "figcaption" | "figure" | "footer" | "header" | "main" | "section" | Render as a different host element from the closed layout vocabulary
({@link LayoutElement}). The set is deliberately closed: | |
| guidelines | boolean | false | Show dashed outline guidelines during development. |
MobileNavigationProfileAction
| Prop | Type | Default | Description |
|---|---|---|---|
| avatarName | string | undefined | Name used to derive the avatar initials fallback. | |
| displayName | string | User's display name shown as the button label. | |
| loading | boolean | false | Show a loading label and disable the button. |
| userAvatarUrl | string | null | undefined | Avatar image URL; falls back to initials when absent. | |
| asChild | boolean | undefined | false | Merge props and styling onto the single child element via Slot. |
| tone | "neutral" | "brand" | "danger" | null | undefined | ||
| radius | "rounded" | "square" | "full" | null | undefined | ||
| size | ButtonSizeProp | "base" | Size token; |
| dot | string | undefined | CSS colour for a status dot; empty/undefined renders no dot. | |
| square | boolean | null | undefined | ||
| icon | IconComponent | undefined | Leading icon (Lucide or SVG component); with no children it becomes an icon-only button. | |
| emphasis | "link" | "outline" | "solid" | "ghost" | "soft" | "transparent" | null | undefined | ||
| asInput | boolean | null | undefined | ||
| align | "center" | "end" | "start" | null | undefined | ||
| pressed | boolean | null | undefined | ||
| testId | string | ||
| suffixIcon | IconComponent | undefined | Trailing icon (Lucide or SVG component) rendered at the end. | |
| loadingLabel | string | undefined | Label shown in place of | |
| iconClassName | string | undefined | Extra classes for the leading icon. | |
| suffixIconClassName | string | undefined | Extra classes for the trailing icon. | |
| dotPlacement | "end" | "start" | undefined | "start" | Dot position relative to content. |
| expandable | boolean | undefined | false | Icon-only at rest; expands on hover/focus-visible to reveal the label
to the right of the icon. Collapsed geometry equals the matching icon-*
size, expanded equals the text button of that size — so pass a text
size ( |
| focused | boolean | undefined | Force the focus ring on — for documentation/testing only. | |
| hovered | boolean | undefined | Force the hover state on — for documentation/testing only. |
MobileNavigationProjectItem
| Prop | Type | Default | Description |
|---|---|---|---|
| active | boolean | Mark the project as current (dot indicator + filled background). | |
| archived | boolean | Dim the label to indicate an archived project. | |
| children | React.ReactNode | ||
| label | React.ReactNode | ||
| onAction | () => void | Invoked when the trailing action button is pressed. | |
| actionIcon | import("../../tokens/icon-component").IconComponent | ||
| actionLabel | string | Accessible label for the trailing action button. |
MobileNavigationRoot
| Prop | Type | Default | Description |
|---|---|---|---|
| onClose | () => void |
MobileNavigationSeparator
| Prop | Type | Default | Description |
|---|---|---|---|
| variant | "strong" | "default" | "muted" | "accent" | "default" | Visual weight of the separator line. |
Also exports
- const
mobileNavigationAnatomy - component
MobileNavigationAppHeader - component
MobileNavigationContent - interface
MobileNavigationDrawerProfileProps - component
MobileNavigationHeaderSearchSlot - interface
MobileNavigationItemProps - interface
MobileNavigationProfileActionProps - interface
MobileNavigationProjectItemProps - component
MobileNavigationSlottedText
Anatomy
MobileNavigationRoot
mobile-navigation-rootRoot controlling open state for the mobile drawer
MobileNavigationFrame
mobile-navigation-frameFull-height frame that stacks header and content
MobileNavigationHeader
mobile-navigation-headerBranded top bar with a close action
MobileNavigationContent
mobile-navigation-contentScrollable region holding the navigation list
MobileNavigationItem
mobile-navigation-itemSingle navigation entry with icon and active state