Customization and debugging
Know when to write CSS
Decide when utilities keep a component clear and when a semantic class, custom property, or ordinary stylesheet is easier to maintain.
8 minute lesson
Utilities are not a rule that forbids CSS.
Keep utilities inline when the element owns a small, explicit set of responsive and state decisions. Extract a framework component when markup and behavior repeat; the component can still contain utilities and expose semantic props such as tone="danger".
Write ordinary CSS when CSS itself is the clearer abstraction:
- rich prose descendants generated by Markdown or a CMS
- third-party markup you cannot add classes to
- complex selectors or pseudo-elements
- keyframes and coordinated animation
- a semantic component style shared outside the template system
- browser behavior that has no useful built-in utility
For example:
.article-content h2 {
margin-block-start: 2.5rem;
font-size: var(--text-2xl);
}
This can be easier to audit than repeating descendant arbitrary variants on every article container.
Use @utility for a small reusable CSS behavior that should support Tailwind variants. Use @theme for values that should expand Tailwind’s token-driven API. Use ordinary custom properties when you need runtime values without generating utilities.
Avoid extracting a class merely because a class list is long. A card with many unique visual decisions may be clearer in one component file than split between markup and a one-off .card selector. Extract when there is stable reuse or a semantic boundary.
Also avoid copying the same long class string. In React, Vue, Astro, or templates, a reusable component is often a better abstraction than a CSS class because it preserves markup, accessibility, and behavior together.
Use the simplest layer that makes the design clear. Tailwind and ordinary CSS work together.
Your action is to classify five styles in your project as inline utility, component, custom utility, theme token, or ordinary CSS. Write one sentence for each boundary and remove one abstraction that adds indirection without reuse.
Lesson completed