Components / Layout & Navigation / Sidebar

Sidebar stable

The app sidebar as a part: sections, collapsible groups, badges, an icon rail variant, and the user at the foot.

Preview

Overview

The sidebar is the part; this column is just the room it stands in. Try the Projects group — it folds. The current page carries the vermillion core on its icon, and the user sits at the foot, out of the way until needed.

<div style="display:flex;border:1px solid var(--k-line);border-radius:14px;overflow:hidden;max-width:620px;background:var(--k-bg)">
  <nav class="k-side" data-side aria-label="Sidebar preview">
    <div class="k-side-brand"><span class="k-side-mark"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="square" stroke-linejoin="bevel" aria-hidden="true"><path d="M12 3.5 2.5 8.5 12 13.5l9.5-5L12 3.5Z"/><path d="m2.5 12.8 9.5 5 9.5-5"/></svg></span>Northwind</div>
    <div class="k-side-sec">MAIN</div>
    <div class="k-side-nav">
      <a class="k-side-item on" href="#"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="square" stroke-linejoin="bevel" aria-hidden="true"><path d="m3 11 9-8 9 8"/><path d="M5 9.5V20a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V9.5"/></svg><span class="k-side-t">Overview</span></a>
      <div class="k-side-group open">
        <button class="k-side-item" type="button" data-side-toggle aria-expanded="true"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="square" stroke-linejoin="bevel" aria-hidden="true"><path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V7Z"/></svg><span class="k-side-t">Projects</span><svg class="k-side-chev" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="square" stroke-linejoin="bevel" aria-hidden="true"><path d="m6 9 6 6 6-6"/></svg></button>
        <div class="k-side-sub">
          <a class="k-side-item" href="#"><span class="k-side-t">Website rebuild</span></a>
          <a class="k-side-item" href="#"><span class="k-side-t">Mobile app</span></a>
          <a class="k-side-item" href="#"><span class="k-side-t">Brand refresh</span></a>
        </div>
      </div>
      <a class="k-side-item" href="#"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="square" stroke-linejoin="bevel" aria-hidden="true"><rect x="3.5" y="5" width="17" height="16" rx="2"/><path d="M3.5 10h17M8 3v4M16 3v4"/></svg><span class="k-side-t">Calendar</span><span class="k-side-badge">3</span></a>
      <a class="k-side-item" href="#"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="square" stroke-linejoin="bevel" aria-hidden="true"><path d="M6 20v-6M12 20V4M18 20v-9"/><path d="M3.5 20.5h17"/></svg><span class="k-side-t">Reports</span></a>
    </div>
    <div class="k-side-sec">MANAGE</div>
    <div class="k-side-nav">
      <a class="k-side-item" href="#"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="square" stroke-linejoin="bevel" aria-hidden="true"><circle cx="9" cy="8.5" r="3.4"/><path d="M2.8 20c.7-3.4 3.2-5.2 6.2-5.2s5.5 1.8 6.2 5.2"/><path d="M16 5.4a3.4 3.4 0 0 1 0 6.4M18.5 15.4c1.5.8 2.5 2.4 2.9 4.6"/></svg><span class="k-side-t">Team</span></a>
      <a class="k-side-item" href="#"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="square" stroke-linejoin="bevel" aria-hidden="true"><path d="M3 6h10M17 6h4M3 12h4M11 12h10M3 18h12M19 18h2"/><circle cx="15" cy="6" r="2"/><circle cx="9" cy="12" r="2"/><circle cx="17" cy="18" r="2"/></svg><span class="k-side-t">Settings</span></a>
    </div>
    <div class="k-side-user"><span class="k-side-ava">AR</span><span class="k-side-umeta"><span class="k-side-uname">Aoki Ren</span><br><span class="k-side-urole">Workspace admin</span></span></div>
  </nav>
  <div style="flex:1;padding:20px;min-width:0">
    <p style="font-size:15px;font-weight:600">Overview</p>
    <p style="font-size:13px;color:var(--k-ink-2);line-height:1.8;margin-top:6px">The sidebar is the part; this column is just the room it stands in. Try the Projects group — it folds. The current page carries the vermillion core on its icon, and the user sits at the foot, out of the way until needed.</p>
  </div>
</div>
/* KATA Sidebar — the app sidebar as a part: sections, collapsible groups,
   an icon rail, and the user at the foot. The current page carries the
   vermillion core on its icon, like the app shell and the templates. */
