Skip to content

NubiscoUI ships with a complete SCSS token system. Every visual decision, color, spacing, type scale, z-index, field heights, is a CSS custom property derived from typed SCSS maps. You do not need to write SCSS to use it.

How it works

The pipeline has three stages:

  1. SCSS maps (src/styles/variables/) define every raw value, color names, type scales, spacing ratios, z-index stacks.
  2. _theme.scss iterates those maps and emits a CSS custom property for each entry onto :root.
  3. Your browser resolves the properties at runtime. No rebuild needed to change a value.

Overriding tokens as a consumer

You don't need to touch SCSS. Override CSS custom properties in your own stylesheet:

css
/* main.css or App.vue <style> */
:root {
  /* Rebrand primary color */
  --nb-c-primary: #1a56db;
  --nb-c-primary-hover: #1e429f;
  --nb-c-primary-active: #1c3fa0;

  /* Change the base spacing unit (all gaps, field heights scale with it) */
  --nb-base-unit: 10px; /* default is 8px */
}

That is all. Every component that references --nb-c-primary or --nb-base-unit inherits the change automatically.

Semantic vs. palette tokens

NubiscoUI separates two layers:

Palette tokens: raw color values tied to a named color. Rarely override these directly.

css
--nb-c-grape-hyacinth-500: #5c35c4 /* auto-generated tint */
  --nb-c-grape-hyacinth-600: #4d2aa8 /* darker tint */;

Semantic tokens: intent-level tokens that components consume. Override these to rebrand.

css
--nb-c-primary: var(--nb-c-grape-hyacinth-500) /* references palette */
  --nb-c-primary-hover: var(--nb-c-grape-hyacinth-600);

Override semantic tokens when you want to change the brand. Override palette tokens when you want to add new colors to the system.

Customising in SCSS

If you import @nubisco/ui/styles directly, you can also override the SCSS maps before the library is compiled:

scss
// Override the $colors map to inject your brand palette
@use '@nubisco/ui/variables' with (
  $colors: (
    grape-hyacinth: #5c35c4,
    // keep the base
    your-brand: #1a56db,
    // add yours
  )
);

This gives you the full shade ramp (--nb-c-your-brand-100 through --nb-c-your-brand-900) plus a11y contrast variants: generated automatically from a single hex value.

Color system

Colors are defined in src/styles/variables/_colors.scss as a $colors map. Each entry is a name–hex pair. The system generates 17 tints per color (100–900) plus an accessible contrast variant (-a11y) for each tint.

Adding a color

scss
// src/styles/variables/_colors.scss
$colors: (
  grape-hyacinth: #5c35c4,
  plain-white: #ffffff,
  plain-black: #000000,
  // Add your brand color:
  ocean-drive: #0ea5e9,
);

This automatically generates:

css
--nb-c-ocean-drive-100: /* lightest tint */ --nb-c-ocean-drive-200...
  --nb-c-ocean-drive-500: #0ea5e9 /* original */...
  --nb-c-ocean-drive-900: /* darkest tint */
  /* + a11y variants: auto-computed contrast color (black or white) */
  --nb-c-ocean-drive-500-a11y: #ffffff;

Naming colors

