Skip to main content

Overview

The DesignSystem object is the core interface for working with Tailwind’s utilities, variants, and theme. It provides methods for parsing candidates, generating CSS, and managing the design system configuration.
interface DesignSystem {
  theme: Theme
  utilities: Utilities
  variants: Variants
  invalidCandidates: Set<string>
  important: boolean
  
  // Parsing and compilation
  parseCandidate(candidate: string): Readonly<Candidate>[]
  parseVariant(variant: string): Readonly<Variant> | null
  compileAstNodes(candidate: Candidate, flags?: CompileAstFlags): AstNode[]
  
  // String conversion
  printCandidate(candidate: Candidate): string
  printVariant(variant: Variant): string
  
  // Ordering and sorting
  getClassOrder(classes: string[]): [string, bigint | null][]
  getVariantOrder(): Map<Variant, number>
  
  // IntelliSense support
  getClassList(): ClassEntry[]
  getVariants(): VariantEntry[]
  candidatesToCss(classes: string[]): (string | null)[]
  candidatesToAst(classes: string[]): AstNode[][]
  
  // Theme resolution
  resolveThemeValue(path: string, forceInline?: boolean): string | undefined
  trackUsedVariables(raw: string): void
  canonicalizeCandidates(candidates: string[], options?: CanonicalizeOptions): string[]
  
  // General purpose storage
  storage: Record<symbol, unknown>
}

Creating a Design System

Design systems are typically created internally during compilation, but you can create one manually:
import { buildDesignSystem } from 'tailwindcss/design-system'
import { Theme } from 'tailwindcss/theme'

const theme = new Theme()
theme.add('--color-primary', '#3b82f6', ThemeOptions.NONE)
theme.add('--color-secondary', '#8b5cf6', ThemeOptions.NONE)

const designSystem = buildDesignSystem(theme)

Properties

theme

theme
Theme
The theme instance containing all CSS custom properties and their values.
const primaryColor = designSystem.theme.resolve(null, ['--color-primary'])

utilities

utilities
Utilities
The utilities registry for registering and managing utility classes.
designSystem.utilities.static('custom-util', () => {
  return [decl('display', 'flex')]
})

variants

variants
Variants
The variants registry for managing variant modifiers like hover:, md:, etc.
designSystem.variants.static('custom', (r) => {
  r.nodes = [styleRule('.custom &', r.nodes)]
})

invalidCandidates

invalidCandidates
Set<string>
Set of candidate strings that have been determined to be invalid. Used for caching validation results.

important

important
boolean
Whether utility declarations should be marked as !important. Defaults to false.

storage

storage
Record<symbol, unknown>
General purpose storage for plugins and extensions. Each key must be a unique symbol to avoid collisions.

Parsing Methods

parseCandidate()

Parse a candidate string into structured candidate objects.
parseCandidate(candidate: string): Readonly<Candidate>[]
candidate
string
required
The candidate string to parse (e.g., 'hover:bg-blue-500', 'md:flex').
Returns: Array of parsed candidate objects. A single string can produce multiple candidates (e.g., 'text-red-500/50' creates candidates for both color and opacity).
const candidates = designSystem.parseCandidate('hover:bg-blue-500')

for (const candidate of candidates) {
  console.log({
    variants: candidate.variants,
    root: candidate.root,
    modifier: candidate.modifier
  })
}

parseVariant()

Parse a variant string into a variant object.
parseVariant(variant: string): Readonly<Variant> | null
variant
string
required
The variant string to parse (e.g., 'hover', 'md', 'dark').
Returns: Parsed variant object or null if the variant is invalid.
const variant = designSystem.parseVariant('hover')
if (variant) {
  console.log('Valid variant:', variant)
}

compileAstNodes()

Compile a parsed candidate into AST nodes.
compileAstNodes(
  candidate: Candidate,
  flags?: CompileAstFlags
): { node: AstNode; propertySort: number }[]
candidate
Candidate
required
The parsed candidate object to compile.
flags
CompileAstFlags
Compilation flags:
  • CompileAstFlags.None - No special flags
  • CompileAstFlags.RespectImportant - Apply !important if designSystem.important is true (default)
Returns: Array of AST nodes with their property sort order.
const candidates = designSystem.parseCandidate('flex')
const astNodes = designSystem.compileAstNodes(candidates[0])

for (const { node, propertySort } of astNodes) {
  console.log('Node:', node, 'Sort order:', propertySort)
}

String Conversion Methods

printCandidate()

Convert a parsed candidate back to its string representation.
printCandidate(candidate: Candidate): string
const candidates = designSystem.parseCandidate('hover:bg-blue-500')
const str = designSystem.printCandidate(candidates[0])
console.log(str) // 'hover:bg-blue-500'

printVariant()

Convert a parsed variant back to its string representation.
printVariant(variant: Variant): string
const variant = designSystem.parseVariant('hover')
if (variant) {
  const str = designSystem.printVariant(variant)
  console.log(str) // 'hover'
}

Ordering Methods

getClassOrder()