.k-side{width:230px;flex:none;display:flex;flex-direction:column;background:var(--k-bg);border-right:1px solid var(--k-line);padding:14px 10px;font-family:var(--k-font);color:var(--k-ink);text-align:left}
.k-side-brand{display:flex;align-items:center;gap:9px;padding:2px 8px 12px;font-size:14px;font-weight:600}
.k-side-mark{width:24px;height:24px;border-radius:7px;background:var(--k-ink);color:var(--k-on-color);display:flex;align-items:center;justify-content:center;flex:none}
.k-side-sec{font-size:10.5px;letter-spacing:.09em;font-weight:600;color:var(--k-ink-3);margin:14px 8px 5px}
.k-side-nav{display:grid;gap:2px}
.k-side-item{display:flex;align-items:center;gap:9px;padding:8px 10px;border-radius:8px;font-size:13.5px;color:var(--k-ink-2);text-decoration:none;cursor:pointer;background:none;border:0;width:100%;text-align:left;font-family:inherit}
.k-side-item:hover{background:var(--k-bg-soft);color:var(--k-ink)}
.k-side-item.on{background:var(--k-bg-soft);color:var(--k-ink);font-weight:550}
.k-side-item.on svg{color:var(--k-core)}
.k-side-item svg{flex:none}
.k-side-badge{margin-left:auto;font-size:11px;font-weight:600;background:var(--k-bg-soft);border:1px solid var(--k-line);color:var(--k-ink-2);border-radius:99px;padding:1px 7px}
.k-side-item.on .k-side-badge{background:var(--k-bg)}
.k-side-chev{margin-left:auto;transition:transform .18s}
.k-side-group.open .k-side-chev{transform:rotate(180deg)}
.k-side-sub{display:none;gap:2px;margin:2px 0 2px 25px}
.k-side-group.open .k-side-sub{display:grid}
.k-side-sub .k-side-item{font-size:13px;padding:6px 10px}
.k-side-user{margin-top:auto;display:flex;align-items:center;gap:9px;padding:12px 8px 2px;border-top:1px solid var(--k-line)}
.k-side-ava{width:30px;height:30px;border-radius:50%;background:var(--k-ink);color:var(--k-on-color);display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:600;flex:none}
.k-side-uname{font-size:13px;font-weight:550;line-height:1.3}
.k-side-urole{font-size:11.5px;color:var(--k-ink-3)}
.k-side.rail{width:60px;padding:14px 8px;align-items:center}
.k-side.rail .k-side-brand{padding:2px 0 12px}
.k-side.rail .k-side-nav{justify-items:center}
.k-side.rail .k-side-item{justify-content:center;padding:9px 0;width:40px}
.k-side.rail .k-side-t,.k-side.rail .k-side-sec,.k-side.rail .k-side-badge,.k-side.rail .k-side-chev,.k-side.rail .k-side-umeta{display:none}
.k-side.rail .k-side-user{justify-content:center;padding:12px 0 2px}
@media (prefers-reduced-motion:reduce){.k-side-chev{transition:none}}
// KATA Sidebar — collapsible groups. Everything else is plain links.
document.querySelectorAll('[data-side-toggle]').forEach(function (btn) {
  btn.addEventListener('click', function () {
    var group = btn.closest('.k-side-group');
    if (!group) return;
    var open = group.classList.toggle('open');
    btn.setAttribute('aria-expanded', open ? 'true' : 'false');
  });
});

Installation

CLI

node kata-ui.mjs add sidebar

Writes the part’s CSS and JS into your project. New to the CLI? See the CLI doc.

Manual

  1. Load tokens.css once, before any part.
  2. Copy the CSS tab into your stylesheet.
  3. Copy the HTML where it belongs. The part has a script — include it after the markup; it initializes itself.

Examples

Icon rail

The rail

Same part, one class narrower. Labels hide visually and stay in the markup; every icon keeps its title. For tools whose users live in the content, not the nav.

<div style="display:flex;border:1px solid var(--k-line);border-radius:14px;overflow:hidden;max-width:480px;background:var(--k-bg)">
  <nav class="k-side rail" data-side aria-label="Rail preview">
    <div class="k-side-brand"><span class="k-side-mark"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="square" stroke-linejoin="bevel" aria-hidden="true"><path d="M12 3.5 2.5 8.5 12 13.5l9.5-5L12 3.5Z"/><path d="m2.5 12.8 9.5 5 9.5-5"/></svg></span></div>
    <div class="k-side-nav">
      <a class="k-side-item on" href="#" title="Overview"><svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="square" stroke-linejoin="bevel" aria-hidden="true"><path d="m3 11 9-8 9 8"/><path d="M5 9.5V20a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V9.5"/></svg><span class="k-side-t">Overview</span></a>
      <a class="k-side-item" href="#" title="Projects"><svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="square" stroke-linejoin="bevel" aria-hidden="true"><path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V7Z"/></svg><span class="k-side-t">Projects</span></a>
      <a class="k-side-item" href="#" title="Calendar"><svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="square" stroke-linejoin="bevel" aria-hidden="true"><rect x="3.5" y="5" width="17" height="16" rx="2"/><path d="M3.5 10h17M8 3v4M16 3v4"/></svg><span class="k-side-t">Calendar</span></a>
      <a class="k-side-item" href="#" title="Reports"><svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="square" stroke-linejoin="bevel" aria-hidden="true"><path d="M6 20v-6M12 20V4M18 20v-9"/><path d="M3.5 20.5h17"/></svg><span class="k-side-t">Reports</span></a>
      <a class="k-side-item" href="#" title="Team"><svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="square" stroke-linejoin="bevel" aria-hidden="true"><circle cx="9" cy="8.5" r="3.4"/><path d="M2.8 20c.7-3.4 3.2-5.2 6.2-5.2s5.5 1.8 6.2 5.2"/><path d="M16 5.4a3.4 3.4 0 0 1 0 6.4M18.5 15.4c1.5.8 2.5 2.4 2.9 4.6"/></svg><span class="k-side-t">Team</span></a>
      <a class="k-side-item" href="#" title="Settings"><svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="square" stroke-linejoin="bevel" aria-hidden="true"><path d="M3 6h10M17 6h4M3 12h4M11 12h10M3 18h12M19 18h2"/><circle cx="15" cy="6" r="2"/><circle cx="9" cy="12" r="2"/><circle cx="17" cy="18" r="2"/></svg><span class="k-side-t">Settings</span></a>
    </div>
    <div class="k-side-user"><span class="k-side-ava">AR</span></div>
  </nav>
  <div style="flex:1;padding:20px;min-width:0">
    <p style="font-size:15px;font-weight:600">The rail</p>
    <p style="font-size:13px;color:var(--k-ink-2);line-height:1.8;margin-top:6px">Same part, one class narrower. Labels hide visually and stay in the markup; every icon keeps its title. For tools whose users live in the content, not the nav.</p>
  </div>
