# No Dynamic Class Construction

**NEVER** · **ID:** `performance-dynamic-classes` · **Category:** performance
**Source:** [Tailwind](https://tailwindcss.com/docs)
**Interactive version:** https://ui-guides-agent-rules.netlify.app/principles/performance-dynamic-classes

> NEVER: Dynamically construct class names (`bg-${color}-500`); use object lookup with complete strings

Write complete class names for Tailwind to detect them

Tailwind's build process scans your source files for complete class name strings. It cannot execute JavaScript or interpolate template literals. Dynamically constructed classes like bg-${color}-500 will be purged from production builds.

## Bad — do not do this

`performance-dynamic-classes-bad`

```tsx
import { useState } from 'react';

export function DynamicClassesBad() {
  const [color, setColor] = useState('green');
  const colors = ['green', 'yellow', 'red'];

  // This pattern breaks in production!
  const dynamicClass = `bg-${color}-500`;

  return (
    <div className="w-full max-w-sm space-y-4">
      <div className="bg-card border border-border rounded-lg p-4">
        <h4 className="font-medium mb-3">Status Badge</h4>
        <div className="flex gap-2 mb-4">
          {colors.map((c) => (
            <button
              key={c}
              onClick={() => setColor(c)}
              className={`px-3 py-1 rounded text-sm capitalize ${
                color === c ? 'ring-2 ring-primary' : ''
              }`}
            >
              {c}
            </button>
          ))}
        </div>
        <div className="px-4 py-2 rounded bg-muted text-muted-foreground">
          Would be: {dynamicClass}
        </div>
      </div>
      <div className="bg-muted rounded p-3 font-mono text-xs">
        <pre className="text-error">{`// Tailwind can't detect this!
const dynamicClass = \`bg-\${color}-500\`;`}</pre>
      </div>
      <p className="text-xs text-error">
        Dynamic class construction is purged in production builds
      </p>
    </div>
  );
}
```

## Good — do this

`performance-dynamic-classes-good`

```tsx
import { useState } from 'react';

const statusClasses = {
  success: 'bg-green-500 text-white',
  warning: 'bg-yellow-500 text-black',
  error: 'bg-red-500 text-white',
} as const;

type Status = keyof typeof statusClasses;

export function DynamicClassesGood() {
  const [status, setStatus] = useState<Status>('success');

  return (
    <div className="w-full max-w-sm space-y-4">
      <div className="bg-card border border-border rounded-lg p-4">
        <h4 className="font-medium mb-3">Status Badge</h4>
        <div className="flex gap-2 mb-4">
          {(Object.keys(statusClasses) as Status[]).map((s) => (
            <button
              key={s}
              onClick={() => setStatus(s)}
              className={`px-3 py-1 rounded text-sm capitalize ${
                status === s ? 'ring-2 ring-primary' : ''
              }`}
            >
              {s}
            </button>
          ))}
        </div>
        <div className={`px-4 py-2 rounded ${statusClasses[status]}`}>
          Current: {status}
        </div>
      </div>
      <div className="bg-muted rounded p-3 font-mono text-xs">
        <pre>{`const statusClasses = {
  success: 'bg-green-500',
  warning: 'bg-yellow-500',
  error: 'bg-red-500',
};`}</pre>
      </div>
      <p className="text-xs text-success">
        Complete class strings are detectable by Tailwind's purge
      </p>
    </div>
  );
}
```

## References

- [Dynamic Class Names](https://tailwindcss.com/docs/detecting-classes-in-source-files#dynamic-class-names)
- [Safelist Configuration](https://tailwindcss.com/docs/detecting-classes-in-source-files#safelisting-classes)