Use the color naming tool below to generate a descriptive name for any hex value. Color names in NubiscoUI follow a "what it looks like" convention. Not "what it is used for" (that's what semantic tokens are for).

100
150
200
250
300
350
400
450
500
550
600
650
700
750
800
850
900
#214DA6Click to change color

Built-in palette

The default palette includes:

NameValueUse
grape-hyacinth#5c35c4Primary brand color
emerald-reflection#4acf7bSuccess states
the-blues-brothers#214da6Info states
phoenix-flames#f59e0bWarning states
chicken-comb#dc2626Danger/error states
nouveau-gray#6b7280Neutral UI chrome
french-gray#a7a7a7Borders, field backgrounds
plain-white#ffffffSurfaces, backgrounds
plain-black#000000Text, contrast surfaces

Wiring a color to a semantic role

After adding a palette color, point a semantic token at it:

css
:root {
  --nb-c-primary: var(--nb-c-ocean-drive-500);
  --nb-c-primary-hover: var(--nb-c-ocean-drive-600);
  --nb-c-primary-active: var(--nb-c-ocean-drive-700);
  --nb-c-primary-a11y: var(--nb-c-ocean-drive-500-a11y);
}

Typography system

NubiscoUI ships with two typefaces via the fonts Vite plugin, and a SCSS-driven type scale that generates utility classes and CSS custom properties.

Typefaces

Plus Jakarta Sans (--nb-font-family-sans), the primary typeface for all UI text. Used for labels, body copy, headings, and display type.

Fira Code (--nb-font-family-mono), monospace, used exclusively for code, JSON viewers, inline code, and keyboard shortcuts. Ligatures enabled by default.

Both are bundled in the library and served via the fonts plugin. No CDN dependency.

Type sets

Components always use named type sets, never raw font sizes. A type set bundles size, weight, line-height, letter-spacing, and font-family into a single named role.

Apply a type set in one utility class:

html
<p class="type-body-md">Readable paragraph text</p>
<span class="type-label-md">Form label</span>
<h2 class="type-heading-03">Section title</h2>
<code class="type-code-md">const x = 1</code>

Or via CSS custom properties in your own component:

scss
.my-title {
  font-size: var(--nb-type-heading-03-size);
  font-weight: var(--nb-type-heading-03-weight);
  line-height: var(--nb-type-heading-03-line-height);
  letter-spacing: var(--nb-type-heading-03-letter-spacing);
}

Adding a type set

Edit $typeSets in src/styles/variables/_type.scss:

scss
$typeSets: (
  // ...existing sets...
  caption: (
      size: 11,
      weight: regular,
      line-height: 1.4,
      letter-spacing: 0.01em,
    )
) !default;

This automatically generates --nb-type-caption-* CSS variables and a .type-caption utility class.

Full type set reference

See the Typography principles page for the complete type scale, all named sets, and usage guidelines.

CSS custom property reference

All tokens are emitted on :root. Override any of these in your own stylesheet to customise the system.

Base unit

TokenDefaultDescription
--nb-base-unit8pxThe geometric base for all spacing. All gaps, field heights, and padding are multiples of this value.

Semantic color tokens

These are the tokens you override to rebrand the library. Each semantic token has a base, hover, and active state, plus an -a11y variant for text rendered on that color.

TokenDefaultDescription
--nb-c-primarygrape-hyacinth-500Primary brand color
--nb-c-primary-hovergrape-hyacinth-600Hover state
--nb-c-primary-activegrape-hyacinth-700Active/pressed state
--nb-c-secondaryplain-black-700Secondary actions
--nb-c-successemerald-reflection-600Success / confirm
--nb-c-infothe-blues-brothers-500Informational
--nb-c-warningphoenix-flames-500Warning / caution
--nb-c-dangerchicken-comb-500Error / destructive

Each token above also has -a11y (auto-computed contrast text color), -hover, -hover-a11y, -active, -active-a11y variants.

Surface & text

TokenDescription
--nb-c-surfaceCard and panel background (white in light mode)
--nb-c-contrastMaximum contrast on surface (near-black in light)
--nb-c-documentPage/document background
--nb-c-whiteAbsolute white, not theme-aware
--nb-c-blackAbsolute black, not theme-aware
--nb-c-textPrimary body text
--nb-c-text-mutedSupporting text, captions, secondary labels
--nb-c-text-subtlePlaceholder text, disabled labels
--nb-c-bgPage background tier
--nb-c-bg-softElevated/inset background tier

Form field tokens

TokenDefaultDescription
--nb-c-field-bgfrench-gray-100Input background
--nb-c-field-borderfrench-gray-500Input border
--nb-field-height-sm4 × base-unit (32px)Small field height
--nb-field-height-md5 × base-unit (40px)Medium field height
--nb-field-height-lg6 × base-unit (48px)Large field height
--nb-field-padding-h2 × base-unit (16px)Horizontal field padding
--nb-field-font-size--nb-font-size-14Font size for all inputs
--nb-field-disabled-opacity0.45Opacity for disabled fields

Grid

TokenDefaultDescription
--nb-grid-max-width1440pxMaximum content width
--nb-grid-columns16Number of grid columns
--nb-grid-gutter16pxGrid gutter size

Gap scale

TokenValueDescription
--nb-gap-xxs2px¼ base unit
--nb-gap-xs4px½ base unit
--nb-gap-sm8px1× base unit
--nb-gap-md16px2× base unit
--nb-gap-lg24px3× base unit
--nb-gap-xl32px4× base unit
--nb-gap-xxl48px6× base unit

Z-index stack

TokenDescription
--nb-zindex-rootBase layer (0)
--nb-zindex-tableheaderSticky table headers
--nb-zindex-selectSelect dropdowns
--nb-zindex-dropdownDropdown menus
--nb-zindex-pageheaderSticky page headers
--nb-zindex-titlebarApp title bar
--nb-zindex-navigationTop navigation
--nb-zindex-backdropModal backdrop
--nb-zindex-modalModal dialogs
--nb-zindex-toastToast notifications
--nb-zindex-tooltipTooltips (highest)

See Z-Index principles for the full rationale and values.