</div>

In dark

Activity

Nothing about the part changes in the dark — the tokens turn, the core stays vermillion. This whole frame is one data-theme attribute.

<div data-theme="dark" style="border-radius:14px;padding:14px;background:var(--k-zinc-950)">
  <div style="display:flex;border:1px solid var(--k-line);border-radius:12px;overflow:hidden;background:var(--k-bg)">
    <nav class="k-side" data-side aria-label="Dark sidebar preview">
      <div class="k-side-brand"><span class="k-side-mark"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="square" stroke-linejoin="bevel" aria-hidden="true"><path d="M12 3.5 2.5 8.5 12 13.5l9.5-5L12 3.5Z"/><path d="m2.5 12.8 9.5 5 9.5-5"/></svg></span>Northwind</div>
      <div class="k-side-sec">MAIN</div>
      <div class="k-side-nav">
        <a class="k-side-item" href="#"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="square" stroke-linejoin="bevel" aria-hidden="true"><path d="m3 11 9-8 9 8"/><path d="M5 9.5V20a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V9.5"/></svg><span class="k-side-t">Overview</span></a>
        <a class="k-side-item on" href="#"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="square" stroke-linejoin="bevel" aria-hidden="true"><path d="M18 16H6c.6-1.2 1-2.6 1-4.5V10a5 5 0 0 1 10 0v1.5c0 1.9.4 3.3 1 4.5Z"/><path d="M10 20a2 2 0 0 0 4 0"/></svg><span class="k-side-t">Activity</span><span class="k-side-badge">9</span></a>
        <a class="k-side-item" href="#"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="square" stroke-linejoin="bevel" aria-hidden="true"><path d="M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8l-5-5Z"/><path d="M14 3v5h5M9 13h6M9 17h6"/></svg><span class="k-side-t">Documents</span></a>
        <a class="k-side-item" href="#"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="square" stroke-linejoin="bevel" aria-hidden="true"><path d="M3 6h10M17 6h4M3 12h4M11 12h10M3 18h12M19 18h2"/><circle cx="15" cy="6" r="2"/><circle cx="9" cy="12" r="2"/><circle cx="17" cy="18" r="2"/></svg><span class="k-side-t">Settings</span></a>
      </div>
      <div class="k-side-user"><span class="k-side-ava">AR</span><span class="k-side-umeta"><span class="k-side-uname">Aoki Ren</span><br><span class="k-side-urole">Workspace admin</span></span></div>
    </nav>
    <div style="flex:1;padding:20px;min-width:0">
      <p style="font-size:15px;font-weight:600">Activity</p>
      <p style="font-size:13px;color:var(--k-ink-2);line-height:1.8;margin-top:6px">Nothing about the part changes in the dark — the tokens turn, the core stays vermillion. This whole frame is one data-theme attribute.</p>
    </div>
  </div>
</div>

Usage

Drop it at the left edge of an app frame. The current page is marked by the vermillion core on its icon — the same mark the App Shell block and the templates use. Groups collapse with the small script; without the script they stay exactly as written, so write the important one open.

Accessibility

A real nav landmark of links; group buttons carry aria-expanded and the sub-list is plain links. In the rail the label is hidden visually, never removed — keep it in the markup and add a title so the icon still has a name.

Anatomy

The public surface of this part, read from its own source. Class names are the API — the CSS tab above is the full contract.

.k-sideclass
.k-side-brandclass
.k-side-markclass
.k-side-secclass
.k-side-navclass
.k-side-itemclass
.onclass
.k-side-badgeclass
.k-side-chevclass
.k-side-groupclass
.openclass
.k-side-subclass
.k-side-userclass
.k-side-avaclass
+5 moreclasses — see the CSS tab
data-sidedata hook
data-side-toggledata hook
aria-labelARIA
aria-hiddenARIA
aria-expandedARIA

Related parts