Components / Layout & Navigation / Navigation Menu
Navigation Menu stable
Site navigation with panels: the top level stays one line, the depth opens underneath it.
The panel opens under its item. Hover or click — Escape puts it away.
<div style="border:1px solid var(--k-line);border-radius:14px;padding:10px 12px 150px;background:var(--k-bg)">
<div class="k-navm" data-navm>
<div class="k-navm-bar" role="navigation" aria-label="Preview">
<span class="k-navm-item open">
<button class="k-navm-btn" type="button" aria-expanded="true" aria-haspopup="true">Product <svg 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-navm-panel"><a class="k-navm-link" href="#"><span class="ic"><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="M12 3 3 7.5v9L12 21l9-4.5v-9L12 3Z"/><path d="M3 7.5 12 12l9-4.5M12 12v9"/></svg></span><span><b>Components</b><span>The parts themselves, with live previews.</span></span></a><a class="k-navm-link" href="#"><span class="ic"><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="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><span><b>Blocks</b><span>Parts already assembled into sections.</span></span></a><a class="k-navm-link" href="#"><span class="ic"><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><span><b>Themes</b><span>Five accents over one token set.</span></span></a><a class="k-navm-link" href="#"><span class="ic"><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><span><b>Changelog</b><span>What changed, and when.</span></span></a></div>
</span>
<span class="k-navm-item">
<button class="k-navm-btn" type="button" aria-expanded="false" aria-haspopup="true">Resources <svg 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-navm-panel">
<a class="k-navm-link" href="#"><span><b>Documentation</b><span>Install, theme and compose.</span></span></a>
<a class="k-navm-link" href="#"><span><b>Guides</b><span>Dashboards, settings and pricing, walked through.</span></span></a>
</div>
</span>
<a class="k-navm-btn" href="#">Pricing</a>
<a class="k-navm-btn" href="#">About</a>
</div>
</div>
<p style="font-size:12.5px;color:var(--k-ink-3);margin-top:8px">The panel opens under its item. Hover or click — Escape puts it away.</p>
</div>/* KATA Navigation Menu — one line on top, the depth underneath. */
.k-navm{position:relative;font-family:var(--k-font);color:var(--k-ink)}
.k-navm-bar{display:flex;align-items:center;gap:4px}
.k-navm-item{position:relative}
.k-navm-btn{display:flex;align-items:center;gap:6px;padding:8px 12px;border:0;background:none;font-family:inherit;font-size:13.5px;font-weight:550;color:var(--k-ink-2);border-radius:8px;cursor:pointer;text-decoration:none}
.k-navm-btn:hover,.k-navm-item.open .k-navm-btn{background:var(--k-bg-soft);color:var(--k-ink)}
.k-navm-btn svg{transition:transform .18s;color:var(--k-ink-3)}
.k-navm-item.open .k-navm-btn svg{transform:rotate(180deg)}
.k-navm-panel{position:absolute;inset-inline-start:0;top:calc(100% + 8px);min-width:300px;background:var(--k-bg);border:1px solid var(--k-line);border-radius:14px;box-shadow:0 20px 44px -14px rgba(16,24,40,.22);padding:8px;display:none;z-index:60}
.k-navm-item.open .k-navm-panel{display:block}
.k-navm-link{display:flex;gap:11px;padding:9px 10px;border-radius:9px;text-decoration:none;color:var(--k-ink)}
.k-navm-link:hover{background:var(--k-bg-soft)}
.k-navm-link .ic{width:32px;height:32px;flex:none;border:1px solid var(--k-line);border-radius:8px;display:flex;align-items:center;justify-content:center;color:var(--k-ink-2)}
.k-navm-link b{display:block;font-size:13.5px;font-weight:600}
.k-navm-link span{font-size:12.5px;color:var(--k-ink-2);line-height:1.55}
@media (prefers-reduced-motion:reduce){.k-navm-btn svg{transition:none}}
// KATA Navigation Menu — one panel at a time; Escape and outside clicks close.
document.querySelectorAll('[data-navm]').forEach(function (root) {
var items = Array.prototype.slice.call(root.querySelectorAll('.k-navm-item'));
function closeAll(except) {
items.forEach(function (it) {
if (it === except) return;
it.classList.remove('open');
var b = it.querySelector('.k-navm-btn'); if (b) b.setAttribute('aria-expanded', 'false');
});
}
items.forEach(function (it) {
var btn = it.querySelector('.k-navm-btn');
if (!btn || !it.querySelector('.k-navm-panel')) return;
btn.addEventListener('click', function () {
var open = it.classList.toggle('open');
btn.setAttribute('aria-expanded', open ? 'true' : 'false');
if (open) closeAll(it);
});
it.addEventListener('pointerenter', function () {
if (window.matchMedia('(hover: hover)').matches) { closeAll(it); it.classList.add('open'); btn.setAttribute('aria-expanded', 'true'); }
});
it.addEventListener('pointerleave', function () {
if (window.matchMedia('(hover: hover)').matches) { it.classList.remove('open'); btn.setAttribute('aria-expanded', 'false'); }
});
});
document.addEventListener('click', function (e) { if (!root.contains(e.target)) closeAll(null); });
document.addEventListener('keydown', function (e) { if (e.key === 'Escape') closeAll(null); });
});
Installation
CLI
node kata-ui.mjs add navigation-menu
Writes the part’s CSS and JS into your project. New to the CLI? See the CLI doc.
Manual
- Load
tokens.cssonce, before any part. - Copy the CSS tab into your stylesheet.
- Copy the HTML where it belongs. The part has a script — include it after the markup; it initializes itself.
Usage
For the header of a site with real depth — products with sub-pages, resources with kinds. On wide screens the panel opens under its item; below that, the honest answer is the drawer, not a squeezed panel. One panel open at a time, always.
Accessibility
Buttons carry aria-expanded and the panels are lists of plain links. Hover opens the panel for the mouse; the click is what the keyboard gets, and Escape closes and returns focus to the button.
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-navm | class |
.k-navm-bar | class |
.k-navm-item | class |
.k-navm-btn | class |
.open | class |
.k-navm-panel | class |
.k-navm-link | class |
.ic | class |
data-navm | data hook |
aria-label | ARIA |
aria-expanded | ARIA |
aria-haspopup | ARIA |
aria-hidden | ARIA |
Related parts
Accordion beta
Disclosure built on native <details>. Zero JavaScript, keyboard and find-in-page included.
Bottom Navigation stable
The mobile app tab bar: three to five destinations under the thumb, the current one lit with the core.
Breadcrumbs beta
Where you are, as a path. The last crumb is the page itself — not a link.
Collapsible stable
One disclosure on its own: a trigger row and the region it folds away. The Accordion is this, grouped.