Components / Layout & Navigation / Bottom Navigation

Bottom Navigation stable

The mobile app tab bar: three to five destinations under the thumb, the current one lit with the core.

Preview

Home

The bar is the part; this is the room it stands in. Tap a destination — the core moves to it.

<div style="max-width:330px;border:1px solid var(--k-line);border-radius:18px;overflow:hidden;background:var(--k-bg)">
  <div style="padding:16px;min-height:120px">
    <p style="font-size:14px;font-weight:600">Home</p>
    <p style="font-size:12.5px;color:var(--k-ink-2);line-height:1.75;margin-top:5px">The bar is the part; this is the room it stands in. Tap a destination — the core moves to it.</p>
  </div>
  <nav class="k-bnav" data-bnav aria-label="Bottom">
    <a class="on" href="#"><svg width="19" height="19" 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="lbl">Home</span></a>
    <a href="#"><svg width="19" height="19" 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="lbl">Docs</span></a>
    <a href="#"><svg width="19" height="19" 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 5v14M5 12h14"/></svg><span class="lbl">New</span></a>
    <a href="#"><svg width="19" height="19" 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="lbl">Alerts</span><span class="dot"></span></a>
    <a href="#"><svg width="19" height="19" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="square" stroke-linejoin="bevel" aria-hidden="true"><circle cx="12" cy="8" r="3.6"/><path d="M5 20c.8-3.2 3.6-5 7-5s6.2 1.8 7 5"/></svg><span class="lbl">You</span></a>
  </nav>
</div>
/* KATA Bottom Navigation — destinations under the thumb. */
.k-bnav{display:flex;background:var(--k-bg);border-top:1px solid var(--k-line);font-family:var(--k-font);padding:6px 8px calc(6px + env(safe-area-inset-bottom))}
.k-bnav a{flex:1;display:flex;flex-direction:column;align-items:center;gap:3px;padding:6px 2px;border-radius:9px;color:var(--k-ink-3);text-decoration:none;font-size:10.5px;font-weight:550;position:relative}
.k-bnav a:hover{background:var(--k-bg-soft)}
.k-bnav a.on{color:var(--k-ink)}
.k-bnav a.on svg{color:var(--k-core)}
.k-bnav .dot{position:absolute;top:5px;right:calc(50% - 14px);width:7px;height:7px;border-radius:50%;background:var(--k-core);border:1.5px solid var(--k-bg)}
.k-bnav.icons a{padding:9px 2px}
.k-bnav.icons .lbl{display:none}
// KATA Bottom Navigation — in the catalog preview, taps move the marker.
// In production these are links; the current page carries .on.
document.querySelectorAll('[data-bnav]').forEach(function (bar) {
  bar.querySelectorAll('a').forEach(function (a) {
    a.addEventListener('click', function (e) {
      e.preventDefault();
      bar.querySelectorAll('a').forEach(function (x) { x.classList.remove('on'); });
      a.classList.add('on');
    });
  });
});

Installation

CLI

node kata-ui.mjs add bottom-navigation

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

Icons only

Icons only

For the smallest screens. The labels are gone from the eye, so every link carries an aria-label instead.

<div style="max-width:330px;border:1px solid var(--k-line);border-radius:18px;overflow:hidden;background:var(--k-bg)">
  <div style="padding:16px;min-height:120px">
    <p style="font-size:14px;font-weight:600">Icons only</p>
    <p style="font-size:12.5px;color:var(--k-ink-2);line-height:1.75;margin-top:5px">For the smallest screens. The labels are gone from the eye, so every link carries an aria-label instead.</p>
  </div>
  <nav class="k-bnav icons" data-bnav aria-label="Bottom, icons only">
    <a class="on" href="#" aria-label="Home"><svg width="20" height="20" 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></a>
    <a href="#" aria-label="Search"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="square" stroke-linejoin="bevel" aria-hidden="true"><circle cx="11" cy="11" r="7"/><path d="m21 21-4.5-4.5"/></svg></a>
    <a href="#" aria-label="New"><svg width="20" height="20" 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 5v14M5 12h14"/></svg></a>
    <a href="#" aria-label="You"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="square" stroke-linejoin="bevel" aria-hidden="true"><circle cx="12" cy="8" r="3.6"/><path d="M5 20c.8-3.2 3.6-5 7-5s6.2 1.8 7 5"/></svg></a>
  </nav>
</div>

Usage

For app-shaped pages on phones: the destinations a thumb can reach, always in the same order. Three to five items; a sixth means the app needs a menu, not a wider bar. The part ships the bar — fixing it to the viewport bottom is the page’s job.

Accessibility

A nav landmark of real links, each with an icon and a text label — the label is what the screen reader reads, so never ship the icon-only variant to production without aria-labels.

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-bnavclass
.onclass
.dotclass
.iconsclass
.lblclass
data-bnavdata hook
aria-labelARIA
aria-hiddenARIA

Related parts