j3w1 / Sidebar navigationVue · HTML · React · Astro

J3W1 / DESIGN SYSTEM

Sidebar navigation

A vertical list of section links with optional nested groups; the current section carries a 2px inline-start indicator and bright text, and the rail collapses to icons.

stable · LIGHT DOM · 1.1.0

Light DOM retains static content, native semantics, label relationships and host composition without duplicating controls.

Live variants

default

Example destination: sn overview

Example destination: sn tokens

Example destination: sn actions

Example destination: sn forms

Example destination: sn ports

<j3w1-sidebar-nav id="example-sidebar-nav-default"><nav class="sidebar-nav" aria-label="Sections">
  <ul class="sidebar-nav-list">
    <li class="sidebar-nav-item"><a class="sidebar-nav-link sidebar-nav-current" href="#example-sidebar-nav-default-sn-overview" aria-current="page"><span class="sidebar-nav-icon" aria-hidden="true"><svg viewBox="0 0 16 16" width="16" height="16" focusable="false"><rect x="2.5" y="2.5" width="11" height="11"></rect></svg></span><span class="sidebar-nav-label">Overview</span></a></li>
    <li class="sidebar-nav-item"><a class="sidebar-nav-link sidebar-nav-link-demo-target" href="#example-sidebar-nav-default-sn-tokens"><span class="sidebar-nav-icon" aria-hidden="true"><svg viewBox="0 0 16 16" width="16" height="16" focusable="false"><circle cx="8" cy="8" r="5.5"></circle></svg></span><span class="sidebar-nav-label">Tokens</span></a></li>
    <li class="sidebar-nav-item">
      <button class="sidebar-nav-link sidebar-nav-group" type="button" aria-expanded="false" aria-controls="example-sidebar-nav-default-sn-components"><span class="sidebar-nav-icon" aria-hidden="true"><svg viewBox="0 0 16 16" width="16" height="16" focusable="false"><path d="M2.5 4h11M2.5 8h11M2.5 12h11"></path></svg></span><span class="sidebar-nav-label">Components</span><span class="sidebar-nav-chevron" aria-hidden="true"><svg viewBox="0 0 16 16" width="16" height="16" focusable="false"><path d="M6 4l4 4-4 4"></path></svg></span></button>
      <ul class="sidebar-nav-list sidebar-nav-sublist" id="example-sidebar-nav-default-sn-components" hidden="">
        <li class="sidebar-nav-item"><a class="sidebar-nav-link" href="#example-sidebar-nav-default-sn-actions"><span class="sidebar-nav-label">Actions</span></a></li>
        <li class="sidebar-nav-item"><a class="sidebar-nav-link" href="#example-sidebar-nav-default-sn-forms"><span class="sidebar-nav-label">Forms</span></a></li>
      </ul>
    </li>
    <li class="sidebar-nav-item"><a class="sidebar-nav-link" href="#example-sidebar-nav-default-sn-ports"><span class="sidebar-nav-icon" aria-hidden="true"><svg viewBox="0 0 16 16" width="16" height="16" focusable="false"><path d="M3 8h10M9 4l4 4-4 4"></path></svg></span><span class="sidebar-nav-label">Ports</span></a></li>
  </ul>
</nav><p id="example-sidebar-nav-default-sn-overview" tabindex="-1" class="j3w1-example-target">Example destination: sn overview</p><p id="example-sidebar-nav-default-sn-tokens" tabindex="-1" class="j3w1-example-target">Example destination: sn tokens</p><p id="example-sidebar-nav-default-sn-actions" tabindex="-1" class="j3w1-example-target">Example destination: sn actions</p><p id="example-sidebar-nav-default-sn-forms" tabindex="-1" class="j3w1-example-target">Example destination: sn forms</p><p id="example-sidebar-nav-default-sn-ports" tabindex="-1" class="j3w1-example-target">Example destination: sn ports</p></j3w1-sidebar-nav>

collapsed

Example destination: sn overview

Example destination: sn tokens

Example destination: sn actions

Example destination: sn forms

Example destination: sn ports

