// preview in
saved for every page

Sidebar

The app's main navigation, down the left edge. Named groups of links, the current page marked, counts for what is waiting, and a rail of icons when space is short.

Pattern WAI-ARIA Landmarks (navigation)Client componentSource ↗
minimal · light · #3fa34d
collapsed

Installation

Set up Camaleo once (Installation), then import what you need. It renders on the client.

import { Sidebar, SidebarHeader, SidebarNav, SidebarGroup, SidebarItem, SidebarFooter, SidebarToggle } from "@camaleo/react";

Anatomy

An <aside> with three rows. Only the nav scrolls, so the brand and the footer stay in view. SidebarBrand and SidebarContent are other names for SidebarHeader and SidebarNav.

Examples

Every example is a real file you can copy. They all wear the skin, mode and brand from the bar above. Press Tab to walk through the links.

minimal · light · #3fa34d

Collapse to a rail

Press the button at the bottom. Labels hide but still name each link for screen readers, and a tooltip shows them on hover and focus.

Current page

Click a link. current adds aria-current="page", and the bar beside it shows the page without relying on color.

With your router

Pass render={<NextLink href="…" />}. The router handles the click without reloading the page, and the item keeps its style. Here current comes from the path, so the link to this page is marked.

Counts that make sense when heard

The count is read as part of the link's name, so add the unit in VisuallyHidden: "Inbox 12 unread", not "Inbox 12".

Nested sections

A project with its own pages opens in place with a Collapsible. Its header is a button, because it only shows links and goes nowhere.

Account menu in the footer

The person and their settings sit at the bottom, out of the way of the pages. The menu opens upward when there is no room below.

Tasks
Today's tasks
  • Send the Q3 report to Marina
  • Review the new home page
  • Book the team offsite

On phones, in a drawer

The Sidebar has no phone mode of its own. Below a breakpoint, hide it and put the same links in a left Drawer, which traps focus and returns it to the menu button.

In context

These are whole pieces of UI you can copy, in the skin you picked.

Documentation siteSidebar · Collapsible · Badge
Store adminSidebar · Meter · Button
Team workspaceSidebar · IconButton · Avatar

Guidelines

DoA few named groups.

Two or three headings let people skip to the part of the app they need.

Don’tTen links in one list.

Without groups, people read every link to find one, and related pages end up far apart.

DoOne or two words per link.

Short names fit the column and are quick to scan. The page itself can have a longer title.

Don’tSentences as labels.

Long labels get cut off, and the words that tell them apart are the ones that disappear.

Props

PropTypeDefaultDescription
collapsedboolean—Whether it shows as a rail of icons. Set it to control the sidebar from code, with onCollapseChange.
defaultCollapsedbooleanfalseWhether it starts as a rail, when you don't control it.
onCollapseChange(collapsed: boolean) => void—Called with the new state when SidebarToggle (or useSidebar().setCollapsed) changes it.

SidebarItem takes href, icon, count and current, plus render to use your router's link instead of the a. SidebarGroup takes label. SidebarToggle takes collapseLabel and expandLabel; pass them in the page's language (defaults "Collapse sidebar" and "Expand sidebar"). useSidebar() reads and sets the state from any part inside.

Styling hooks

Restyle it without forking: target the attributes, or set the tokens on a parent, a skin or the sidebar itself.

Attributes

data-collapsedon the sidebar, while it is a rail
data-current · aria-currentpage · on the link of the page shown

Tokens it reads

Color

--cml-border--cml-brand--cml-fg--cml-fg-secondary--cml-focus-ring--cml-surface--cml-surface-raised

Shape & size

--cml-border-width--cml-radius-control--cml-radius-pill

Type & motion

--cml-duration-fast--cml-font-body--cml-font-label

This component only

--cml-item-highlight--cml-sidebar-group-label-size--cml-sidebar-group-label-tracking--cml-sidebar-group-label-transform--cml-sidebar-indicator-bg--cml-sidebar-indicator-width--cml-sidebar-item-active-fg--cml-sidebar-item-fg--cml-sidebar-item-height--cml-sidebar-item-hover-bg--cml-sidebar-item-hover-fg--cml-sidebar-item-radius--cml-sidebar-rail-width--cml-sidebar-width
/* a wider sidebar and a slimmer rail */
.app [data-slot="sidebar"] {
  --cml-sidebar-width: 16rem;
  --cml-sidebar-rail-width: 3.25rem;
}

Accessibility

TabMoves to the next link, section header or button, top to bottom. In the rail too: the hidden labels don't take a stop.
Shift + TabMoves to the previous one.
EnterOn a link, follows it. On the toggle or a section header, collapses or expands it.
SpaceOn the toggle or a section header, collapses or expands it.
Was this page helpful? · Edit this page on GitHub