Get the sort order for an array of class names.
getClassOrder(classes: string[]): [string, bigint | null][]
classes
string[]
required
Array of class names to get sort order for.
Returns: Array of tuples containing the class name and its sort order (or null if invalid).
const order = designSystem.getClassOrder([
  'hover:bg-blue-500',
  'flex',
  'md:grid'
])

// Sort classes by their order
const sorted = order
  .sort((a, z) => {
    if (a[1] === null) return 1
    if (z[1] === null) return -1
    return a[1] < z[1] ? -1 : 1
  })
  .map(([name]) => name)

console.log(sorted)

getVariantOrder()

Get a map of variants to their sort order.
getVariantOrder(): Map<Variant, number>
Returns: Map where keys are variant objects and values are their numeric sort order.
const variantOrder = designSystem.getVariantOrder()

const hoverVariant = designSystem.parseVariant('hover')
if (hoverVariant) {
  const order = variantOrder.get(hoverVariant)
  console.log('Hover variant order:', order)
}

IntelliSense Methods

getClassList()

Get a list of all available utility classes for IntelliSense.
getClassList(): ClassEntry[]
Returns: Array of class entries containing metadata about each utility.
const classList = designSystem.getClassList()

for (const entry of classList) {
  console.log({
    name: entry.name,
    kind: entry.kind,
    // ... other metadata
  })
}

getVariants()

Get a list of all available variants for IntelliSense.
getVariants(): VariantEntry[]
Returns: Array of variant entries.
const variants = designSystem.getVariants()

for (const variant of variants) {
  console.log('Available variant:', variant)
}

candidatesToCss()

Convert an array of candidates to their CSS output.
candidatesToCss(classes: string[]): (string | null)[]
classes
string[]
required
Array of class names to convert to CSS.
Returns: Array of CSS strings (or null for invalid classes) corresponding to each input class.
const cssOutput = designSystem.candidatesToCss([
  'flex',
  'bg-blue-500',
  'invalid-class'
])

// cssOutput[0]: '.flex { display: flex; }'
// cssOutput[1]: '.bg-blue-500 { background-color: ... }'
// cssOutput[2]: null (invalid)

candidatesToAst()

Convert an array of candidates to AST nodes.
candidatesToAst(classes: string[]): AstNode[][]
classes
string[]
required
Array of class names to convert to AST.
Returns: Array of AST node arrays (empty array for invalid classes).
const astArrays = designSystem.candidatesToAst(['flex', 'grid'])

for (const nodes of astArrays) {
  for (const node of nodes) {
    console.log('AST Node:', node)
  }
}

Theme Methods

resolveThemeValue()

Resolve a theme path to its CSS value.
resolveThemeValue(path: string, forceInline?: boolean): string | undefined
path
string
required
Theme path to resolve (e.g., '--color-blue-500', '--spacing-4').Can include an opacity modifier using / syntax: '--color-blue-500 / 50%'
forceInline
boolean
If true, forces the value to be inlined rather than using a CSS variable reference. Defaults to true.
Returns: The resolved CSS value or undefined if the path doesn’t exist.
const color = designSystem.resolveThemeValue('--color-blue-500')
console.log(color) // '#3b82f6'

const spacing = designSystem.resolveThemeValue('--spacing-4')
console.log(spacing) // '1rem'

trackUsedVariables()

Track CSS variables used in arbitrary values to ensure they’re included in the output.
trackUsedVariables(raw: string): void
raw
string
required
Raw string that may contain CSS variable references.
// Track variables in arbitrary values
designSystem.trackUsedVariables('calc(var(--spacing-4) * 2)')
designSystem.trackUsedVariables('color-mix(in srgb, var(--color-primary), white)')

canonicalizeCandidates()

Canonicalize an array of candidates by parsing and re-printing them.
canonicalizeCandidates(
  candidates: string[],
  options?: CanonicalizeOptions
): string[]
candidates
string[]
required
Array of candidate strings to canonicalize.
options
CanonicalizeOptions
Options for canonicalization.
Returns: Array of canonicalized candidate strings.
const canonical = designSystem.canonicalizeCandidates([
  'hover:bg-blue-500',
  'bg-blue-500',
  'md:hover:bg-blue-500'
])

console.log(canonical) // Normalized, de-duplicated candidates

Example: Building a Custom Tool

import { buildDesignSystem } from 'tailwindcss/design-system'
import { Theme } from 'tailwindcss/theme'

function validateClassNames(classes: string[]): {
  valid: string[]
  invalid: string[]
} {
  const theme = new Theme()
  const designSystem = buildDesignSystem(theme)
  
  const valid: string[] = []
  const invalid: string[] = []
  
  for (const className of classes) {
    const candidates = designSystem.parseCandidate(className)
    
    if (candidates.length > 0) {
      const astNodes = designSystem.compileAstNodes(candidates[0])
      
      if (astNodes.length > 0) {
        valid.push(className)
      } else {
        invalid.push(className)
      }
    } else {
      invalid.push(className)
    }
  }
  
  return { valid, invalid }
}

Build docs developers (and LLMs) love