JGuang

SideNav

SideNav · Astryx

Preview
npm install @astryxdesign/core@0.7.1 @astryxdesign/theme-neutral@0.7.1 @stylexjs/stylex@0.19.0

SideNav

A sidebar navigation component for organizing application pages with sections, nested items, and icons. Use SideNav as the primary navigation when an app has 5 or more destinations or requires hierarchical grouping.

Installation

npm install @astryxdesign/core@0.7.1 @astryxdesign/theme-neutral@0.7.1 @stylexjs/stylex@0.19.0

Requires React 19+, base CSS and a Theme provider. See Setup.

Side Nav

A sidebar navigation component for organizing application pages with sections, nested items, and icons. Use SideNav as the primary navigation when an app has 5 or more destinations or requires hierarchical grouping.

PropTypeDefaultDescription
headerReactNodeHeader area (typically SideNavHeading). Sticky.
topContentReactNodeContent below the header, e.g., a create button.
childrenReactNodeNavigation sections and items. Scrollable.
footerReactNodeFooter area above the icon bar.
footerIconsReactNodeFooter icon bar. The row cascades a 'sm' size to the interactive children it contains, so its icons and the built-in collapse button come out one height; pass an explicit size on a child to opt out.
collapsibleboolean | { defaultIsCollapsed?: boolean; isCollapsed?: boolean; onCollapsedChange?: (isCollapsed: boolean) => void; hasButton?: boolean; buttonLabel?: string }falseEnables collapse behavior. true for uncontrolled with default toggle button, or an object for controlled mode and advanced config (defaultIsCollapsed, isCollapsed + onCollapsedChange, hasButton, buttonLabel). A controlled config can also be passed to a SideNavCollapseButton rendered outside this SideNav, so both share one state.
resizableboolean | { defaultWidth?: number; minWidth?: number; maxWidth?: number; autoSaveId?: string; onWidthChange?: (width: number) => void; defaultIsCollapsed?: boolean; isCollapsed?: boolean; onCollapseChange?: (isCollapsed: boolean) => void }falseEnables a resize handle at the inline-end edge. true for defaults (260px initial, 180-480px range), or a ResizableConfig object (defaultWidth, minWidth, maxWidth, autoSaveId for localStorage persistence of width and collapse state, onWidthChange). It can also own collapse state (defaultIsCollapsed, isCollapsed + onCollapseChange); when both props carry collapse state, resizable wins and a dev warning names the conflicting keys. The handle is hidden while collapsed.
handleRefRef<SideNavImperativeCollapseHandle>Deprecated. Imperative collapse handle for SideNavCollapseButton instances rendered outside this SideNav; hand both the same controlled collapsible config instead. Separate from ref, which continues to expose the root HTMLElement.
xstyleStyleXStylesStyleX styles for layout customization (margins, positioning, sizing). Must be a stylex.create() value: not an inline style object like style={{}}.

