On this page
Proposed CSC Standards · 0.1.0
Sidebars
Application navigation along the side of an internal tool.
Show the information architecture and the current section.
What this describes
When to use
- An internal app with several sections.
- The person needs to see where they are in the hierarchy.
When not to use
- A public marketing page with a few links. Use TopNav.
- A single-step form.
Allowed variants
Classic
Labeled links with icons.
- Hierarchy
- Full sidebar.
- Use in
- Internal apps.
- Restriction
- Keep the current item marked.
- Accessibility
- Links are keyboard reachable.
- Responsive
- Becomes a drawer under 760px.
Icon rail
More room for content.
- Hierarchy
- Narrow icons.
- Use in
- Familiar sections.
- Restriction
- Every icon needs a name.
- Accessibility
- Do not rely on the icon alone.
- Responsive
- Still collapses on a phone.
Grouped
Links under section labels.
- Hierarchy
- Groups with headings.
- Use in
- Many destinations.
- Restriction
- Group labels are text, not color bars.
- Accessibility
- Headings or text labels separate groups.
- Responsive
- Groups stack. They do not sit in horizontal scroll.
Floating
A sidebar inset from the page edge.
- Hierarchy
- Card-like navigation.
- Use in
- The floating dashboard shell.
- Restriction
- Keep contrast against the canvas.
- Accessibility
- Same link rules.
- Responsive
- The floating card becomes full width when the shell stacks.
Dual-level
Parent and child sections.
- Hierarchy
- Two columns.
- Use in
- A real second level.
- Restriction
- Do not use it for a flat list.
- Accessibility
- Both levels are labeled.
- Responsive
- Stack the levels under 760px.
Mandatory rules
Mark the current section
The active item is indicated by more than color. The component uses aria-current.
Implementation detail
WCAG 1.4.1 and the current-page convention both apply. Color alone is not enough.
Mark the current link with aria-current or text, not with color alone.
Check: The current link exposes aria-current or an equivalent text cue.
Keep every item keyboard reachable
Links in the sidebar are native anchors in tab order.
Implementation detail
A div menu item is not focusable.
Use anchors for each destination. Do not put the click handler on a div.
Check: Tab reaches each visible item and Enter activates it.
Name icon-rail items
The rail variant has no room for visible text, so each item still has an accessible name.
Implementation detail
An icon with no name is an unlabeled link.
Give every icon-only item an accessible name. Do not leave the icon as the only content.
Applies when: variant is rail.
Check: Each rail icon has an accessible name.
Collapse to a drawer on a narrow viewport
Under 760px the app sidebar is off-canvas and opens from the menu button.
Implementation detail
Proposed CSC Standard. A 254px sidebar cannot sit beside content at 320px.
Use the existing shell behavior for the design-system chrome. Inside a dashboard, stack the shell and let the sidebar use the full width.
Check: At 375px the sidebar does not force horizontal scroll. It opens and closes from a button with a name.
Do not mix two competing sidebars
Dual-level is the only variant that shows two columns, and only when the product has a real second level.
Implementation detail
Proposed CSC Standard. A second sidebar for decoration wastes the content width.
Use variant="dual" only for a parent section plus its children. Otherwise use classic, grouped, rail, or floating.
Check: A page shows one navigation landmark, or the dual variant’s two levels are labeled.
Restrictions
- SB-003 Name icon-rail items. variant is rail.
Accessibility
- Current page is not color-only.
- Icon rails have names.
- Keyboard order follows the visual order.
Responsive behavior
- At 375px the sidebar is off-canvas or stacked, not beside a squeezed content column.
- The open button is named Open navigation or an equivalent.
- Closing returns focus to that button.
Component states
Expanded
Labels are visible.
Collapsed
Pass collapsed="true" only when names remain for the rail.
Current
The active destination is marked beyond color.
Correct implementation
The current link uses aria-current and a soft blue wash, not color alone.
Imports: None. Dependencies: None. Rules: SB-001.
export function AppNav() {
return (
<nav aria-label="Sections" style={{ width: 260, background: '#fff', borderRadius: 12, padding: 12 }}>
<a href="/records" aria-current="page" style={{ color: '#2A338F', background: '#EEF0FA', borderRadius: 8, display: 'block', padding: 10 }}>Records</a>
</nav>
);
}Incorrect implementation
Div items are not links and have no current-page state.
Imports: None. Dependencies: None. Rules: SB-002.
export function FakeNav() {
return <div onClick={() => {}}>Records</div>;
}Common mistakes
- A permanent 254px sidebar at 320px.
- Icon rails without names.
- Active state shown only with CSC blue.
Testing checklist
Agent prompts for this component are in the AI Development Hub.