Foundation
Themes
Nerio separates brand theme, color mode, and density so one component API can work across many products without creating combined theme names.
Runtime axes
| Axis | Attribute | Values |
|---|---|---|
| Theme | data-theme | purple, blue, green, orange, red, neutral, or custom |
| Mode | data-mode | system, light, dark |
| Density | data-density | comfortable, compact |
Preset themes
| Theme | Attribute value | Light primary mapping |
|---|---|---|
| Purple | data-theme="purple" | --n-purple-600 |
| Blue | data-theme="blue" | --n-blue-600 |
| Green | data-theme="green" | --n-green-600 |
| Orange | data-theme="orange" | --n-orange-700 |
| Red | data-theme="red" | --n-red-600 |
| Neutral | data-theme="neutral" | --n-gray-950 |
Mode behavior
Light mode uses opaque white foundations with cool dark alpha neutrals for adaptive controls, grouping, borders, and interaction states. Dark mode maps the canvas, default, sunken, raised, and overlay surface roles to --n-gray-1000, then uses white alpha neutrals for controls, borders, selected layers, and other adaptive surfaces.
Text, focus, actions, statuses, and charts remap through their own semantic roles. Purple and neutral use lighter primary actions in dark and system-dark modes where the light-mode accent would lose contrast. Product code consumes semantic roles and does not depend on a resolved gray or alpha primitive.
The appearance control exposes System, Light, and Dark explicitly. System follows live OS preference changes, and theme, mode, and density selections are restored independently before hydration.
| Role | Light | Dark | System dark |
|---|---|---|---|
--n-color-surface-canvas | --n-gray-0 | --n-gray-1000 | --n-gray-1000 |
--n-color-surface-default | --n-gray-0 | --n-gray-1000 | --n-gray-1000 |
--n-color-surface-sunken | --n-gray-a-6 | --n-gray-1000 | --n-gray-1000 |
--n-color-surface-raised | --n-gray-0 | --n-gray-1000 | --n-gray-1000 |
--n-color-surface-overlay | --n-gray-0 | --n-gray-1000 | --n-gray-1000 |
Density
| Value | Use | Source-backed aliases |
|---|---|---|
comfortable | Default spacing for mixed product and documentation surfaces. | --n-density-space-md → --n-space-3--n-density-space-lg → --n-space-4--n-density-space-xl → --n-space-5 |
compact | Remaps semantic density aliases and component tokens for dense operational interfaces without changing primitive spacing values. | --n-density-space-md → --n-space-2-5--n-density-space-lg → 0.875rem--n-density-space-xl → --n-space-4 |
Custom themes
<html data-theme="purple" data-mode="system" data-density="comfortable">: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;}: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.3); --n-chart-primary: #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.3); --n-chart-primary: #5eead4; }}- Override semantic roles and stable component contracts, not primitive palettes.
- Do not create combined names such as purple-light or neutral-dark.
- Do not use vertical-specific preset names such as fintech-blue.
- Keep brand color as an accent for primary action, selection, focus, and charts.
- Provide dark-mode accent overrides when the light accent loses contrast.
- Test real component states and content rather than approving isolated swatches.
Theme validation
| Check | Expected result |
|---|---|
| Text contrast | Normal text reaches 4.5:1; the 3:1 exception is reserved for text that qualifies as large under WCAG 2.2. |
| Non-text contrast | Control boundaries, meaningful graphics, and focus indicators reach 3:1 where WCAG 2.2 applies. |
| State communication | Selection, status, validation, and urgency remain understandable without relying on color alone. |
| Mode coverage | Review explicit light and dark modes, then test both OS light and OS dark preferences while data-mode="system". |
| System preferences | Verify forced colors, reduced motion, text resize, and zoom/reflow without losing state or operation. |
Do / do not
Review contrast, focus, non-color communication, and manual evidence responsibilities in the Accessibility foundation before approving a custom theme. The Color foundation defines the source-backed role inventory, required accent mappings, and complete foreground/background validation matrix. The Spacing & layout foundation defines how comfortable and compact density remap semantic and component geometry without changing the primitive scale.
| Guidance | Recommendation |
|---|---|
| Do | Use generic brand theme names and let mode handle light or dark rendering. |
| Do | Validate action, focus, status, chart, and selected-state pairs in every supported mode. |
| Do not | Fork component source to hard-code a product color into a button or field. |
| Do not | communicate status, selection, or validation through hue alone. |