uuid: - value: 12950855-9231-4731-9ccc-e8bc9f61e170 langcode: - value: en type: - target_id: daily_email target_type: node_type target_uuid: 8bde1f2f-eef9-4f2d-ae9c-96921f8193d7 revision_timestamp: - value: '2025-05-11T09:00:48+00:00' revision_uid: - target_type: user target_uuid: b8966985-d4b2-42a7-a319-2e94ccfbb849 revision_log: { } status: - value: true uid: - target_type: user target_uuid: b8966985-d4b2-42a7-a319-2e94ccfbb849 title: - value: | Reducing utility class duplication created: - value: '2023-01-07T00:00:00+00:00' changed: - value: '2025-05-11T09:00:48+00:00' promote: - value: false sticky: - value: false default_langcode: - value: true revision_translation_affected: - value: true path: - alias: /daily/2023/01/07/reducing-utility-class-duplication langcode: en body: - value: |
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:
<li>
<a class="block py-2 border-b-2 border-transparent hover:text-blue-500 hover:border-blue-500 focus:bg-yellow-400 focus:border-current focus:outline-none" href="#0">About</a>
</li>
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.
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";
--- <li><a class={linkClasses} href="#0">About</a></li>
<li><a class={linkClasses} href="#0">Talks</a></li>
<li><a class={linkClasses} href="#0">Blog</a></li>
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"
>
<li><a class="link" href="#0">About</a></li>
<li><a class="link" href="#0">Blog</a></li>
<li><a class="link" href="#0">Talks</a></li>
</ul>
</Layout>
<style>
.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;
}
</style>
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.
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 => (
<li>
<a class="block py-2 border-b-2 border-transparent hover:text-blue-500 hover:border-blue-500 focus:bg-yellow-400 focus:border-current focus:outline-none" href="#0">
{link.name}
</a>
</li>
))}
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;
--- <a class="block py-2 border-b-2 border-transparent hover:text-blue-500 hover:border-blue-500 focus:bg-yellow-400 focus:border-current focus:outline-none" href="#0">
{name}
</a>
And the original file:
--- import Layout from "~/layouts/Layout.astro";
import Link from "~/components/Link.astro";
--- <Layout>
<ul class="flex flex-col gap-4 justify-center sm:flex-row sm:flex-wrap sm:gap-6">
<li><Link name="About" /></li>
<li><Link name="Blog" /></li>
<li><Link name="Talks" /></li>
<li><Link name="Daily list" /></li>
<li><Link name="Search" /></li>
</ul>
</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.
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.
format: full_html processed: |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:
<li>
<a class="block py-2 border-b-2 border-transparent hover:text-blue-500 hover:border-blue-500 focus:bg-yellow-400 focus:border-current focus:outline-none" href="#0">About</a>
</li>
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.
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";
--- <li><a class={linkClasses} href="#0">About</a></li>
<li><a class={linkClasses} href="#0">Talks</a></li>
<li><a class={linkClasses} href="#0">Blog</a></li>
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"
>
<li><a class="link" href="#0">About</a></li>
<li><a class="link" href="#0">Blog</a></li>
<li><a class="link" href="#0">Talks</a></li>
</ul>
</Layout>
<style>
.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;
}
</style>
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.
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 => (
<li>
<a class="block py-2 border-b-2 border-transparent hover:text-blue-500 hover:border-blue-500 focus:bg-yellow-400 focus:border-current focus:outline-none" href="#0">
{link.name}
</a>
</li>
))}
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;
--- <a class="block py-2 border-b-2 border-transparent hover:text-blue-500 hover:border-blue-500 focus:bg-yellow-400 focus:border-current focus:outline-none" href="#0">
{name}
</a>
And the original file:
--- import Layout from "~/layouts/Layout.astro";
import Link from "~/components/Link.astro";
--- <Layout>
<ul class="flex flex-col gap-4 justify-center sm:flex-row sm:flex-wrap sm:gap-6">
<li><Link name="About" /></li>
<li><Link name="Blog" /></li>
<li><Link name="Talks" /></li>
<li><Link name="Daily list" /></li>
<li><Link name="Search" /></li>
</ul>
</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.
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.
summary: null field_daily_email_cta: { }