Skip to content

Brand Validate

nib brand validate runs 11 automated checks against your token files and component contracts — catching broken references, naming violations, WCAG failures, and structural issues before they reach production.


Before and After

Before validate: You rename a color token in your brand guidelines, run nib brand build, and ship. Two weeks later a PR breaks because a component contract references the old token name — caught in code review by chance.

After validate: nib brand validate catches the broken reference immediately. It also flags the camelCase segment in the token path you added last sprint, and warns that your button component contract is missing a disabled state token.


Quick Start

sh
# Run all 11 checks
nib brand validate

# Fail only on schema errors (skip a11y and naming)
nib brand validate --fail-on schema

# Validate a specific tokens directory
nib brand validate --tokens-dir ./custom/tokens

What It Checks

CheckIDWhat it catches
DTCG schemaV-01Tokens missing $type or $value
Required categoriesV-02Missing color, typography, spacing, borderRadius, elevation
Semantic tokensV-03Missing required aliases (color.interactive.default, color.background.*, etc.)
Naming conventionsV-04camelCase, spaces, or underscores in token path segments
Typography scaleV-05Missing required font-size steps (xs, sm, base, lg, xl, 2xl)
Contrast (a11y)V-06Text/background pairs that fail WCAG AA (4.5:1 minimum)
Composite typesV-07Shadow, typography, or transition tokens with wrong value shapes
Deprecated tokensV-08Tokens marked $extensions.nib.deprecated still referenced
Component contractsV-09Contracts referencing token paths that don't exist
Extensions schemaV-10$extensions.nib fields with unknown or invalid keys
Circular referencesV-11{token.path} references that form cycles

Reading the Output

✓ nib brand validate

  Checks run: 11
  Tokens:     247

  PASS  V-01  DTCG schema compliance
  PASS  V-02  Required categories present
  FAIL  V-03  Required semantic tokens
  PASS  V-04  Naming conventions
  WARN  V-05  Typography scale completeness
  FAIL  V-06  Contrast (WCAG AA)
  PASS  V-07  Composite type shapes
  PASS  V-08  Deprecated token references
  FAIL  V-09  Component contract token references
  PASS  V-10  Extensions schema
  PASS  V-11  Circular references

  Issues (4 errors, 1 warning):

  ERROR  V-03  color.text.default — required semantic token missing
  ERROR  V-06  color.text.muted on color.background.primary — contrast 3.2:1 (need ≥ 4.5:1)
  ERROR  V-09  Button.contract.json → tokens.root.default.background: "color.interactive.base" — not found
  ERROR  V-09  Badge.contract.json → tokens.root.default.text: "color.text.onBrand" — not found
  WARN   V-05  font-size.2xl missing (expected xs, sm, base, lg, xl, 2xl)

Exit code is 1 when any errors are present (warnings don't fail the process).


Fixing Common Issues

V-03: Missing semantic tokens

nib looks for tokens at specific paths. If you've renamed tokens in your guidelines and regenerated, the semantic layer may not have re-mapped correctly.

sh
# Regenerate from scratch
nib brand build

# Or check your semantic token file directly
cat docs/design/system/tokens/color-semantic.tokens.json | grep "interactive"

V-04: Naming conventions

Token path segments must be lowercase with hyphens only. No camelCase, no underscores, no spaces.

json
// ✗ wrong
{ "brandColor": { "$type": "color", "$value": "#0066ff" } }
{ "brand_color": { "$type": "color", "$value": "#0066ff" } }

// ✓ correct
{ "brand-color": { "$type": "color", "$value": "#0066ff" } }

V-06: Contrast failures

nib auto-fixes most contrast issues during nib brand build by adjusting the semantic layer. If you're getting V-06 after a build, you likely have a custom token with a manually specified value.

Check the exact pair in the error message and adjust the lighter or darker token until the ratio reaches 4.5:1.

Online contrast checker

Use Polypane contrast checker to find a passing value quickly.

V-09: Component contract references

A component contract references a token that doesn't exist in your token files. This happens when:

  1. A token was renamed during a brand refresh
  2. A contract was written before the token existed
sh
# List all available token paths
nib brand build --dry-run

# Regenerate the contract from scratch (if it was auto-generated by nib)
nib component init Button --overwrite

CI Integration

Add validate to your CI pipeline to catch regressions before merge:

yaml
# .github/workflows/design-system.yml
- name: Validate brand tokens
  run: |
    nib brand build
    nib brand validate

Fail-on levels

sh
nib brand validate --fail-on schema    # only V-01 (strictest gating)
nib brand validate --fail-on required  # V-01, V-02, V-03
nib brand validate --fail-on a11y      # adds V-06 contrast checks
nib brand validate --fail-on all       # all 11 checks (default)

Pre-commit Hook

Catch issues locally before they hit CI:

sh
# .husky/pre-commit (or equivalent)
nib brand validate --fail-on schema

Configuration

brand.config.json controls which checks run by default:

json
{
  "validate": {
    "failOn": "all",
    "skipChecks": ["V-11"],
    "contrastLevel": "AA"
  }
}
FieldDefaultOptions
failOn"all""schema", "required", "a11y", "components", "all"
skipChecks[]Any check ID (V-01 through V-11)
contrastLevel"AA""AA" (4.5:1), "AAA" (7:1)

Released under the AGPL-3.0 License.