Usage guidance

  • Use sections to group related navigation items and help users scan for their destination.
  • Pair outline and filled icon variants so the selected state is visually distinct.
  • Mark the current page with isSelected: it sets aria-current="page", so the current destination is announced rather than carried by color alone.
  • SideNav renders a navigation landmark, and a collapsible item follows the WAI-ARIA APG Disclosure pattern (https://www.w3.org/WAI/ARIA/apg/patterns/disclosure/): the toggle carries aria-expanded and aria-controls, and the group it owns is inert while collapsed. Keep item labels short; they name icon-only items unless a meaningful aria-label supplies more context.
  • While the nav is collapsed, an item with children shows them in a submenu flyout. On a device that can hover, pointing at the item opens it after a short delay and moving away closes it; a flyout opened by clicking stays open until it is dismissed. On touch, it opens on tap. Do not put an action in there that has no other route to it.
  • Avoid: Include a SideNavHeading when a TopNav is already providing app identity; this duplicates branding.
  • Avoid: Use for filtering content; use tabs or filter buttons instead.

Theming API

{
  "targets": [
    {
      "className": "astryx-side-nav",
      "visualProps": [
        "mode"
      ]
    },
    {
      "className": "astryx-side-nav-heading"
    },
    {
      "className": "astryx-side-nav-item",
      "visualProps": [
        "size"
      ],
      "states": [
        "selected",
        "disabled"
      ]
    },
    {
      "className": "astryx-side-nav-section"
    }
  ]
}

SideNavHeading

SideNavItem

SideNavSection

SideNavCollapseButton

Anatomy

  • Product icon and name: Branding area at the top of the nav.
  • Navigation items: Sections and groups of navigable links.
  • Collapse/expand toggle: Toggle to collapse or expand the side nav.

Side Nav Collapse Button

Toggle button for sidenav collapse. Place inside SideNav (reads context automatically) or outside it (hand the same controlled collapsible config to both). Renders as an icon-only ghost button by default.

PropTypeDefaultDescription
collapsible{isCollapsed: boolean, onCollapsedChange: (isCollapsed: boolean) => void}The same controlled collapsible config passed to SideNav. Only needed when the button is rendered outside the sidenav, where collapse context cannot reach it.
handleRefRefObject<SideNavImperativeCollapseHandle | null>Deprecated. Imperative collapse handle from SideNav; pass collapsible instead.
labelstringCustom button label. When provided, renders as a text button with chevron. When omitted, renders icon-only.
size'sm' | 'md' | 'lg'Button size. Defaults to the size its container cascades ('sm' inside a SideNav footer) and to 'md' with no container. Set it when the button sits outside a sized container and has to match its neighbours.
childrenReactNodeCustom button content. Overrides the default chevron icon and label.

Side Nav Heading

Product/suite/account heading with smart interaction boundary logic for links and a menu popover.

PropTypeDefaultDescription
heading *stringProduct/app name.
iconReactNodeProduct/app icon.
headingHrefstringLink for the heading.
superheadingstringText above the heading.
superheadingHrefstringLink for the superheading.
subheadingstringText below the heading.
subheadingHrefstringLink for the subheading.
menuReactNodeMenu content rendered inside a popover.
headerEndContentReactNodeContent rendered at the trailing edge of the heading row, between text and chevron. Useful for badges, status indicators, or compact action buttons. Hidden when collapsed.

Side Nav Item

Navigation item with icon, selected state, optional end content, and nesting support via children.

PropTypeDefaultDescription
label *stringItem label.
asLinkComponentTypeCustom link component.
iconIconTypeIcon displayed in the outline (unselected) variant. See astryx docs icons for valid semantic names.
selectedIconIconTypeIcon displayed when the item is selected (filled variant). See astryx docs icons for valid semantic names.
isSelectedbooleanfalseMarks this item as the current page.
isDisabledbooleanfalseDisabled state.
hrefstringNavigation URL.
onClick(e: MouseEvent) => voidClick handler.
endContentReactNodePassive right-side content only (badges, counts). Interactive controls go in actions.
actionsReactNodeRow-level secondary controls (icon buttons, menus) rendered as siblings of the primary element at the trailing edge of the row: after the expand/collapse toggle, before any nested children in DOM and focus order. Each control owns its accessible name and behavior. Controls inherit the row control size through SizeContext, so an unsized icon button matches the built-in expand/collapse toggle; an explicit size still wins. Hidden while the SideNav rail is collapsed. Use endContent for passive content (badges, counts); use actions for anything interactive.
childrenReactNodeSub-items for nesting.
collapsibleboolean | { defaultIsCollapsed?: boolean, isCollapsed?: boolean, onCollapsedChange?: (isCollapsed: boolean) => void }falseEnables collapse behavior for items with children. Pass true for uncontrolled (starts expanded), or an object for controlled mode.
size'sm' | 'md' | 'lg''md'Size variant for the nav item row.

Side Nav Section

Section grouping with an optional title, subtitle, and end content.

PropTypeDefaultDescription
title *stringSection title.
subtitlestringSection subtitle.
childrenReactNodeSection items.
endContentReactNodeRight-side content in the section header.
isHeaderHiddenbooleanfalseVisually hides the section header while keeping it accessible to screen readers.
xstyleStyleXStylesStyleX styles for layout customization (margins, positioning, sizing). Must be a stylex.create() value: not an inline style object like style={{}}.

Examples

  • Side Nav Collapse Button: Demonstrates SideNavCollapseButton inside a collapsible SideNav.
  • Side Nav Heading: Demonstrates SideNavHeading with an app name, logo icon, superheading, and subheading.
  • Side Nav Item: Demonstrates SideNavItem with selected, icon, disabled, and nested states.
  • Side Nav Section: Demonstrates SideNavSection with titled groups of navigation items.
  • Side Nav:
  • SideNavCollapseButton — Basic: Place a collapse button in the SideNav footer to let users toggle the rail between expanded and collapsed states. Disable the built-in button via collapsible={{hasButton: false}} when positioning it yourself.
  • SideNav — End Content: Side navigation items with badges, counts, and context menus as trailing content.
  • SideNavHeading — Basic: A SideNav header with an app icon and a linked title. Pass it to the SideNav header prop to identify the product or workspace at the top of the navigation rail.
  • SideNavItem — Basic: Navigation links inside a SideNav, each with a label, an icon, and an href. Mark the item for the current page with isSelected.
  • SideNav — Nested Items: Side navigation with collapsible nested items for settings or hierarchical menus.
  • SideNavSection — Basic: Group related SideNavItems under titled sections. Use sections to organize longer navigation lists into scannable clusters like Overview and Account.
  • SideNav — Header with Menu: Side navigation with an account switcher dropdown in the header for multi-account apps.