Appearance
Nav โ
A sticky top app bar built around three named slots โ start, default (center), and end โ plus an optional extension second row. Three densities (compact / comfortable / default), three variants (flat / elevated / outlined), and eleven colors (ten palette roles + surface) โ or any CSS color, e.g. color="#7c3aed". Writes its resolved height to --mono-nav-height on :root so layout wrappers can pad themselves without prop drilling. Toggle Vue / CSS to switch the live demo and source together.
Basecoat ships no nav component โ basecoat-css@1.0.2 has dialog, drawer, sidebar, tabs and the rest, but no header bar โ so this is an extension. What it does ship is a wide rectangular surface with an edge and an elevation, and that is exactly what a top bar is: the nav's chrome tracks .card value for value โ radius, ring, elevation, gutter and type โ so every flavor's nav delta is its card delta. sera's bar is square, roomy and shadow-sm; maia's is rounded-2xl and flat; luma's is the rounded-4xl pill with shadow-md; lyra's is square, tight and text-xs. Put a nav above a card and the two edges line up.
The bar's own ladder โ three densities, three variants, the extension row โ is mono's, and .sidebar nav supplies the chrome ink (--sidebar for the fill, the bar ink at 70% for muted copy, --sidebar-border for the extension hairline). A coloured bar paints in the role and inks in that role's -foreground, the way .btn[data-variant="primary"] does. The two-stop brand gradients, the --*-rgb triples and the hand-rolled contrast maths are gone, and dark mode comes free.
A full-bleed bar wants no corners
The bar inherits the card's radius and the card's inset ring, which is right inside a page frame and wrong flush against the viewport. At the very top of a page, set --mono-nav-radius: 0 and --mono-nav-ring-width: 0.
Basic โ
Sticky top bar with a brand on the left and an avatar on the right.
Vue SFC
Density โ
compact (48 px), comfortable (56 px), default (64 px).
Vue SFC
Colors โ
Pick a colour and every variant takes it. Six themed accents plus the white surface default, across flat (no shadow), elevated (shadow) and outlined (bottom border).
Vue SFC
Extension row โ
Second row beneath the main bar via the extension slot โ useful for tabs or breadcrumbs.
Vue SFC
Non-sticky โ
Inline header that scrolls with the page.
Vue SFC
Sticky not sticking? Check the ancestors' overflow
sticky defaults to true and applies position: sticky; top: 0 โ but a sticky element sticks to its nearest scroll container, not necessarily the viewport. Any ancestor with overflow set to hidden, auto or scroll on either axis becomes that container and captures the nav.
The usual culprit is a page wrapper with overflow-x-hidden. Per CSS overflow, when one axis is not visible the other computes from visible to auto โ so overflow-x-hidden silently makes the <div> a scroll container. Its height is content-driven, so it never scrolls internally: the nav gets zero scroll range and rides the document scroll away.
Fix: use overflow-x: clip. It suppresses horizontal overflow the same way but is not a scroll container, so overflow-y stays visible. (presetWind4 ships the overflow-x-clip utility.)
diff
- <div class="bg-white relative overflow-x-hidden w-full">
+ <div class="bg-white relative overflow-x-clip w-full">Measured in a real layout chain: with hidden the nav moved top 0 โ -604px over an 800px scroll; with clip it held at top 0.
Dashboard top bar โ
The nav is only layout, so everything in its three regions is a real component: two <mono-button icon-only>s (one badged), a <mono-input> with a slotted prefix icon, and a <mono-dropdown> whose body is a column of text buttons. The Shadow tab shows the mix a real app ends up with โ the bar is the shadow build, its slotted children stay light, and the slot is the boundary. The CSS tab is the same bar in four attribute contracts at once, with no Lit on the page.
Vue SFC
Layout var โ
Reads --mono-nav-height from :root to auto-pad the page below the bar.
Vue SFC
Customized โ
Override per-section styling via cssClass (Vue) or utility classes (CSS).
Vue SFC
CSS Variables โ
Vue SFC
Every nav is themed through --mono-nav-* custom properties. Setting one on the element, on any wrapper/ancestor, or inline all work โ custom properties inherit, and they pierce the shadow-DOM boundary, so the same overrides apply to <mono-nav> and the shadow build. The density, color and variant props set presets, but an explicit --mono-nav-* override always wins. To re-skin globally, set the underlying tokens (--sidebar, --border, the role colours โฆ) or switch flavor.
The bar height knob is
--mono-nav-bar-heightโ--mono-nav-heightis the separate layout-padding value the nav writes to:rootfor.mono-layout-content.
| Variable | Default | Controls |
|---|---|---|
--mono-nav-surface | --sidebar (which is --card) | The unpainted bar's fill |
--mono-nav-radius | the card's โ --mono-radius-xl at vega | Bar corner radius. This is the knob each flavor moves: 0 at lyra and sera, 2xl at maia, 3xl at rhea, 4xl at luma |
--mono-nav-ring-color / -ring-width | --foreground/10 / --mono-border-width | The card's ring-1, drawn INSIDE the box so nothing clips it. luma, sera and rhea fade it to /5; 0 width removes it |
--mono-nav-border | the ring colour | The outlined variant's bottom rule โ the one piece of nav chrome the card has no counterpart for |
--mono-nav-bg / -text | the surface / --sidebar-foreground | The bar's fill and ink โ a colour role re-points both |
--mono-nav-text-soft | the bar ink at 70% | Muted / secondary ink, upstream's text-sidebar-foreground/70 |
--mono-nav-border-lite | --sidebar-border | The hairline above the extension row |
--mono-nav-accent / -on-accent | --primary / --primary-foreground | The colour in play and the ink that sits on it (set by color) |
--mono-nav-<role> | the ten role tokens | Each role's own slot โ --mono-nav-danger defaults to --destructive, and so on |
--mono-nav-bar-height / -bar-height-<density> | 14 ร --mono-spacing (56px) at comfortable | The bar row's height. Flavors follow their card's vertical rhythm: 48 where the card is py-4, 52 at py-5, 64 at py-8 |
--mono-nav-extension-height / -extension-height-<density> | 11 ร --mono-spacing (44px) | The second row's height |
--mono-nav-pad-x / -pad-x-<density> | the card's px-6 (24px) at comfortable | The bar's gutter. The compact and default steps scale from the comfortable one, so --mono-nav-pad-x-comfortable alone moves all three |
--mono-nav-gap / -gap-<density> | 3 ร --mono-spacing (12px) | The gap between items; the end region uses 70% of it |
--mono-nav-font / -font-<density> | --mono-text-sm | The bar's type. lyra and mira drop it to text-xs |
--mono-nav-extension-font / -extension-font-<density> | --mono-text-sm | The second row's type |
--mono-nav-shadow | the card's โ --mono-shadow-xs at vega | The elevated elevation, on top of the ring. nova, maia, lyra and mira drop it; sera and rhea take sm, luma md; ONE restores its own |
--mono-nav-border-width | --mono-border-width | The outlined rule's and the extension hairline's thickness |
--mono-nav-backdrop-filter | none | Opt back in to the pre-port translucent blurred bar |
--mono-nav-z | 30 | The sticky bar's layer |
Types โ
Import
import { NavProps } from 'mono-helper'| Prop | Value | Default | Description |
|---|---|---|---|
sticky | boolean | โ | Sticks the bar to the top of the viewport on scroll. |
density | 'default' | 'compact' | 'comfortable' | โ | Vertical spacing density of the bar. |
color | 'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'info' | 'teal' | 'purple' | 'neutral' | 'dark' | 'surface' | string & {} | โ | Theme color of the bar background. |
variant | 'elevated' | 'outlined' | 'flat' | โ | Visual style of the bar (flat, elevated, or outlined). |
extension | boolean | โ | Renders an additional extension row below the bar. |
cssClass | NavCssClass | โ | Per-part class overrides for internal elements. |