Building a Tailwind CSS Class Name Generator: From String Concatenation to Visual Builder#

What’s the most painful part of writing Tailwind CSS? It’s not memorizing class names—it’s debugging a long string like flex justify-center items-center p-4 bg-blue-500 and not knowing which class is taking effect or which one is being overridden. Today let’s build a visual Tailwind class name generator that turns class assembly into building blocks.

Core Design: State-Driven, Not String Concatenation#

Many people’s first instinct is string concatenation, but a better approach is using a Set for state management:

const [selectedClasses, setSelectedClasses] = useState<Set<string>>(new Set())

const toggleClass = useCallback((cls: string) => {
  setSelectedClasses(prev => {
    const next = new Set(prev)
    if (next.has(cls)) {
      next.delete(cls)  // Remove if exists
    } else {
      next.add(cls)     // Add if not exists
    }
    return next
  })
}, [])

Why use a Set instead of an array?

  1. Automatic deduplication: Clicking the same class twice won’t add duplicates
  2. O(1) lookup: Checking if a class exists is faster
  3. Clear semantics: A Set represents a collection; an array represents a sequence

The final class string output:

const classString = Array.from(selectedClasses).join(' ')

Category Management: Organizing 700+ Class Names#

Tailwind CSS has over 700 class names—displaying them all at once would be overwhelming. Organizing by functionality is the only way:

type Category = 'layout' | 'spacing' | 'typography' | 'colors' | 'borders' | 'effects' | 'flexGrid'

const categoryTabs = [
  { key: 'layout', icon: <Layers />, label: 'Layout' },
  { key: 'spacing', icon: <Square />, label: 'Spacing' },
  { key: 'typography', icon: <Type />, label: 'Typography' },
  { key: 'colors', icon: <Palette />, label: 'Colors' },
  { key: 'borders', icon: <Square />, label: 'Borders' },
  { key: 'effects', icon: <Sparkles />, label: 'Effects' },
  { key: 'flexGrid', icon: <Grid3x3 />, label: 'Flex/Grid' },
]

Each category shows only relevant classes—users don’t need to see bg-red-500 next to text-xl.

The Spacing Direction Matrix#

Spacing classes are the most complex: padding has 7 directions (p/t/b/l/r/x/y), and so does margin. Each direction has 14 sizes (0-12 plus auto).

Displaying 7 × 14 × 2 = 196 buttons directly? A UX disaster.

The solution is direction + size separation:

const SPACING_DIRECTIONS = ['all', 't', 'b', 'l', 'r', 'x', 'y']
const SPACING_SIZES = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', 'auto']

// Render direction selector
{SPACING_DIRECTIONS.map(dir => (
  <span key={dir}>
    {dir === 'all' ? 'p-*' : `p${dir[0]}-*`}
  </span>
))}

// Render size selector
{SPACING_SIZES.map(size => (
  <button onClick={() => toggleClass(`p-${size}`)}>
    {size}
  </button>
))}

Combined with a padding/margin toggle, users can precisely target pt-4 or mx-auto.

Color Picker: From Strings to Visualization#

Tailwind’s color classes like bg-red-500 don’t convey the actual color visually. The solution is visualizing with color swatches:

const BASIC_COLORS = ['red', 'blue', 'green', 'yellow', 'purple', 'pink', 'cyan', 'gray']
const COLOR_SHADES = ['50', '100', '200', '300', '400', '500', '600', '700', '800', '900']

{BASIC_COLORS.map(color => (
  <div key={color}>
    <h5>{color}</h5>
    <div className="flex gap-1.5">
      {COLOR_SHADES.map(shade => {
        const cls = colorMode === 'bg' ? `bg-${color}-${shade}` : `text-${color}-${shade}`
        return (
          <button
            onClick={() => toggleClass(cls)}
            className="w-8 h-8 rounded border"
            style={{ backgroundColor: getColorFallback(color, shade) }}
            title={cls}
          />
        )
      })}
    </div>
  </div>
))}

The getColorFallback function predefines all 10 shades for each color, ensuring correct display even if Tailwind hasn’t loaded.

Live Preview: What You See Is What You Get#

The preview component directly applies selected classes:

<div className={`bg-bg-secondary border rounded-lg p-4 ${classString}`}>
  <span>Preview Element</span>
</div>

A subtle detail: the preview container itself has some classes (bg-bg-secondary, etc.), and user-selected classes are appended. If a user selects bg-red-500, it overrides the container’s default background—exactly how CSS cascade works visually.

Conflict Detection and Smart Hints#

Tailwind classes can conflict—for example, selecting both p-4 and p-8 means only the later-defined one takes effect. How to solve this?

Option 1: Mutex Groups#

const MUTEX_GROUPS = [
  ['p-0', 'p-1', 'p-2', 'p-3', 'p-4', ...],  // padding same direction mutex
  ['text-xs', 'text-sm', 'text-base', ...],  // font-size mutex
]

const toggleClass = (cls: string) => {
  setSelectedClasses(prev => {
    const next = new Set(prev)
    // Check if belongs to a mutex group
    for (const group of MUTEX_GROUPS) {
      if (group.includes(cls)) {
        // Remove other classes in same group
        group.forEach(c => next.delete(c))
      }
    }
    next.add(cls)
    return next
  })
}

Option 2: Warning Messages#

Don’t prevent selection, but warn about conflicts in the preview area:

const conflicts = findConflicts(selectedClasses)
{conflicts.length > 0 && (
  <div className="text-yellow-500 text-sm">
    ⚠️ Conflicting classes detected: {conflicts.join(', ')}
  </div>
)}

The current implementation uses option 2, because sometimes users intentionally override earlier classes with later ones.

One-Click Copy: Clipboard API#

const handleCopy = async () => {
  if (!classString) return
  await navigator.clipboard.writeText(classString)
  setCopied(true)
  setTimeout(() => setCopied(false), 2000)
}

Simple and direct—show a ✓ animation after successful copy.

Conclusion#

A seemingly simple Tailwind class generator involves:

  • Data structures: Set vs Array choice
  • Information architecture: Organizing 700+ class names
  • Interaction design: Direction+size separation, color visualization
  • CSS cascade: Conflict detection and handling
  • Engineering details: Clipboard API, state management

Final tool: Tailwind CSS Class Generator

Hope this helps you escape manual class writing and focus on layout itself.


Related tools: Flexbox Layout Generator | CSS Gradient Generator