DRY in the Age of AI and Tailwind CSS: A Modern Guide
The DRY (Don't Repeat Yourself) principle has been a cornerstone of software engineering for decades. However, the rise of Tailwind CSS - which encourages "utility-first" styles, and AI-powered coding assistants, which make copy-pasting code effortless, has sparked a debate: Is DRY dead, or has it just evolved?
When you’re using Tailwind "all over," the line between "efficiently rapid" and "unmaintainable mess" is thin. Here is how to navigate the modern styling landscape.
The Modern Conflict: Utility vs. Abstraction
Traditional CSS encouraged early abstraction (creating a class like .btn before you even knew if you'd need it twice). Tailwind flipped this, favoring composition over abstraction.
AI complicates this further. If an LLM can generate 50 lines of Tailwind classes in seconds, the "cost" of repetition feels lower. But the maintenance cost remains high. If your brand's "primary blue" changes, updating 40 AI-generated components is a nightmare.
The "Guru" Paradox: Why Your Head is Spinning
If during your career you learned SASS, LESS, or vanilla CSS3, the current trend feels like a betrayal. Remember BEM, OOCSS and SMACSS and other CSS architectures?
For years, CSS gurus preached:
Separation of Concerns: Keep your HTML clean; put styles in a stylesheet.
Semantic Naming: Use classes like
.card-profile-wrapperinstead of visual ones.Never Repeat Styles: Use mixins and variables to ensure a change in one place updates everywhere.
Now, Tailwind puts those styles directly back into the HTML. It feels messy because, technically, it is. However, the industry has shifted its "unit of abstraction." In the past, we abstracted at the CSS level. Today, we abstract at the Component level.
Rules for Using @apply
The @apply directive allows you to inline Tailwind utility classes into custom CSS rules. While powerful, it should be used sparingly to avoid losing the benefits of the utility-first workflow.
When to use it:
The "Rule of Three": Don't use
@applyfor a component until you have repeated the exact same string of utilities in at least three different places.Third-Party Integration: Use
@applywhen you need to override styles for external libraries (like a calendar or rich-text editor) where you cannot modify the HTML.Base Typography: Use it in your global CSS for standard HTML tags (e.g.,
h1,h2,p) to ensure consistent document flow.
When to avoid it:
Avoid "Semantic" Names Too Early: Don't create
@apply .nav-link-item-active-statejust because it feels "cleaner." It often makes debugging harder because you have to jump between files.
The Power of Reusable Components
In the era of React, Vue, and Svelte, the component is the abstraction, not the CSS class.
Rules for Reusable Components:
Encapsulate, Don't Abstract: Instead of creating a
.cardclass in CSS, create a component. This keeps your styles scoped and discoverable.Prop-Based Variation: Use tools like
tailwind-mergeandcva(Class Variance Authority) to handle dynamic styles.The "Single Source of Truth": Define your core design tokens (colors, spacing, shadows) in
tailwind.config.js. AI assistants are great at reading your config file to ensure they suggest the right brand colors rather than random hex codes.
Working with AI Sustainably
To keep your codebase DRY while using AI:
Feed the Context: Always provide your
tailwind.config.jsor your "Design System" folder to the AI context.Refactor Prompting: Periodically ask the AI: "I have these three components with similar Tailwind styles. How can I refactor these into a single reusable component?"
Limit "Wall of Classes": If a
divhas more than 10 utility classes, it is a candidate for a sub-component, not necessarily an@applyrule.
Why Repetition is Actually Resilience
Here is the hard truth: Traditional DRY was often Premature Optimization. We used to create massive Sass mixin hierarchies that were so "efficient" that no one could change a padding value without breaking the entire site. Tailwind’s "repetition" is actually decoupling.
If you change a utility class on one page, you don't accidentally break another.
AI can move faster because it doesn't have to navigate a 5-level deep CSS inheritance tree.
The Strategy for the future:
"Repeat until the pattern is undeniable. Abstract only when the maintenance cost of repetition exceeds the mental cost of the abstraction."
Something to add or contest? I'm always open to technical debate.
Start a discussion