<j3w1-sidebar-nav id="example-sidebar-nav-collapsed"><nav class="sidebar-nav sidebar-nav-collapsed" aria-label="Sections">
  <ul class="sidebar-nav-list">
    <li class="sidebar-nav-item"><a class="sidebar-nav-link sidebar-nav-current" href="#example-sidebar-nav-collapsed-sn-overview" aria-current="page" aria-label="Overview" title="Overview"><span class="sidebar-nav-icon" aria-hidden="true"><svg viewBox="0 0 16 16" width="16" height="16" focusable="false"><rect x="2.5" y="2.5" width="11" height="11"></rect></svg></span><span class="sidebar-nav-label">Overview</span></a></li>
    <li class="sidebar-nav-item"><a class="sidebar-nav-link sidebar-nav-link-demo-target" href="#example-sidebar-nav-collapsed-sn-tokens" aria-label="Tokens" title="Tokens"><span class="sidebar-nav-icon" aria-hidden="true"><svg viewBox="0 0 16 16" width="16" height="16" focusable="false"><circle cx="8" cy="8" r="5.5"></circle></svg></span><span class="sidebar-nav-label">Tokens</span></a></li>
    <li class="sidebar-nav-item">
      <button class="sidebar-nav-link sidebar-nav-group" type="button" aria-expanded="false" aria-controls="example-sidebar-nav-collapsed-sn-components" aria-label="Components" title="Components"><span class="sidebar-nav-icon" aria-hidden="true"><svg viewBox="0 0 16 16" width="16" height="16" focusable="false"><path d="M2.5 4h11M2.5 8h11M2.5 12h11"></path></svg></span><span class="sidebar-nav-label">Components</span><span class="sidebar-nav-chevron" aria-hidden="true"><svg viewBox="0 0 16 16" width="16" height="16" focusable="false"><path d="M6 4l4 4-4 4"></path></svg></span></button>
      <ul class="sidebar-nav-list sidebar-nav-sublist" id="example-sidebar-nav-collapsed-sn-components" hidden="">
        <li class="sidebar-nav-item"><a class="sidebar-nav-link" href="#example-sidebar-nav-collapsed-sn-actions" aria-label="Actions" title="Actions"><span class="sidebar-nav-icon" aria-hidden="true"><svg viewBox="0 0 16 16" width="16" height="16" focusable="false"><rect x="3" y="5" width="10" height="6"></rect></svg></span><span class="sidebar-nav-label">Actions</span></a></li>
        <li class="sidebar-nav-item"><a class="sidebar-nav-link" href="#example-sidebar-nav-collapsed-sn-forms" aria-label="Forms" title="Forms"><span class="sidebar-nav-icon" aria-hidden="true"><svg viewBox="0 0 16 16" width="16" height="16" focusable="false"><path d="M3 5h10M3 8h6M3 11h8"></path></svg></span><span class="sidebar-nav-label">Forms</span></a></li>
      </ul>
    </li>
    <li class="sidebar-nav-item"><a class="sidebar-nav-link" href="#example-sidebar-nav-collapsed-sn-ports" aria-label="Ports" title="Ports"><span class="sidebar-nav-icon" aria-hidden="true"><svg viewBox="0 0 16 16" width="16" height="16" focusable="false"><path d="M3 8h10M9 4l4 4-4 4"></path></svg></span><span class="sidebar-nav-label">Ports</span></a></li>
  </ul>
</nav><p id="example-sidebar-nav-collapsed-sn-overview" tabindex="-1" class="j3w1-example-target">Example destination: sn overview</p><p id="example-sidebar-nav-collapsed-sn-tokens" tabindex="-1" class="j3w1-example-target">Example destination: sn tokens</p><p id="example-sidebar-nav-collapsed-sn-actions" tabindex="-1" class="j3w1-example-target">Example destination: sn actions</p><p id="example-sidebar-nav-collapsed-sn-forms" tabindex="-1" class="j3w1-example-target">Example destination: sn forms</p><p id="example-sidebar-nav-collapsed-sn-ports" tabindex="-1" class="j3w1-example-target">Example destination: sn ports</p></j3w1-sidebar-nav>

nested

Example destination: sn overview

Example destination: sn actions

Example destination: sn navigation

