# Niveus — reference
Every class, token, attribute and function the system exposes, with the name
the rest of the industry uses for it.
Two audiences:
- **People.** Find the thing you mean by its usual name, then use the class
beside it.
- **Models.** This file is the whole API. Hand it over on its own and an
assistant can build correct Niveus markup without seeing the CSS: it does not
need to know *how* `.nv-nav-tabs` works, only that a tab list is spelled that
way here. Nothing below is aspirational — `tools/check.py` fails if a class
exists in the CSS and is missing from this file.
Everything ships inside the `niveus` cascade layer, so unlayered application
styles win without `!important`.
```html
```
---
## Button
| Class | Known as | Does |
| --- | --- | --- |
| `.nv-button` | button, secondary button | Raised surface. The default; use it for anything that is not *the* action. |
| `.nv-button--primary` | filled / CTA button | The single affirmative action in a view. |
| `.nv-button--subtle` | tonal button | Accent-tinted fill, no elevation. Mid-emphasis. |
| `.nv-button--ghost` | text / quiet button | No material until hovered. Lowest emphasis. |
| `.nv-button--danger` | destructive button | Irreversible actions only. |
| `.nv-button--frosted` | glass button | For use over imagery or frosted chrome. |
| `.nv-button--float` | FAB, overlay control | Floats over content: grows on hover instead of lifting, and keeps its own positioning via `--nv-button-offset`. |
| `.nv-button--sm` `.nv-button--lg` | size variants | 28px and 44px; default is 36px. |
| `.nv-button--icon` | icon button | Square. Requires `aria-label`. |
| `.nv-button--pill` | pill button | Fully rounded. |
| `.nv-button--block` | full-width button | Fills its container. |
| `.nv-button__icon` | button icon slot | Sizes an inline SVG to the label. |
| `.nv-button-group` | segmented control, button group | Buttons sharing edges; only outer corners round. |
States come from the element: `disabled`, `aria-disabled`, `aria-busy="true"`
(shows a spinner and keeps the width), `aria-pressed` for toggles.
## Form controls
| Class | Known as | Does |
| --- | --- | --- |
| `.nv-field` | form field, form group | Label + control + hint, correctly spaced. |
| `.nv-field__label` | field label | Add `data-optional="(optional)"` to append a muted suffix. |
| `.nv-field__hint` | helper text | Guidance below the control. |
| `.nv-field__error` | validation message | Pair with `aria-invalid="true"` + `aria-describedby`. |
| `.nv-input` | text field, form control | `input`, `textarea` and `select`. Inset material. |
| `.nv-input--sm` `.nv-input--lg` | size variants | Match the button sizes. |
| `.nv-input--color` | color well / swatch input | `input[type=color]` as a square swatch. |
| `.nv-input-group` | input with adornment | Wrapper for a field with a prefix or suffix. |
| `.nv-input-group__affix` | prefix / suffix adornment | Sits inside the field's recess. First child = leading, last = trailing. |
| `.nv-select` | select, dropdown | Wrapper that draws the chevron around a native `select.nv-input`. |
| `.nv-checkbox` | checkbox | Native input, custom mark. Supports `:indeterminate`. |
| `.nv-radio` | radio button | Native input, custom mark. |
| `.nv-switch` | toggle switch | Inset track, elevated thumb that travels. |
| `.nv-choice` | control with inline label | `` wrapping a control and its text. |
## Card
| Class | Known as | Does |
| --- | --- | --- |
| `.nv-card` | card, panel | Resting container at elevation 1. |
| `.nv-card--elevated` | raised card | Elevation 2 — read before its surroundings. |
| `.nv-card--floating` | floating card | Elevation 3. |
| `.nv-card--inset` | well, sunken panel | Recessed into its parent. |
| `.nv-card--frosted` | glass card | Translucent, for use over imagery or a bed. |
| `.nv-card--interactive` | clickable card | Lifts on hover, sinks on press. |
| `.nv-card--flush` | edge-to-edge card | Removes part padding, for media or tables. |
| `.nv-card__header` | card header | |
| `.nv-card__title` | card title | |
| `.nv-card__subtitle` | card subtitle, supporting text | |
| `.nv-card__body` | card content | |
| `.nv-card__footer` | card actions | |
| `.nv-card__footer--plain` | undivided card actions | Drops the divider above the footer. |
| `.nv-card__media` | card media | 16:9 image slot. |
| `.nv-card__link` | stretched link | Expands one link's hit area over the whole card. |
| `.nv-card-grid` | responsive card grid | Auto-fitting, equal-height columns. |
## Dialog
Built on native ``; open with `showModal()` or `nv.openDialog()`.
| Class | Known as | Does |
| --- | --- | --- |
| `.nv-dialog` | modal dialog | Elevation 4 over a blurred scrim. Focus trap and Escape are the platform's. |
| `.nv-dialog--sheet` | bottom sheet | Enters from the block end, flush to the edges. |
| `.nv-dialog--compact` `.nv-dialog--wide` | width variants | 24rem / 44rem; default 30rem. |
| `.nv-dialog__header` | dialog header | |
| `.nv-dialog__title` | dialog title | Point `aria-labelledby` at it. |
| `.nv-dialog__description` | dialog supporting text | |
| `.nv-dialog__body` | dialog content | The only scrolling region. |
| `.nv-dialog__footer` | dialog actions | |
| `.nv-dialog__footer--divided` | grounded dialog actions | For a footer sitting over scrollable content. |
| `.nv-dialog__close` | close button | Optical alignment for a ghost icon button. |
## Menu
Built on the `popover` attribute and anchor positioning. Trigger and menu name
the same anchor through `--nv-anchor`.
| Class | Known as | Does |
| --- | --- | --- |
| `.nv-menu` | dropdown menu, popover menu | Frosted surface anchored to its trigger. |
| `.nv-menu-trigger` | menu button | Sets `anchor-name` from `--nv-anchor`. |
| `.nv-menu__item` | menu item | `aria-checked="true"` draws a tick. |
| `.nv-menu__item--danger` | destructive menu item | |
| `.nv-menu__label` | menu section label / group heading | |
| `.nv-menu__separator` | menu divider | |
| `.nv-menu__shortcut` | keyboard shortcut hint, accelerator | Trailing muted text. |
## Navigation
| Class | Known as | Does |
| --- | --- | --- |
| `.nv-nav` | app bar, navigation bar, header | Frosted, sticky chrome. |
| `.nv-nav--vertical` | sidebar, side navigation | Full-height, solid; drops the translucency. |
| `.nv-nav--plain` | solid bar | Opaque instead of frosted. |
| `.nv-nav--static` | non-sticky bar | |
| `.nv-nav--inline` | inline nav group | A navigation used inside content, not as chrome. |
| `.nv-nav__brand` | brand / logo lockup | |
| `.nv-nav__list` | nav list | |
| `.nv-nav__item` | nav item, nav link | Selected via `aria-current`, `aria-selected` or `--active`. |
| `.nv-nav__item--active` | active nav item | For when no ARIA state fits. |
| `.nv-nav__section` | nav section heading | |
| `.nv-nav__icon` | nav icon slot | |
| `.nv-nav__badge` | count badge, notification badge | |
| `.nv-nav__spacer` | flexible spacer | Pushes what follows to the end. |
| `.nv-nav-tabs` | tab list, segmented tabs | Inset track; the selected tab lifts out of it. |
| `.nv-tab-panel` | tab panel | Carries the shared content name so panels cross-fade. |
| `.nv-breadcrumbs` | breadcrumbs | |
## Disclosure
| Class | Known as | Does |
| --- | --- | --- |
| `.nv-disclosure` | disclosure, accordion item | A `` whose height animates open and closed. |
| `.nv-disclosure--plain` | bare disclosure | No surface of its own. |
| `.nv-disclosure__summary` | disclosure trigger | The ``. |
| `.nv-disclosure__chevron` | chevron, caret | Rotates rather than swapping glyphs. |
| `.nv-disclosure__body` | disclosure content | |
| `.nv-disclosure-group` | accordion | Stacked disclosures sharing hairlines. |
| `.nv-collapse` | collapsible region | Same relationship for markup that cannot be a ``. Toggle `data-open`. |
## Scroller
| Class | Known as | Does |
| --- | --- | --- |
| `.nv-scroller-frame` | carousel frame | Positions the controls; holds the track. |
| `.nv-scroller` | carousel, snap scroller, rail | Horizontal row with scroll snapping and fading edges. |
| `.nv-scroller--auto` | content-width items | Items size to content instead of the track. |
Set `--nv-scroller-item` for item width, `--nv-scroller-fade` for the edge fade.
## Badge
| Class | Known as | Does |
| --- | --- | --- |
| `.nv-badge` | badge, chip, tag, status pill | Non-interactive statement of state. |
| `.nv-badge--accent` | accent badge | |
| `.nv-badge--success` `.nv-badge--warning` `.nv-badge--danger` | status badges | Tone follows the semantic role. |
| `.nv-badge--solid` | filled badge | For the one badge that must be seen first. |
| `.nv-badge--count` | count badge | Tabular, borderless, min two digits. |
| `.nv-badge--square` | square badge | |
| `.nv-badge__dot` | status dot | |
## Table
| Class | Known as | Does |
| --- | --- | --- |
| `.nv-table-frame` | table wrapper | Scrolls sideways so the page does not have to. |
| `.nv-table` | data table | |
| `.nv-table--compact` | dense table | |
| `.nv-table--interactive` | clickable rows | |
| `.nv-table__number` | numeric cell | End-aligned, tabular figures. |
| `.nv-table__actions` | row actions cell | Shrinks to content. |
## Bed
| Class | Known as | Does |
| --- | --- | --- |
| `.nv-bed` | showcase surface, patterned backdrop | Ground that is visibly not ordinary background: for regions the user should look *at*. Gives translucent materials something to be translucent against. |
| `.nv-bed--quiet` | subdued bed | No hatch, softer blooms. |
| `.nv-bed--vivid` | emphatic bed | |
| `.nv-bed--single` | single-hue bed | One color instead of three. |
| `.nv-bed--flush` | full-bleed bed | Square, no side borders. |
| `.nv-bed__label` | bed label, eyebrow | |
Set `--nv-bed-tint` to lead with a color other than the accent.
## Surface, material and elevation
| Class | Known as | Does |
| --- | --- | --- |
| `.nv-surface` | surface, panel | Plain container on the solid material. |
| `.nv-material-solid` | opaque surface | Content lives here. The default. |
| `.nv-material-elevated` | raised surface | Separated from its context. |
| `.nv-material-inset` | recessed surface | Fields, wells, tracks. |
| `.nv-material-frosted` | frosted glass, blur backdrop | Chrome that content passes under. |
| `.nv-material-glass` | glass | Contextual layers where content behind must stay legible. |
| `.nv-elevation-0` `.nv-elevation-1` `.nv-elevation-2` | elevation / z-depth | flush · resting · raised |
| `.nv-elevation-3` `.nv-elevation-4` `.nv-elevation-5` | elevation / z-depth | floating · lifted · overlay |
| `.nv-elevation-inset-sm` `.nv-elevation-inset-md` `.nv-elevation-inset-lg` | inner shadow | Recessed surfaces. |
| `.nv-divider` | divider, separator, rule | |
| `.nv-divider--vertical` | column rule | Stretches to its flex row. |
Material and elevation are independent: combine freely.
## Type roles
| Class | Known as | Size |
| --- | --- | --- |
| `.nv-display` | display, hero text | 38px |
| `.nv-heading` | heading | 24px |
| `.nv-title` | title, subheading | 17px |
| `.nv-body` | body copy | 15px |
| `.nv-label` | label, UI text | 13px |
| `.nv-caption` | caption, secondary text | 12px |
| `.nv-overline` | overline, eyebrow, kicker | 12px uppercase |
| `.nv-code` | code, monospace | 13px |
| `.nv-text-primary` `.nv-text-secondary` `.nv-text-tertiary` | text color roles | Emphasis, not size. |
| `.nv-text-accent` `.nv-text-success` `.nv-text-warning` `.nv-text-danger` | semantic text colors | |
## Layout utilities
| Class | Known as | Does |
| --- | --- | --- |
| `.nv-container` | page container, wrapper | Max width + gutters. |
| `.nv-stack` | stack, vertical rhythm | Column with a gap. |
| `.nv-stack--tight` `.nv-stack--loose` | stack density | |
| `.nv-cluster` | cluster, wrap row | Wrapping row, vertically centred. |
| `.nv-cluster--tight` | dense cluster | |
| `.nv-cluster--between` | spread cluster | Pushes children to both ends. |
| `.nv-truncate` | ellipsis, text truncation | One line with an ellipsis. |
| `.nv-prose` | prose, measure | Readable line length and leading. |
| `.nv-visually-hidden` | screen-reader-only, sr-only | Available to assistive tech, invisible on screen. |
| `.nv-continuous` | cross-fading region | Content that should cross-fade in place when it changes. |
| `.nv-carried` | (view-transition class) | Applied to nav items so they ride above a travelling marker. |
| `.nv-travelling` | (view-transition class) | Applied to a selection marker so it travels below the labels. |
---
## Tokens
Names are stable; values are not. Never state a color, shadow, radius, size or
duration directly — reference the token.
### Color roles
`--nv-color-` +
```
background background-subtle surface surface-elevated surface-inset
surface-hover surface-active scrim
text-primary text-secondary text-tertiary text-disabled text-inverted
border-subtle border border-strong
accent accent-hover accent-active accent-subtle accent-subtle-hover
accent-border accent-text on-accent
success success-hover success-subtle success-border success-text on-success
warning warning-hover warning-subtle warning-border warning-text on-warning
danger danger-hover danger-active danger-subtle danger-border
danger-text on-danger
shadow-ambient shadow-penumbra shadow-umbra shadow-inset
highlight highlight-strong elevation-tint-1 … -5
material-frosted material-glass material-border
focus-ring focus-ring-contrast selection
```
`on-*` is the text that goes on top of that color, and is derived — never set
it by hand.
### Color inputs
| Token | Default | Does |
| --- | --- | --- |
| `--nv-brand` | `#4f6cff` | The one color everything derives from. |
| `--nv-brand-tint` | `4%` | How much brand bleeds into the greys. |
| `--nv-brand-harmony` | `12%` | How far status colors lean towards the brand. |
| `--nv-contrast-pivot` | `0.7` | Lightness where a color can no longer carry a label. |
| `--nv-contrast-dark` / `-light` | `0.53` / `0.78` | How far either side a color is pushed. |
`--nv-palette-{neutral|accent|success|warning|danger}-{0…1000}` are raw values.
Components must never reference them.
### Scales
| Family | Steps |
| --- | --- |
| `--nv-space-` | `0 px 0-5 1 1-5 2 2-5 3 4 5 6 7 8 10 12 14 16 20 24 32` (suffix = px ÷ 4) |
| `--nv-radius-` | `none xs sm md lg xl 2xl full`, plus `nested-md` `nested-lg` |
| `--nv-font-size-` | `2xs xs sm md lg xl 2xl 3xl 4xl 5xl` |
| `--nv-font-weight-` | `regular medium semibold bold` |
| `--nv-line-height-` | `tight snug normal relaxed` |
| `--nv-letter-spacing-` | `tighter tight normal wide wider` |
| `--nv-font-` | `display heading title body label caption code` (composite shorthands) |
| `--nv-font-family-` | `sans mono` |
| `--nv-measure` | `-narrow` · `--nv-measure` · `-wide` |
| `--nv-control-height-` | `sm md lg` — also `control-padding-` and `control-gap-` |
| `--nv-elevation-` | `0 1 2 3 4 5`, `inset-sm` `inset-md` `inset-lg` |
| `--nv-highlight-` | `top` `top-strong` `edge` |
| `--nv-blur-` | `sm md lg xl` — also `backdrop-frosted` `backdrop-glass` `backdrop-scrim` |
| `--nv-material-` | `{solid,elevated,inset,frosted,glass}-{bg,border,shadow}` |
### Motion
| Family | Steps |
| --- | --- |
| `--nv-duration-` | `instant fast quick normal slow slower travel expand theme` |
| `--nv-ease-` | `standard entrance exit spring emphasized linear` |
| `--nv-transition-` | `colors depth control surface expand` (composites) |
| displacement | `--nv-lift-hover` `--nv-press-depth` `--nv-travel-sm/md/lg` |
`prefers-reduced-motion` collapses every duration and displacement at the token
level. Components never opt in individually.
### Other
`--nv-focus-ring` · `--nv-focus-ring-width` · `--nv-border-width` ·
`--nv-border-width-strong` · `--nv-target-min` · `--nv-layout-gutter` ·
`--nv-layout-max-width` · `--nv-selection-name` · `--nv-anchor` ·
`--nv-button-offset` · `--nv-bed-tint` · `--nv-scroller-item` ·
`--nv-scroller-fade` · `--nv-content-name`
---
## JavaScript
`niveus.js` is optional and dependency-free; it exposes `window.nv`. Without it
everything still renders — state changes simply arrive instead of travelling.
| Function | Signature | Does |
| --- | --- | --- |
| `nv.transition` | `(update, { direction, kind }) => Promise` | Runs `update` inside a view transition so the change can be followed. `direction` is `"forward"`/`"backward"`; `kind: "theme"` slows the cross-fade. Falls back to running `update` directly under reduced motion or without API support. |
| `nv.setTheme` | `("light" \| "dark" \| "system") => Promise` | Cross-fades the whole surface into the new appearance and fires `nv:theme` on ``. |
| `nv.syncThemeControls` | `(theme) => void` | Sets `aria-pressed` on every `[data-nv-theme]`. |
| `nv.openDialog` | `(dialog \| id, trigger?) => dialog` | `showModal()`, plus a transform origin so the dialog expands out of its trigger. |
| `nv.selectTab` | `(tablist, tab) => Promise` | Moves selection and its panel, with direction. |
| `nv.initScroller` | `(frame) => void` | Wires one scroller's controls. |
| `nv.liftLabels` | `(scope) => void` | Names navigation items so a travelling marker passes behind them. |
| `nv.wire` | `(scope = document) => void` | Applies all of the below. Runs once on load; call again after injecting markup. |
| `nv.prefersReducedMotion` | `() => boolean` | |
### Data attributes
| Attribute | On | Does |
| --- | --- | --- |
| `data-theme` | `` | `light` / `dark`. Absent follows the OS. |
| `data-nv-brand` | any element | Re-derives the whole color set for that subtree. |
| `data-nv-theme` | button | Sets the appearance when clicked. |
| `data-nv-dialog` | button | Opens the dialog with that id, from itself. |
| `data-nv-close` | button | Closes its dialog or popover. |
| `data-nv-tabs` | tablist | Wires `[role=tab]` children to their `aria-controls` panels, with arrow keys. |
| `data-nv-scroller` | `.nv-scroller-frame` | Wires its `[data-nv-scroll="prev"\|"next"]` controls. |
| `data-scrolled` | `.nv-nav` | Set by the application on scroll; gives the bar its shadow. |
| `data-nv-direction` | `` | Set during a transition by `nv.transition`. |
| `data-nv-transition` | `` | `"theme"` during an appearance change. |
---
## Rules that bite
1. **`view-transition-name` must be unique per document.** A duplicate makes
the browser skip the transition entirely. Each selection group needs its own
`--nv-selection-name`; `.nv-nav-tabs` defaults to `nv-tabs-selection` and
everything else to `nv-selection`, which is enough for one of each per page.
2. **A menu and its trigger must name the same anchor** through `--nv-anchor`,
and the value must be unique per pair.
3. **Only one `.nv-tab-panel` may be visible at a time** — hide the rest with
`hidden`. They share one content name.
4. **Never reference `--nv-palette-*` from application code.** It is raw, and
does not adapt to the appearance.
5. **A floating control positioned with `translate`** needs
`.nv-button--float` and `--nv-button-offset`, or the hover lift overwrites
its position.
6. **Icon-only buttons need `aria-label`.** The system gives them a 44px target
but cannot give them a name.
---
Made by **Nexoniarz**.