Reducing utility class duplication

One of the main concerns for Developers evaluating or starting with a utility-first approach to styling is maintainability due to the number and duplication of classes.

For example, with this component, as I duplicate it to add more links, I also duplicate the classes applied to the link - making it harder to maintain:


About


There are some solutions to this, which you can also see in an example Astro project at https://github.com/opdavies/reducing-utility-class-duplication.

Extracting a variable of class names

The simplest way to remove the duplication is to create a variable that holds the class names which can be reused. For example, Astro allows variables to be created within the frontmatter section and used within the template. Creating variables can be done in other templating engines too.

---
const linkClasses = "py-2 block border-b-2 border-transparent hover:border-blue-500 hover:text-blue-500 focus:outline-none focus:bg-yellow-400 focus:border-current";
---

About
Talks
Blog

Extracting CSS components

Instead of extracting a variable, you could also extract a CSS component. With Tailwind, the @apply directive within a stylesheet will create a reusable CSS component:

<Layout>
<ul
class="flex flex-col gap-4 justify-center sm:flex-row sm:flex-wrap sm:gap-6"
>
About
Blog
Talks

</Layout>


.link {
@apply py-2 block border-b-2 border-transparent hover:border-blue-500 hover:text-blue-500 focus:outline-none focus:bg-yellow-400 focus:border-current;
}


The link class can be added to any link items, and whilst the approach works, I prefer to use template-based solutions and keep the classes within the HTML markup.

Loops and maps

Templating engines will have a way to loop over a list of items. This can be used to remove the duplication and only have a single list of classes whilst keeping the benefits of keeping them in the HTML code.

For example, in Astro:

---
const links = [
{ name: "About" },
{ name: "Blog" },
{ name: "Talks" },
{ name: "Daily list" },
{ name: "Search" },
];
---

{links.map(link => (


{link.name}


))}

Extracting HTML components

Finally, if the component needs to be reused, it can be extracted into its own file and re-imported where needed.

This is the extracted component:

---
const { name } = Astro.props;
---


{name}


And the original file:

---
import Layout from "~/layouts/Layout.astro";
import Link from "~/components/Link.astro";
---

<Layout>







</Layout>

This can now be used anywhere within this project and could be combined with the loop approach, passing the appropriate value to the name prop.

Summary

All of these approaches remove duplication, either using features provided by Tailwind CSS or a templating engine, to make the code more maintainable.

I've shown Astro in these examples but the same can be done with PHP, Twig, Blade, Vue, React, etc.

The examples are public on GitHub at https://github.com/opdavies/reducing-utility-class-duplication/tree/main/src/pages.