Foundation
Color
Nerio color starts with immutable primitives, resolves through semantic intent, and reaches components through local aliases. Choose complete foreground, background, state, and accessibility contracts—not isolated swatches.
Color architecture
| Layer | Responsibility |
|---|---|
| Raw opaque and alpha color scales. They are immutable across theme, mode, and density selectors and are inputs to semantic roles, not product UI choices. | |
| Reusable intent such as canvas, primary text, focus ring, danger status, or primary action. Product composition consumes this layer. | |
| Local contracts such as Button background or Input border. Components consume semantic or component aliases, never primitive palette values directly. | |
| Theme changes accent personality, mode changes light/dark color mappings, and density changes spacing only. Density never redefines color primitives. |
The generated inventories below come from packages/tokens/src/styles.css via the accepted foundation metadata contract. Editorial recommendations remain hand-authored. See Themes for runtime-axis composition.
Primitive families
Opaque neutral and accent scales provide predictable raw values. Dark alpha neutrals adapt light-mode layers; light alpha neutrals adapt dark-mode layers. Alpha primitives composite with the surface below them, so a swatch alone cannot establish the final color or contrast.
Opaque neutral
--n-gray-0--n-gray-50--n-gray-100--n-gray-200--n-gray-300--n-gray-400--n-gray-500--n-gray-600--n-gray-700--n-gray-800--n-gray-900--n-gray-950--n-gray-1000Dark alpha neutral
--n-gray-a-4--n-gray-a-6--n-gray-a-8--n-gray-a-10--n-gray-a-12--n-gray-a-16--n-gray-a-20--n-gray-a-24Light alpha neutral
--n-white-a-4--n-white-a-6--n-white-a-8--n-white-a-10--n-white-a-12--n-white-a-16--n-white-a-20--n-white-a-24Purple
--n-purple-50--n-purple-100--n-purple-200--n-purple-300--n-purple-400--n-purple-500--n-purple-600--n-purple-700--n-purple-800--n-purple-900--n-purple-950Blue
--n-blue-50--n-blue-100--n-blue-200--n-blue-300--n-blue-400--n-blue-500--n-blue-600--n-blue-700--n-blue-800--n-blue-900--n-blue-950Green
--n-green-50--n-green-100--n-green-200--n-green-300--n-green-400--n-green-500--n-green-600--n-green-700--n-green-800--n-green-900--n-green-950Orange
--n-orange-50--n-orange-100--n-orange-200--n-orange-300--n-orange-400--n-orange-500--n-orange-600--n-orange-700--n-orange-800--n-orange-900--n-orange-950Red
--n-red-50--n-red-100--n-red-200--n-red-300--n-red-400--n-red-500--n-red-600--n-red-700--n-red-800--n-red-900--n-red-950Amber
--n-amber-50--n-amber-100--n-amber-200--n-amber-300--n-amber-400--n-amber-500--n-amber-600--n-amber-700--n-amber-800--n-amber-900--n-amber-950Cyan
--n-cyan-50--n-cyan-100--n-cyan-200--n-cyan-300--n-cyan-400--n-cyan-500--n-cyan-600--n-cyan-700--n-cyan-800--n-cyan-900--n-cyan-950Magenta
--n-magenta-50--n-magenta-100--n-magenta-200--n-magenta-300--n-magenta-400--n-magenta-500--n-magenta-600--n-magenta-700--n-magenta-800--n-magenta-900--n-magenta-950Semantic role families
Product UI consumes semantic roles. The inventory includes canvas, default, subtle, sunken, raised, overlay, control, selected, hover, and active surfaces; text and borders; complete action and focus roles; status and trend roles; and the general chart boundary.
The shared action family implements a primary default/hover/active sequence, secondary default/hover roles, a transparent tertiary role, and an on-primary foreground. The destructive Button sequence is a component contract backed by danger status and on-danger text roles; do not invent a parallel primitive or undocumented semantic role.
| Family | Canonical roles |
|---|---|
| Surface | --n-color-surface-canvas--n-color-surface-default--n-color-surface-control--n-color-surface-control-hover--n-color-surface-control-active--n-color-surface-subtle--n-color-surface-sunken--n-color-surface-raised--n-color-surface-overlay--n-color-surface-selected--n-color-surface-muted |
| Text | --n-color-text-primary--n-color-text-secondary--n-color-text-tertiary--n-color-text-disabled--n-color-text-inverse--n-color-text-on-danger |
| Border | --n-color-border-subtle--n-color-border-default--n-color-border-strong--n-color-border-interactive--n-color-border-focus--n-color-border-danger |
| Action | --n-color-action-primary--n-color-action-primary-hover--n-color-action-primary-active--n-color-action-on-primary--n-color-action-secondary--n-color-action-secondary-hover--n-color-action-tertiary |
| Focus | --n-color-focus-ring--n-color-focus-offset--n-color-focus-ring-soft |
| Status | --n-color-status-success--n-color-status-success-soft--n-color-status-success-strong--n-color-status-warning--n-color-status-warning-soft--n-color-status-warning-strong--n-color-status-danger--n-color-status-danger-soft--n-color-status-danger-strong--n-color-status-info--n-color-status-info-soft--n-color-status-info-strong--n-color-status-neutral--n-color-status-neutral-soft--n-color-status-neutral-strong--n-color-danger--n-color-success |
| Trend | --n-color-trend-positive--n-color-trend-negative--n-color-trend-pending--n-color-trend-locked--n-color-trend-verified--n-color-trend-unverified--n-color-trend-risk |
| Chart | --n-chart-primary--n-chart-comparison--n-chart-grid--n-chart-axis--n-chart-tooltip--n-chart-selection--n-chart-categorical-1--n-chart-categorical-2--n-chart-categorical-3--n-chart-categorical-4--n-chart-categorical-5 |
Representative mode mappings
| Role | System dark | light | dark |
|---|---|---|---|
--n-color-surface-control | --n-white-a-8 | --n-gray-a-6 | --n-white-a-8 |
--n-color-text-primary | --n-gray-50 | --n-gray-950 | --n-gray-50 |
--n-color-border-default | --n-white-a-16 | --n-gray-a-10 | --n-white-a-16 |
--n-color-status-success | --n-green-400 | --n-green-600 | --n-green-400 |
--n-chart-grid | --n-white-a-10 | --n-gray-a-10 | --n-white-a-10 |
Representative component aliases
| Component contract | Semantic source |
|---|---|
--n-button-background-primary | --n-color-action-primary |
--n-button-foreground-primary | --n-color-action-on-primary |
--n-button-background-destructive | --n-color-danger |
--n-button-foreground-destructive | --n-color-text-on-danger |
--n-input-background | --n-color-surface-control |
--n-input-border | transparent |
--n-badge-background-success | --n-color-status-success-soft |
--n-badge-foreground-success | --n-color-status-success |
Chart series, axes, grids, tooltips, cursors, and data-specific fallback policy belong to the Chart foundation issue. This page documents only the shared color-role boundary.
Pairing and interaction states
Evaluate the rendered pair and its context. Use translucent roles for adaptive control, hover, selected, border, and grouping layers on supported surfaces. Use opaque roles when the foreground needs isolation, the background is unknown, or compositing would make the result unpredictable.
| Composition | Pair | Review |
|---|---|---|
| Primary action | --n-color-action-primary + --n-color-action-on-primary | Review the foreground on default, hover, and active backgrounds; keep one clear local primary action. |
| Neutral control | --n-color-text-primary + --n-color-surface-control | Alpha-neutral control layers intentionally composite over supported surfaces. Test the pair on canvas, default, and grouped surfaces. |
| Status treatment | --n-color-status-*-soft + neutral text + icon or label | Use soft backgrounds for routine feedback. Keep visible wording or iconography so hue is not the only carrier of meaning. |
| Invalid control | --n-color-border-danger + associated error text | Combine the visual boundary with aria-invalid and a programmatically associated error message. |
| Focus | --n-color-focus-ring + --n-color-focus-offset | Check the complete indicator against adjacent colors, including selected and invalid states. |
| State | Review expectation |
|---|---|
| Default | Establish the stable foreground/background pair and control boundary. |
| Hover | Indicate pointer affordance without becoming the only discoverable state. |
| Active | Make the pressed state distinct from hover while preserving foreground contrast. |
| Focus-visible | Keep a visible ring and offset even when hover, selected, or invalid also applies. |
| Disabled | Preserve recognizability and semantics; reduced opacity is not a substitute for disabled behavior. |
| Selected | Pair the selected surface with text, indicator, icon, or state semantics. |
| Invalid | Pair danger styling with an accessible error relationship and actionable copy. |
Applied example
Real components resolve semantic roles through their component aliases. Visible labels keep action and status meaning available when color is unavailable or altered.
import { Badge } from "@nerio-ui/ui";<div className="status-row"> <Badge tone="primary-soft">Selected</Badge> <Badge tone="success">Published</Badge> <Badge tone="danger">Blocked</Badge></div>Use the Button and Badge component contracts for their full state, anatomy, and token guidance.
Accessibility
Contrast is a relationship between rendered foreground and background colors at a specific size and state. A token target cannot prove the final product composition. Review the full evidence boundary in the Accessibility foundation.
| Concern | Contract |
|---|---|
| Text contrast | Primary, secondary, inverse, and action text target 4.5:1. A 3:1 exception applies only when text qualifies as large under WCAG 2.2. |
| Non-text contrast | Meaningful control boundaries, graphics, and focus indicators target 3:1 where WCAG 2.2 applies. |
| Color-independent meaning | Status, selection, validation, trend, and chart meaning require text, position, shape, iconography, pattern, or programmatic state in addition to hue. |
| Forced colors | Core preserves representative boundaries, state, and focus with system colors. Product compositions must still be tested with forced colors active. |
| Increased contrast | Review real states with the platform preference enabled; the current contrast targets are tokens, not a data-contrast runtime axis. |
| Color vision | No categorical palette works for every user, display, background, or data task. Add redundant encoding and test the real visualization. |
--n-contrast-text-primary: 4.5--n-contrast-text-secondary: 4.5--n-contrast-text-tertiary: 3--n-contrast-text-inverse: 4.5--n-contrast-action: 4.5--n-contrast-status: 3--n-contrast-focus-ring: 3Custom themes
A custom theme supplies the same accent contract as every built-in theme. Coordinate selected surface, focus border and ring, the primary action sequence, on-primary foreground, and the primary chart role. Status colors remain semantic unless the product has separately validated replacements.
:root[data-theme="acme"] { --n-color-surface-selected: var(--n-gray-a-8); --n-color-border-focus: #0f766e; --n-color-action-primary: #0f766e; --n-color-action-primary-hover: #115e59; --n-color-action-primary-active: #134e4a; --n-color-action-on-primary: #ffffff; --n-color-focus-ring: #0f766e; --n-color-focus-ring-soft: rgb(15 118 110 / 0.24); --n-chart-primary: #0f766e; --n-chart-categorical-1: #0f766e;}:root[data-theme="acme"][data-mode="dark"] { --n-color-surface-selected: var(--n-white-a-10); --n-color-border-focus: #5eead4; --n-color-action-primary: #5eead4; --n-color-action-primary-hover: #2dd4bf; --n-color-action-primary-active: #14b8a6; --n-color-action-on-primary: #042f2e; --n-color-focus-ring: #5eead4; --n-color-focus-ring-soft: rgb(94 234 212 / 0.32); --n-chart-primary: #5eead4; --n-chart-categorical-1: #5eead4;}@media (prefers-color-scheme: dark) { :root[data-theme="acme"][data-mode="system"] { --n-color-surface-selected: var(--n-white-a-10); --n-color-border-focus: #5eead4; --n-color-action-primary: #5eead4; --n-color-action-primary-hover: #2dd4bf; --n-color-action-primary-active: #14b8a6; --n-color-action-on-primary: #042f2e; --n-color-focus-ring: #5eead4; --n-color-focus-ring-soft: rgb(94 234 212 / 0.32); --n-chart-primary: #5eead4; --n-chart-categorical-1: #5eead4; }}Built-in accent projection
| Theme | Light action | Dark action | System-dark action |
|---|---|---|---|
| Purple | --n-purple-600 | --n-purple-500 | --n-purple-500 |
| Blue | --n-blue-600 | --n-blue-500 | --n-blue-500 |
| Green | --n-green-600 | --n-green-600 | --n-green-600 |
| Orange | --n-orange-700 | --n-orange-700 | --n-orange-700 |
| Red | --n-red-600 | --n-red-500 | --n-red-500 |
| Neutral | --n-gray-950 | --n-gray-50 | --n-gray-50 |
Validation matrix
| Dimension | Coverage |
|---|---|
| Themes | Default purple plus the custom data-theme value. |
| Modes | Explicit light, explicit dark, system with OS light, and system with OS dark. |
| Density | Comfortable and compact; density must not change color primitives or semantic meaning. |
| States | Default, hover, active, focus-visible, disabled, selected, invalid, and loading where applicable. |
| Components | Buttons, links, fields, selection controls, overlays, status treatments, and representative chart surfaces. |
| Preferences | Forced colors, increased contrast, reduced motion where color changes accompany motion, and real display settings. |
| Content | Long labels, errors, real data, icons, meaningful graphics, and empty or dense states. |
Treat changed roles as a migration: document the new owner, compare before and after in real components, preserve aliases during compatibility windows, and rerun token, docs, browser, visual, and product accessibility evidence.
Do / do not
| Guidance | Recommendation |
|---|---|
| Do | Choose --n-color-surface-selected for selected product UI. |
| Do | Pair a danger border with an error message and invalid semantics. |
| Do not | Use --n-purple-600 directly because it resembles the desired accent. |
| Do not | Copy a light-mode action or chart value into dark mode without testing its pair and states. |
| Do not | Assume categorical hue alone makes a chart or status understandable. |
Review checklist
- Choose a semantic role by intent; never select a primitive because its swatch looks close.
- Review the foreground/background pair on every surface where it can appear.
- Exercise default, hover, active, focus-visible, disabled, selected, and invalid states together.
- Confirm status, validation, selection, trend, and chart meaning remains available without color.
- Test light, dark, system-light, and system-dark modes in the default and custom themes.
- Check focus visibility, text and non-text contrast, forced colors, and increased contrast.
- Validate alpha-neutral layers over every supported underlying surface; use opaque roles when isolation or predictable contrast is required.
- Record product-specific and visualization-specific evidence instead of treating Core token targets as a compliance guarantee.
Known boundary: Nerio provides shared roles, mappings, targets, forced-colors fallbacks, and representative evidence. The consumer owns brand values, custom-theme validation, product meaning, real content, and product-level compliance. Nerio does not currently expose a contrast runtime axis, theme editor, or complete visualization color policy.