Example destination: sn display

Example destination: sn ports

<j3w1-sidebar-nav id="example-sidebar-nav-nested"><nav class="sidebar-nav" aria-label="Sections">
  <ul class="sidebar-nav-list">
    <li class="sidebar-nav-item"><a class="sidebar-nav-link" href="#example-sidebar-nav-nested-sn-overview"><span class="sidebar-nav-icon" aria-hidden="true"><svg viewBox="0 0 16 16" width="16" height="16" focusable="false"><rect x="2.5" y="2.5" width="11" height="11"></rect></svg></span><span class="sidebar-nav-label">Overview</span></a></li>
    <li class="sidebar-nav-item">
      <button class="sidebar-nav-link sidebar-nav-group" type="button" aria-expanded="true" aria-controls="example-sidebar-nav-nested-sn-components"><span class="sidebar-nav-icon" aria-hidden="true"><svg viewBox="0 0 16 16" width="16" height="16" focusable="false"><path d="M2.5 4h11M2.5 8h11M2.5 12h11"></path></svg></span><span class="sidebar-nav-label">Components</span><span class="sidebar-nav-chevron" aria-hidden="true"><svg viewBox="0 0 16 16" width="16" height="16" focusable="false"><path d="M6 4l4 4-4 4"></path></svg></span></button>
      <ul class="sidebar-nav-list sidebar-nav-sublist" id="example-sidebar-nav-nested-sn-components">
        <li class="sidebar-nav-item"><a class="sidebar-nav-link" href="#example-sidebar-nav-nested-sn-actions"><span class="sidebar-nav-label">Actions</span></a></li>
        <li class="sidebar-nav-item"><a class="sidebar-nav-link sidebar-nav-current" href="#example-sidebar-nav-nested-sn-navigation" aria-current="page"><span class="sidebar-nav-label">Navigation</span></a></li>
        <li class="sidebar-nav-item"><a class="sidebar-nav-link sidebar-nav-link-demo-target" href="#example-sidebar-nav-nested-sn-display"><span class="sidebar-nav-label">Display</span></a></li>
      </ul>
    </li>
    <li class="sidebar-nav-item"><a class="sidebar-nav-link" href="#example-sidebar-nav-nested-sn-ports"><span class="sidebar-nav-icon" aria-hidden="true"><svg viewBox="0 0 16 16" width="16" height="16" focusable="false"><path d="M3 8h10M9 4l4 4-4 4"></path></svg></span><span class="sidebar-nav-label">Ports</span></a></li>
  </ul>
</nav><p id="example-sidebar-nav-nested-sn-overview" tabindex="-1" class="j3w1-example-target">Example destination: sn overview</p><p id="example-sidebar-nav-nested-sn-actions" tabindex="-1" class="j3w1-example-target">Example destination: sn actions</p><p id="example-sidebar-nav-nested-sn-navigation" tabindex="-1" class="j3w1-example-target">Example destination: sn navigation</p><p id="example-sidebar-nav-nested-sn-display" tabindex="-1" class="j3w1-example-target">Example destination: sn display</p><p id="example-sidebar-nav-nested-sn-ports" tabindex="-1" class="j3w1-example-target">Example destination: sn ports</p></j3w1-sidebar-nav>

Install and register

Use the exact version. If npm publication is pending, install the release tarball from the installation guide.

npm install --save-exact @j3w1/ui@1.1.0
import '@j3w1/ui/tokens.css';
import '@j3w1/ui/styles/sidebar-nav.css';
import '@j3w1/ui/register/sidebar-nav';

Insert the maintained markup above after loading these imports. Its native children provide accessible names and form behavior; the empty custom tag alone does not create a control.

Vue SFC, React, Astro and plain HTML integration →

Copy the complete implementation

npx --package=@j3w1/ui@1.1.0 j3w1-ui copy sidebar-nav --out ./vendor/j3w1/sidebar-nav

The CLI verifies every file before writing and refuses overwrites. Serve the output over HTTP and open index.html. Keep its modules, CSS, tokens and licence notices together.

Public API

attributes

NameType / signatureMeaning
disabledCustomEventDisable the native controls owned by this instance.
loadingCustomEventMark the primary control busy and prevent duplicate activation.

