Reusing styles
A product card takes a dozen classes. If you copy its markup twenty times, every change — say, a different corner radius — has to be made twenty times. In Tailwind such repetition is removed not in CSS but in templates: the markup is written once and the data is filled in.
A loop instead of copies
When cards follow each other, build them in a loop from an array of data. The card markup is written once:
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<div id="catalog" class="grid grid-cols-3 gap-4"></div>
<script>
const products = [
{ name: 'Headphones', price: 79 },
{ name: 'Speaker', price: 45 },
{ name: 'Charger', price: 19 },
];
document.getElementById('catalog').innerHTML = products.map((product) => `
<div class="rounded-xl bg-white p-4 shadow">
<h2 class="font-semibold">${product.name}</h2>
<p class="text-gray-600">$${product.price}</p>
</div>
`).join('');
</script>Below the code are three identically styled cards. To change the shadow on all of them, you fix one line of the template.
A template component
In React, Vue or Svelte a repeated piece goes into a component. For example, in a Vite project with React, the file src/components/ProductCard.jsx:
// src/components/ProductCard.jsx
export default function ProductCard({ name, price, image }) {
return (
<div className="overflow-hidden rounded-xl bg-white shadow-lg">
<img src={image} alt={name} className="h-40 w-full object-cover" />
<div className="p-4">
<h2 className="font-semibold text-gray-900">{name}</h2>
<p className="mt-1 text-gray-600">${price}</p>
</div>
</div>
);
}It is used like a regular tag, with the data passed as attributes:
// src/App.jsx
import ProductCard from './components/ProductCard.jsx';
export default function App() {
return (
<div className="grid grid-cols-3 gap-4 p-6">
<ProductCard name="Headphones" price={79} image="/media/photo-400x250.jpg" />
<ProductCard name="Speaker" price={45} image="/media/photo-400x250.jpg" />
</div>
);
}The card's classes live in one file, and the page assembles it with different data. In React the attribute is called className, not class.
Partials on the server
Without a JavaScript framework, backend templates do the same: include in PHP, @include or Blade components in Laravel, {% include %} in Django and Twig. The card goes into a separate file and is included in a loop.
Small repetitions
If three neighbouring menu links share the same classes, there is no need to extract anything: an editor with multiple cursors edits them in a second. A component is worth it when a piece of markup repeats in different places or files.
Common mistake
Moving the card's classes into CSS with @apply right away "to avoid copying". You end up with a .product-card class in a separate file, while the card's markup — image, heading, price — is still copied. What repeats is not a set of classes but a piece of markup, so it is the markup you should extract — into a component or a partial.