Skip to main content

Overview

Side Nav is a full-featured sidebar component that supports icons, collapsible groups, section labels, and responsive mobile navigation. It collapses to icon-only mode and shows a bottom tab bar on mobile devices.

Usage

import { AxSideNav } from "axmed-design-system"
import { AxBrand } from "axmed-design-system"
import { DashboardOutlined, ShoppingCartOutlined } from "@ant-design/icons"
import { useState } from "react"

function AppLayout() {
  const [collapsed, setCollapsed] = useState(false)
  const [selected, setSelected] = useState("dashboard")

  const items = [
    {
      key: "dashboard",
      label: "Dashboard",
      icon: <DashboardOutlined />,
      onClick: () => setSelected("dashboard"),
    },
    {
      type: "group",
      key: "orders",
      label: "Orders",
      icon: <ShoppingCartOutlined />,
      children: [
        { key: "orders-all", label: "All Orders", onClick: () => setSelected("orders-all") },
        { key: "orders-pending", label: "Pending", onClick: () => setSelected("orders-pending") },
      ],
    },
  ]

  return (
    <AxSideNav
      items={items}
      selectedKey={selected}
      collapsed={collapsed}
      onCollapse={setCollapsed}
      logo={<AxBrand variant="wordmark" size="md" />}
    />
  )
}

Basic Item

{
  key: "dashboard",
  label: "Dashboard",
  icon: <DashboardOutlined />,
  onClick: () => navigate("/dashboard"),
}

Collapsible Group

{
  type: "group",
  key: "orders",
  label: "Orders",
  icon: <ShoppingCartOutlined />,
  defaultOpen: true,  // Start expanded
  children: [
    { key: "orders-all", label: "All Orders", onClick: () => {} },
    { key: "orders-pending", label: "Pending", onClick: () => {} },
  ],
}
When collapsed, clicking a group icon shows a popover flyout with the children.

Section Label

{
  type: "section",
  key: "sec-platform",
  label: "Platform",
}
Section labels are hidden when the sidebar is collapsed.

Divider

{
  type: "divider",
  key: "div-1",
}

User Profile Area

const UserProfile = () => (
  <Flex align="center" gap={10}>
    <Avatar size={32} icon={<UserOutlined />} />
    <Flex vertical>
      <AxText variant="body-sm" weight="medium">Ahmed Al-Rashid</AxText>
      <AxText variant="body-xs" color="secondary">[email protected]</AxText>
    </Flex>
  </Flex>
)

const userActions = [
  { key: "account", label: "My Account", icon: <UserOutlined /> },
  { key: "settings", label: "Settings", icon: <SettingOutlined /> },
  { type: "divider" },
  { key: "logout", label: "Log Out", icon: <LogoutOutlined />, danger: true },
]

<AxSideNav
  user={<UserProfile />}
  userActions={userActions}
  // ... other props
/>

Collapsible State

const [collapsed, setCollapsed] = useState(false)

<AxSideNav
  collapsed={collapsed}
  onCollapse={setCollapsed}
  logo={<AxBrand variant={collapsed ? "icon" : "wordmark"} size="md" />}
  // ... items
/>
  • Expanded: Shows full labels, group children inline
  • Collapsed: Icon-only mode, groups open in popover flyouts

Mobile Bottom Nav

On screens < 768px, Side Nav automatically shows a fixed bottom tab bar with the first 4 top-level items. Overflow items go into a “More” menu.
// Shows bottom nav on mobile by default
<AxSideNav
  showMobileNav={true}  // default
  items={items}
/>

// Or disable if you have a custom mobile solution
<AxSideNav
  showMobileNav={false}
  items={items}
/>

With Header

Combine with AxHeader for a complete app shell:
const [collapsed, setCollapsed] = useState(false)
const [selected, setSelected] = useState("dashboard")

return (
  <div style={{ display: "flex", height: "100vh" }}>
    <AxSideNav
      items={items}
      selectedKey={selected}
      collapsed={collapsed}
      onCollapse={setCollapsed}
      hideCollapseButton  // Header provides the toggle
      logo={<AxBrand variant={collapsed ? "icon" : "wordmark"} />}
      user={<UserProfile />}
      userActions={userActions}
    />
    
    <div style={{ flex: 1, display: "flex", flexDirection: "column" }}>
      <AxHeader
        onSidebarToggle={() => setCollapsed(!collapsed)}
        sidebarCollapsed={collapsed}
        mobileLogo={<AxBrand variant="wordmark" />}
        right={<ActionButtons />}
      />
      <main style={{ flex: 1, overflow: "auto", padding: 24 }}>
        {/* Page content */}
      </main>
    </div>
  </div>
)

Props

items
NavItem[]
required
Array of navigation items. Each item can be:
  • NavItem: { key, label, icon, onClick?, disabled? }
  • NavGroup: { type: "group", key, label, icon, children: NavItem[], defaultOpen? }
  • NavSection: { type: "section", key, label }
  • NavDivider: { type: "divider", key }
selectedKey
string
Key of the currently active item
collapsed
boolean
default:"false"
Whether the sidebar is collapsed to icon-only mode
onCollapse
(collapsed: boolean) => void
Called when the user toggles collapse
Logo/brand slot rendered at the top
user
ReactNode
User profile slot pinned to the bottom
userActions
ActionItem[]
Profile action menu items shown when clicking the user area (e.g. My Account, Settings, Log Out)
width
number
default:"240"
Width when expanded (px)
collapsedWidth
number
default:"64"
Width when collapsed (px)
hideCollapseButton
boolean
default:"false"
Hide the built-in collapse toggle button. Use when AxHeader provides the toggle instead.
showMobileNav
boolean
default:"true"
Show a fixed bottom tab bar on mobile (< 768px) instead of the sidebar
className
string
Additional class name
style
CSSProperties
Inline styles

Best Practices

Use icons for all top-level items to support collapsed mode
Group related pages under a NavGroup (e.g., “Orders” → “All”, “Pending”, “Completed”)
Sync selectedKey with your router to highlight the active page
Use section labels to organize long nav lists
Don’t nest groups more than one level deep — keep the hierarchy flat
Avoid more than 10 top-level items — consider splitting into multiple sections

Accessibility

  • Uses semantic <nav> element with aria-label="Main navigation"
  • Items use role="list" and role="listitem"
  • Active items marked with aria-current="page"
  • Collapsed items have aria-label for screen readers
  • Groups use aria-expanded to indicate open/closed state

API Reference

See the Side Nav API for the complete TypeScript interface.
  • Header — Pair with Side Nav for full app layout
  • Brand — Use in the logo slot
  • Action Menu — Powers the user profile dropdown

Build docs developers (and LLMs) love