properties

NameType / signatureMeaning
disabledbooleanDelegates disabled state to native children.
namestringNative control name; application form keys remain explicit.
openbooleanNative details expansion when this component contains details.

methods

NameType / signatureMeaning
refresh(): voidReconnect behavior after replacing native child structure.
focus(options?: FocusOptions): voidFocus the first usable native control.

events

NameType / signatureMeaning
j3w1-toggleCustomEventA native disclosure or navigation group changed.

Dependencies and verification

Registered components: none. Style dependencies: none.

Package presence establishes an available implementation. Actual passes depend on the tested artifact and environment. Read specification execution evidence; read packed-consumer evidence; inspect the complete state matrix.

Full implementation manifest, API and token dependency closure

Canonical specification

Purpose

Moves between the sections of an application. The sidebar is the primary navigation of a settings panel, an admin area or a documentation site; tabs switch views inside one section, and a tree browses data rather than sections.

Anatomy

A nav on color.surface.default with a 1px color.border.divider inline-end edge. Each link is one row: an icon slot, a label in color.text.default, and a transparent 2px inline-start edge. The current link colours that edge with color.border.selected-indicator and its text with color.text.bright. Groups are buttons with a chevron in color.icon.decorative; their children sit in a sublist indented by one icon width. Collapsed, the rail keeps the icons and hides the labels visually.

States

StateVisualNon-colour channel
defaulttext color.text.default; no fill; transparent inline-start edge
hoverbackground → color.interaction.hover.bgcursor: pointer
focus-visiblering 1px dashed color.interaction.focus.ring at −2pxthe ring
current2px color.border.selected-indicator inline-start bar; text color.text.brightaria-current="page"; the bar
selectedfill color.interaction.selection.bg with color.interaction.selection.text; the ring in color.interaction.focus.ring-container when focusedaria-selected on a listbox-style rail; the fill’s on-fill text
selected+container-inactivefill color.interaction.selection.inactive-bg with color.interaction.selection.inactive-text; no ringlightness drop between the two fills
expandedthe group’s chevron rotated 90°; its sublist shownaria-expanded="true"; the children are present
collapsedlabels visually hidden; icons centred; the current bar and fills unchangedthe labels remain for assistive technology and as tooltips

current is where the user is; selected is what the user chose in a rail that drives a detail pane. A rail is one or the other, never both at once.

Keyboard

Every link and every group button is a tab stop in document order; children of a closed group are hidden and skipped. Enter follows a link; Enter or Space toggles a group and leaves focus on the button. There is no arrow-key model: the rail is a list of links, not a tree, so the native tab order is the whole contract.

Accessibility

aria-label on the nav distinguishes it from other landmarks. The current link carries aria-current="page"; a rail that drives a detail pane uses a listbox with aria-selected instead of links. Group buttons carry aria-expanded and aria-controls; the sublist is hidden until expanded so its links leave the tab order. Collapsed labels use a clip-rect hiding, not display: none, so names survive; icon-only links also get a title. Contrast: text 8.43:1, current text 10.10:1, indicator 4.57:1, selection text 12.47:1 on the fill, inactive selection 7.02:1. Rows are at least 24 CSS pixels tall in compact density.

Portability

A border-inline-start, a background and an outline; the chevron is an SVG. Toolkits without logical borders draw the bar on the left in LTR and on the right in RTL explicitly. The collapsed rail is a width change and a hidden label; hosts that cannot hide labels while keeping their names show the full rail.

Non-examples

A filled or rounded current item. The indicator on the inline-end edge. A current item marked by bold text alone. Labels removed from the DOM when collapsed. A group whose children stay in the tab order while hidden. A rail that scrolls horizontally. Icon-only links with no accessible name. Hover that changes the text colour.

j3w1 / command

  • SPEC Overview
  • SPEC Foundations
  • SPEC Components
  • SPEC Patterns
  • SPEC Tokens
  • SPEC Tools
  • SPEC Implement
  • SPEC For agents
  • SPEC Ports
  • SPEC Releases
  • DEMO Vue application demo
  • SPEC Complete UI theme specification