Skip to content

Tailwind CSS - Reusing Styles

Tailwind CSS: Modern Strategies for Reusing Styles

Section titled “Tailwind CSS: Modern Strategies for Reusing Styles”

Tailwind’s utility-first approach is incredibly powerful for building bespoke designs quickly. However, as projects grow, you’ll inevitably encounter repeating patterns of utilities. Managing this repetition effectively is key to maintaining a clean and scalable codebase.

This guide covers modern strategies for reusing styles, from simple editor tricks to robust component-based architectures, helping you decide which approach is best for your situation.

Often, what looks like repeated code in your final HTML is actually generated by a loop in a template or from a list of data. This isn’t true repetition because you only write the template markup once.

This is the most common and preferred method for lists of similar items, such as blog posts, product cards, or user profiles. The styles are defined once in the loop’s template, and the data provides the unique content.

Example: Generating Profile Cards from an Array

Section titled “Example: Generating Profile Cards from an Array”

Here, we define a JavaScript array of user data and use forEach to dynamically create the HTML for each profile card. If we need to change the card’s styling, we only have to edit one place.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dynamic Profile Cards</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-gray-100 p-8">
<div id="profile-container" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
<!-- Profile cards will be dynamically inserted here -->
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
const profiles = [
{
name: 'Alex Johnson',
role: 'Lead Developer',
imgSrc: 'https://randomuser.me/api/portraits/men/1.jpg',
borderColor: 'border-blue-500',
bio: 'Alex is a full-stack expert with a passion for clean code and modern frameworks.'
},
{
name: 'Maria Garcia',
role: 'UX/UI Designer',
imgSrc: 'https://randomuser.me/api/portraits/women/2.jpg',
borderColor: 'border-pink-500',
bio: 'Maria crafts beautiful, intuitive, and accessible user experiences.'
},
{
name: 'Kenichi Tanaka',
role: 'DevOps Engineer',
imgSrc: 'https://randomuser.me/api/portraits/men/3.jpg',
borderColor: 'border-teal-500',
bio: 'Kenichi ensures our infrastructure is scalable, reliable, and secure.'
}
];
const container = document.getElementById('profile-container');
if (container) {
profiles.forEach(profile => {
const profileCardHTML = `
<div class="flex flex-col items-center p-6 bg-white rounded-xl shadow-lg transform hover:scale-105 transition-transform">
<img class="h-24 w-24 rounded-full border-4 ${profile.borderColor} object-cover" src="${profile.imgSrc}" alt="${profile.name}'s profile picture" />
<h3 class="text-xl font-semibold text-gray-900 mt-4">${profile.name}</h3>
<p class="text-gray-600">${profile.role}</p>
<p class="text-gray-500 text-sm text-center mt-2">${profile.bio}</p>
</div>
`;
container.innerHTML += profileCardHTML;
});
}
});
</script>
</body>
</html>

Strategy 2: Extracting Components (The Modern Standard)

Section titled “Strategy 2: Extracting Components (The Modern Standard)”

When you need to reuse a piece of UI across different pages or contexts, extracting it into a reusable component is the best practice. This is the standard approach in modern frameworks like React, Vue, and Svelte, and is also possible with server-side templating languages like Blade (Laravel) or Twig (Symfony).

A component encapsulates both the HTML structure and the Tailwind classes, providing a single source of truth. You can then pass data to the component via props to customize its content.

Example: A Reusable TestimonialCard Component in React

Section titled “Example: A Reusable TestimonialCard Component in React”

First, we define the TestimonialCard component. It accepts name, photo, and testimonial as props.

components/TestimonialCard.jsx
import React from 'react';
// This is a functional React component.
// It receives props (data) and returns JSX (HTML-like syntax).
const TestimonialCard = ({ name, photo, testimonial, company }) => {
return (
<figure className="flex flex-col items-center p-6 bg-white rounded-xl shadow-lg">
<img
className="w-20 h-20 rounded-full object-cover"
src={photo}
alt={`Photo of ${name}`}
/>
<blockquote className="mt-4 text-center text-gray-700 italic">
<p>"{testimonial}"</p>
</blockquote>
<figcaption className="mt-4 font-semibold text-gray-900">
{name}
<div className="text-sm text-gray-500 font-normal">{company}</div>
</figcaption>
</figure>
);
};
export default TestimonialCard;

Then, we can import and use this component anywhere in our application, keeping our code clean and DRY (Don’t Repeat Yourself).

pages/HomePage.jsx
import React from 'react';
import TestimonialCard from './components/TestimonialCard';
const App = () => {
const testimonialsData = [
{ name: 'John Doe', company: 'TechCorp', photo: '...', testimonial: 'This service is fantastic!' },
{ name: 'Jane Smith', company: 'Innovate LLC', photo: '...', testimonial: 'An excellent experience from start to finish.' },
];
return (
<div className="bg-gray-100 p-8">
<h2 class="text-3xl font-bold text-center mb-8">What Our Clients Say</h2>
<div className="grid md:grid-cols-2 gap-8 max-w-4xl mx-auto">
{testimonialsData.map((data, index) => (
<TestimonialCard key={index} {...data} />
))}
</div>
</div>
);
};
export default App;

Strategy 3: Extracting Classes with @apply

Section titled “Strategy 3: Extracting Classes with @apply”

Tailwind’s @apply directive lets you extract a list of utility classes into a new, custom CSS class. This can be useful for very small, generic, and widely repeated UI elements where creating a full-blown component might feel like overkill.

Good use cases:

  • Buttons: btn-primary, btn-secondary.
  • Form Inputs: .form-input, .form-label.
  • Styling content from a CMS: Applying styles to raw HTML where you can’t add classes directly (e.g., Markdown output).

Warning: Avoid Premature Abstraction! Overusing @apply is a common anti-pattern. It can lead you back to the old way of writing CSS, where you have to invent class names for everything and constantly switch between your HTML and CSS files. Always prefer component extraction or loops first.

/* in your main CSS file, e.g., src/input.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer components {
.btn-primary {
@apply py-2 px-4 bg-blue-600 text-white font-semibold rounded-lg shadow-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-400 focus:ring-opacity-75;
}
.btn-secondary {
@apply py-2 px-4 bg-gray-600 text-white font-semibold rounded-lg shadow-md hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-gray-400 focus:ring-opacity-75;
}
}

Now you can use these classes directly in your HTML:

<button class="btn-primary">Submit</button>
<button class="btn-secondary">Cancel</button>