Tailwind CSS Interview Questions

Commonly asked Tailwind CSS interview questions with clear, practical answers.

A curated set of Tailwind CSS interview questions — the kind that come up when a team wants to know if you understand the trade-offs, not just the class names.

Philosophy & trade-offs

Q: What's the core trade-off of utility-first CSS compared to writing traditional custom CSS classes? Utility-first keeps styling fully local to the element it affects — there's no separate stylesheet to cross-reference, and no risk of a shared class like .card silently affecting other unrelated elements when edited. The cost is denser markup, since styling information that used to live in CSS now lives inline in the class attribute. Most teams find the trade-off worth it because it removes an entire class of "which of the fifty places using this class did I just break" bugs.

Q: Doesn't inline utility classes just recreate the old problem of inline style attributes? Not quite — inline styles have no access to the cascade, media queries, or pseudo-classes (you can't write hover: or md: in a style attribute), and can't be constrained to a design system. Tailwind's utilities are still real CSS classes generated from a curated scale (specific spacing values, a fixed color palette), so the output stays visually consistent in a way ad hoc inline styles never would.

Build & configuration

Q: What does the content array in tailwind.config.js actually do, and what happens if a file is missing from it? Tailwind scans every file path/glob listed in content at build time to detect which utility classes are actually used, then generates CSS containing only those classes (everything else is discarded). If a file isn't listed, any class used only in that file won't be detected, and the corresponding CSS rule simply won't exist in the production bundle — the class will appear in the markup but have no effect, which is a very common "why isn't my style applying in production" bug.

Q: Why does building class names dynamically (e.g. `text-${color}-500`) often break in production? Tailwind's scanner looks for complete, literal class name strings in your source files — it doesn't execute JavaScript or resolve template interpolation. A class assembled from string fragments at runtime is never seen as a complete class name during the build scan, so it's never generated. The fix is to reference the complete class names literally somewhere in the source (even in a lookup object), so the scanner can find them intact.

Responsive & state variants

Q: Are Tailwind's responsive breakpoints mobile-first or desktop-first? Mobile-first. An unprefixed utility (text-base) applies at every screen size, and a breakpoint-prefixed utility (md:text-lg) only overrides it from that breakpoint's min-width upward — mirroring the same mobile-first min-width media query convention used in hand-written responsive CSS.

Q: How does group-hover: work, and what's required for it to have any effect? The ancestor element that should trigger the effect must carry the literal class group. Any descendant can then use group-hover:{utility} to apply a style only while that ancestor is hovered — useful for effects like a card's body text changing color when the whole card (not just the text) is hovered, without any JavaScript.

@apply

Q: When is @apply a good idea, and when does it undercut Tailwind's whole approach? It's useful for a small number of components repeated heavily across a codebase with an identical, long utility string each time (a primary button, a card shell) — folding that into one semantic class name reduces repetition. It becomes counterproductive if used pervasively, because it moves styling back out of the markup and into a separate CSS file, which is exactly the indirection utility-first CSS is designed to avoid.

Performance & design systems

Q: Does Tailwind still have a separate "purge" step, and how does the JIT engine actually decide what CSS to generate? No — that was Tailwind v1/v2 terminology for a post-processing pass over an already-fully-generated stylesheet. Since v3, the JIT engine scans every file listed in content for text that looks like a complete, literal utility class name, and generates CSS only for classes it actually finds — there's nothing to purge afterward because nothing unused is ever generated in the first place.

Q: If dynamically building a class name doesn't work reliably in production, what's the correct fix? Reference every possible complete class name literally somewhere in a scanned source file — typically via a lookup object that maps a dynamic value (like a status string) to a full, static class string, rather than interpolating a partial class name at runtime. This way, the scanner finds and generates every one of the possible classes at build time, and the runtime code just picks which already-generated class name to apply.

Q: What's the practical difference between a design token and an @apply component in a Tailwind-based design system? A design token (added via theme.extend) is a single named value — a color, spacing step, or radius — that should cover everything a design has genuinely standardized on, since adding more tokens rarely causes harm. An @apply component bundles a fixed combination of several utilities into one class name, and should be used sparingly, reserved for combinations that are copy-pasted verbatim across many places, since overusing it undermines the main benefit of seeing a component's styling directly in its markup.