Skip to content

A strong Material Design theme is not “pick a primary & accent and ship.” It is a structured translation of brand identity → seed colors → tonal palettes → semantic roles → cross-platform design tokens → implementable, testable theme surfaces with guaranteed contrast.

1. Overview

StepInputOutputTooling / ArtifactRisk If Skipped
Brand AuditLogo, marketing site, typography moodCanonical brand primitivesBrand spec (Figma/Markdown)Incoherent visual identity
Seed Color SelectionPrimary + supporting neutrals1–3 seed hex valuesPalette draftWeak tonal harmony
Tonal Palette GenerationSeed(s) + MD algorithmTonal scales (0–100)JSON palette exportInconsistent light/dark states
Role MappingTonals + product contextSemantic roles (primary, surface, error, etc.)Role matrixArbitrary color reuse
Token DefinitionRoles + platformsToken set (global/alias/component)tokens.jsonHard-to-scale overrides
Contrast ValidationTokens vs backgroundsWCAG AA/AAA resultsContrast reportAccessibility failures
ImplementationTokens + framework (e.g. Vuetify)Theme configuration + CSS varstheme.ts / cssDrift between design & code
Regression GuardSnapshot & lintingAutomated checksTests (visual + contrast)Silent regressions

2. Brand Inputs (Ground Truth)

Gather:

  • Brand narrative keywords (e.g. "trust", "momentum", "clarity").
  • Existing marketing hex values (primary logo color, accent, neutral backgrounds).
  • Usage frequencies (primary 60%, secondary 30%, accent 10% as a starting heuristic).
  • Accessibility promises (e.g. minimum contrast AA for text, AAA for critical alerts).

Store this in a lightweight brand-spec.md so engineering can diff reasoning over time.

3. Seed & Tonal Palettes

Material Design 3 uses a seed color to derive a tonal palette (0 → 100). If you have multiple brand hues (e.g. Indigo + Teal) you may create separate tonal tracks or restrict one as accent.

Essential tonal stops commonly used:

ToneUsage Hint
0–10Highest contrast content on light surfaces; dark mode surfaces
20–30Elevated surfaces / outlines in dark mode
40–50Mid emphasis text on dark, accents on light
60Primary default in many light themes
70–80Secondary containers / hovered states
90–95Surface variants / subtle backgrounds
98–100Pure surfaces (light) or high-elevation overlays

4. Mapping Tonals to Semantic Roles

Define a matrix mapping each role to a tonal value + reasoning.

RoleLight (Tone)Dark (Tone)Rationale
primary6070Sufficient contrast vs white & dark surfaces
on-primary10010Legibility inside primary elements
primary-container9030Container differentiation
on-primary-container1090Max contrast in container
error(seed: red tone 60)60Conventional alert visibility
on-error10010Text inside error surfaces

Use product screenshots to validate the matrix—visual judgment complements numeric contrast.

5. Designing Token Layers

Three-layer token strategy keeps scale manageable:

  • Global Tokens (raw, brand-invariant semantic: color.primary, color.surface, radius.sm).
  • Alias / Context Tokens (role-specific or stateful: button.primary.background, card.outlined.border).
  • Component Tokens (lowest level: v-btn-padding-x, nav-drawer-elevation).

Example tokens.json fragment:

json
{
  "color": {
    "primary": "{palette.indigo.60}",
    "on-primary": "{palette.indigo.99}",
 
    "surface": "{palette.neutral.98}",
    "surface-variant": "{palette.neutral.90}",
    "outline": "{palette.neutral.50}"
  },
  "radius": {
    "sm": "4px",
    "md": "8px"
  },
  "button": {
    "primary": {
      "bg": "{color.primary}",
      "fg": "{color.on-primary}",
      "radius": "{radius.md}"
    }
  }
}

6. Contrast & Accessibility

Run automated contrast checks across each foreground/background pair. Required minimums (WCAG 2.1):

Text TypeMin Contrast (AA)Target (Stretch)
Focus ring vs adjacent3:14.5:1

If a chosen tone pair fails, adjust the role tone rather than injecting ad-hoc overrides—maintain matrix integrity.

7. Tooling Workflow

  1. Start with seed color(s) in a palette generator (Material Theme Builder or CLI).
  2. Export tonal palette JSON.
  3. Feed into a token build step (Style Dictionary / custom script) that resolves {palette.*} references.
  4. Emit platform artifacts: tokens.css, tokens.d.ts, tokens.android.xml, tokens.ios.json (as needed).
  5. Run contrast test script (e.g. Node + color-contrast package) failing CI on regressions.
  6. Publish versioned token package (npm) consumed by app(s).

8. Example Implementation (Vuetify 3 Theme)

ts
// theme.ts
import { createVuetify } from 'vuetify';
import 'vuetify/styles';

const brandLight = {
  dark: false,
  colors: {
    primary: '#4F46E5',
    'on-primary': '#FFFFFF',
    surface: '#FAFAFE',
 
    'surface-variant': '#ECECF4',
    outline: '#9393A3',
    error: '#DC2626',
    'on-error': '#FFFFFF'
  }
};

const brandDark = {
  dark: true,
  colors: {
    primary: '#A5B4FF',
    'on-primary': '#1E1B2E',
    surface: '#121214',
 
    'surface-variant': '#2A2A32',
    outline: '#5A5A66',
    error: '#F87171',
    'on-error': '#1E1E1E'
  }
};

export const vuetify = createVuetify({
  theme: {
    defaultTheme: 'brandLight',
    themes: { brandLight, brandDark }
  }
});

9. Evolution & Governance

  • Maintain a CHANGELOG for tokens; bump minor on additive, major on breaking semantic shifts.
  • Sunset tokens via deprecation comments & CI warnings before removal.
  • Quarterly contrast re-validation (designs & real usage screens can drift).
  • Use design linting (Figma plugins) to catch off-token color usage.

10. Migration Strategy (If Coming From Ad-Hoc Colors)

PhaseActionSuccess Criteria
AuditExtract all hard-coded # colors & frequencyColor inventory produced
ClusterGroup by visual intent (primary, info, border, subtle-bg)>= 90% mappings decided
SeedSelect canonical seed(s) & neutralsSigned off by design & brand
GenerateProduce tonal palettesJSON artifacts stored in repo
MapBuild role matrix (light/dark)Matrix passes initial contrast
TokenizeImplement tokens + build pipelineApp builds with tokens only
EnforceAdd lint/CI checks (no raw hex)New PRs blocked on violations
IterateTweak tones for contrast / emotionNo manual inline overrides

11. Quality Checklist

text
[ ] Brand spec documented & versioned
[ ] Seed color(s) agreed & justified
[ ] Tonal palette JSON exported (light & dark)
[ ] Role matrix (light/dark) reviewed with design + engineering
[ ] All semantic tokens defined (global + alias + component)
[ ] Contrast report passes AA (body) & AAA (critical text)
[ ] Token build pipeline outputs multi-platform artifacts
[ ] Theme implemented in framework (Vuetify / etc.)
[ ] CI checks for raw hex & contrast regressions
[ ] Governance process (changelog + deprecation) in place

12. Summary

Translating brand identity into a robust Material Design theme is an information architecture exercise for color. When you formalize inputs → tonal math → semantic roles → tokens → implementation, you gain consistency, accessibility, and agility. Invest early; it pays down design debt continuously.

Random thoughts on Tech