{"id":23124,"date":"2026-08-07T21:34:19","date_gmt":"2026-08-07T21:34:19","guid":{"rendered":"https:\/\/scannn.com\/5-best-practices-for-preventing-chaos-in-tailwind-css-martian-chronicles-evil-martians-team-blog\/"},"modified":"2026-08-07T21:34:19","modified_gmt":"2026-08-07T21:34:19","slug":"5-best-practices-for-preventing-chaos-in-tailwind-css-martian-chronicles-evil-martians-team-blog","status":"publish","type":"post","link":"https:\/\/scannn.com\/lv\/5-best-practices-for-preventing-chaos-in-tailwind-css-martian-chronicles-evil-martians-team-blog\/","title":{"rendered":"5 best practices for preventing chaos in Tailwind\u00a0CSS\u2014Martian Chronicles, Evil Martians\u2019 team blog"},"content":{"rendered":"\n<div data-theme-reset=\"true\">\n<div class=\"MarkdownIntro-module--root--2a5f4 Markdown-module--max--b7164\">\n<p>Working with Tailwind CSS is pretty fast and easy (that\u2019s why it\u2019s received such wide recognition). You just paste a list of different classes in your HTML\u2014and your interface immediately becomes attractive! But, as the application grows, the lists of classes grow. Then, one day you realize you can\u2019t understand your code, you\u2019re confused with the structure of the application and magic variables, and work becomes a struggle. This article is all about avoiding this scenario, sharing some best practices to ensure you stay aloft when using Tailwind CSS.<\/p>\n<\/div>\n<p><strong class=\"MarkdownStrong-module--root--fab94\">Want your agent to do this for you?<\/strong> We packaged the guide as a skill you can download that includes every practice below, plus the anti-patterns to catch.<\/p>\n<div id=\"skill-tailwind-best-practices\" class=\"MarkdownAgentSkillReference-module--anchor--ad2aa\">\n<aside class=\"MarkdownAgentSkillReference-module--root--98bb8\" style=\"--rgb-theme-logo:62 0 53;--oklch-theme-logo:24.3300% 0.1190 335.4300;--opacity-theme-logo:11.08%;--switch-theme-logo:1;--rgb-theme-title:62 0 53;--oklch-theme-title:24.3300% 0.1190 335.4300;--opacity-theme-title:11.08%;--rgb-theme-navigation:62 0 53;--oklch-theme-navigation:24.3300% 0.1190 335.4300;--opacity-theme-navigation:11.08%;--rgb-theme-text:255 239 255;--oklch-theme-text:97.0000% 0.0296 328.0000;--opacity-theme-text:29.25%;--rgb-theme-button:62 0 53;--oklch-theme-button:24.3300% 0.1190 335.4300;--opacity-theme-button:11.08%;--rgb-theme-background:87 185 225;--oklch-theme-background:74.2774% 0.1080 227.7094;--opacity-theme-background:100%\" data-with-theme=\"true\">\n<div class=\"MarkdownAgentSkillReference-module--label--eb402\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"24\" height=\"24\" fill=\"none\" viewbox=\"0 0 24 24\" class=\"Icon-module--icon24--b74c8 MarkdownAgentSkillReference-module--labelIcon--f66ca ariaHidden\" aria-hidden=\"true\"><path fill=\"currentColor\" d=\"M22.586 4c-.965 0-1.517-.552-1.517-1.517A.471.471 0 0 0 20.586 2a.471.471 0 0 0-.483.483c0 .551.138 1.034.345 1.448l-1.31 1.38c-1.035-.828-2.345-1.242-4.069-1.242h-6c-1.724 0-3.035.414-4.069 1.241L3.69 4c.276-.414.344-.897.344-1.448 0-.345-.275-.552-.551-.552S3 2.207 3 2.483C3 3.448 2.448 4 1.483 4 1.207 4 1 4.207 1 4.483s.207.483.483.483c.551 0 1.034-.138 1.448-.345l1.38 1.31C3.482 6.966 3.068 8.276 3.068 10v8.552A3.415 3.415 0 0 0 6.517 22h11.035A3.415 3.415 0 0 0 21 18.552V10c0-1.724-.414-3.034-1.241-4.069l1.31-1.31c.414.276.897.345 1.448.345.276 0 .483-.207.483-.483S22.862 4 22.586 4zM8.931 16.483c-1.31 0-2.414-1.104-2.414-2.414s1.104-2.414 2.414-2.414 2.414 1.104 2.414 2.414-1.104 2.414-2.414 2.414zm6.207 0c-1.31 0-2.414-1.104-2.414-2.414s1.104-2.414 2.414-2.414 2.414 1.104 2.414 2.414-1.104 2.414-2.414 2.414z\"\/><path fill=\"currentColor\" fill-rule=\"evenodd\" d=\"M15.113 13.156a.956.956 0 1 0 0 1.913.956.956 0 0 0 0-1.913zm-1.457.956a1.456 1.456 0 1 1 2.913 0 1.456 1.456 0 0 1-2.913 0zm-4.7-.956a.956.956 0 1 0 0 1.913.956.956 0 0 0 0-1.913zm-1.456.957a1.456 1.456 0 1 1 2.913 0 1.456 1.456 0 0 1-2.913 0z\" clip-rule=\"evenodd\"\/><\/svg>Install this skill in your agent<\/div>\n<div class=\"MarkdownAgentSkillReference-module--preview--c516e\">\n<div id=\"skill-tailwind-best-practices-body\" class=\"MarkdownAgentSkillReference-module--body--30d77 MarkdownAgentSkillReference-module--bodyCollapsed--58df2\"><span class=\"MarkdownAgentSkillReference-module--filename--7c5bc\">SKILL.md<\/span><\/p>\n<pre class=\"MarkdownAgentSkillReference-module--code--de2e9\"><code>---\nname: tailwind-best-practices\ndescription: Write Tailwind CSS following practices that keep a fast-to-write codebase maintainable \u2014 use design tokens instead of magic values, keep class lists short, group tokens semantically, generate classes in consistent order, avoid @apply for extracting repeated styles, and use fixed variants instead of arbitrary className props. Use this whenever writing or editing Tailwind classes, components, or config, and also when reviewing, cleaning up, refactoring, or auditing an existing Tailwind project. Do NOT use for general CSS architecture unrelated to Tailwind, or for build tooling unrelated to CSS output (bundlers, JS minification, etc.).\n---\n\n# Tailwind CSS best practices\n\nApply the checks below to keep a Tailwind CSS codebase readable as it grows. Companion to &lt;https:\/\/evilmartians.com\/chronicles\/5-best-practices-for-preventing-chaos-in-tailwind-css&gt;.\n\nTailwind's utility-first approach only stays maintainable under two conditions \u2014 confirm both before applying anything else:\n\n1. **A design system with tokens exists** (colors, spacing, typography scale defined once, reused everywhere \u2014 not hand-typed magic values repeated across files).\n2. **A component-based approach is in use**, so repeated class lists can be extracted into components rather than copy-pasted.\n<\/code><\/pre>\n<p><span class=\"MarkdownAgentSkillReference-module--fade--35270\" aria-hidden=\"true\"\/><\/div>\n<p><button type=\"button\" class=\"MarkdownAgentSkillReference-module--toggle--aeb08\" aria-expanded=\"false\" aria-controls=\"skill-tailwind-best-practices-body\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"16\" height=\"16\" fill=\"none\" viewbox=\"0 0 16 16\" class=\"Icon-module--icon16--25a2c MarkdownAgentSkillReference-module--toggleIcon--22751 ariaHidden\" aria-hidden=\"true\"><path d=\"m3.5 5.75 4.5 4.5 4.5-4.5\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"square\"\/><\/svg><span class=\"MarkdownAgentSkillReference-module--toggleLabel--b45d1\">Show full SKILL.md<\/span><\/button><\/div>\n<div class=\"AgentSkillActions-module--root--a7cc4\">\n<p><button class=\"Button-module--root--c1f31 Button-module--size_sm--63d55 Button-module--variant_solid--d7dbc Button-module--theme_current_text--4627d Button-module--hoverable--69e49 Clickable-module--root--f3e4f\" type=\"button\" tabindex=\"0\" role=\"tab\" aria-selected=\"true\">Claude Code<\/button><button class=\"Button-module--root--c1f31 Button-module--size_sm--63d55 Button-module--variant_translucent--d26fb Button-module--theme_current_text--4627d Button-module--hoverable--69e49 Clickable-module--root--f3e4f\" type=\"button\" tabindex=\"0\" role=\"tab\" aria-selected=\"false\">Cursor<\/button><button class=\"Button-module--root--c1f31 Button-module--size_sm--63d55 Button-module--variant_translucent--d26fb Button-module--theme_current_text--4627d Button-module--hoverable--69e49 Clickable-module--root--f3e4f\" type=\"button\" tabindex=\"0\" role=\"tab\" aria-selected=\"false\">Codex<\/button><button class=\"Button-module--root--c1f31 Button-module--size_sm--63d55 Button-module--variant_translucent--d26fb Button-module--theme_current_text--4627d Button-module--hoverable--69e49 Clickable-module--root--f3e4f\" type=\"button\" tabindex=\"0\" role=\"tab\" aria-selected=\"false\">GitHub Copilot<\/button><button class=\"Button-module--root--c1f31 Button-module--size_sm--63d55 Button-module--variant_translucent--d26fb Button-module--theme_current_text--4627d Button-module--hoverable--69e49 Clickable-module--root--f3e4f\" type=\"button\" tabindex=\"0\" role=\"tab\" aria-selected=\"false\">Gemini CLI<\/button><\/p>\n<p><button class=\"Button-module--root--c1f31 Button-module--size_sm--63d55 Button-module--variant_solid--d7dbc Button-module--theme_current_text--4627d Button-module--hoverable--69e49 Clickable-module--root--f3e4f\" type=\"button\" tabindex=\"0\" role=\"tab\" aria-selected=\"true\">npx skills<\/button><button class=\"Button-module--root--c1f31 Button-module--size_sm--63d55 Button-module--variant_translucent--d26fb Button-module--theme_current_text--4627d Button-module--hoverable--69e49 Clickable-module--root--f3e4f\" type=\"button\" tabindex=\"0\" role=\"tab\" aria-selected=\"false\">claude plugin<\/button><button class=\"Button-module--root--c1f31 Button-module--size_sm--63d55 Button-module--variant_translucent--d26fb Button-module--theme_current_text--4627d Button-module--hoverable--69e49 Clickable-module--root--f3e4f\" type=\"button\" tabindex=\"0\" role=\"tab\" aria-selected=\"false\">gh skill<\/button><button class=\"Button-module--root--c1f31 Button-module--size_sm--63d55 Button-module--variant_translucent--d26fb Button-module--theme_current_text--4627d Button-module--hoverable--69e49 Clickable-module--root--f3e4f\" type=\"button\" tabindex=\"0\" role=\"tab\" aria-selected=\"false\">curl<\/button><\/p>\n<div class=\"AgentSkillActions-module--commandRow--8e2a4\"><code class=\"AgentSkillActions-module--command--1ed25\">npx skills add https:\/\/evilmartians.com\/agent-skills --skill tailwind-best-practices -a claude-code -g<\/code><button class=\"Button-module--root--c1f31 Button-module--size_sm--63d55 Button-module--variant_translucent--d26fb Button-module--theme_current_text--4627d AgentSkillActions-module--copy--2d5b3 Button-module--hoverable--69e49 Clickable-module--root--f3e4f\" type=\"button\" aria-label=\"Copy install command\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"16\" height=\"16\" fill=\"none\" viewbox=\"0 0 16 16\" class=\"Icon-module--icon16--25a2c ariaHidden\" aria-hidden=\"true\"><path stroke=\"currentColor\" d=\"M5.5 5.5h8v8h-8z\"\/><path d=\"M10.5 5.5v-3h-8v8h3\" stroke=\"currentColor\"\/><\/svg><\/button><\/div>\n<\/div>\n<\/aside>\n<\/div>\n<p>We can prevent headaches and resolve any problems (for the most part) by using Tailwind precisely and wisely. But, there are two requirements your project must meet, and if it doesn\u2019t, Tailwind can actually make your job very difficult.<\/p>\n<aside class=\"MarkdownSidenote-module--root--21525 Markdown-module--aside--e9b55\" role=\"note\"\/>\n<p><strong class=\"MarkdownStrong-module--root--fab94\">First, you should have a design system in your project<\/strong>. Tailwind\u2019s philosophy couples with a design system where designers and developers use consistent design tokens. Design tokens are atomic values (like colors, spacing, or typography scales) that define a design\u2019s properties and that are reused throughout the project.<\/p>\n<p>Let\u2019s imagine we have a standard button and some tabs that need to be the same color as that button:<\/p>\n<pre class=\"language-css\"><code class=\"language-css code-highlight\"><span class=\"code-line\"><span class=\"token selector\"><span class=\"token class\">.button<\/span><\/span> <span class=\"token punctuation\">{<\/span>\n<\/span><span class=\"code-line\">  <span class=\"token property\">background-color<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">oklch<\/span><span class=\"token punctuation\">(<\/span><span class=\"token number\">45<\/span><span class=\"token unit\">%<\/span> <span class=\"token number\">0.2<\/span> <span class=\"token number\">270<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span>\n<\/span><span class=\"code-line\"><span class=\"token punctuation\">}<\/span>\n<\/span><span class=\"code-line\">\n<\/span><span class=\"code-line\"><span class=\"token selector\"><span class=\"token class\">.tab<\/span><\/span> <span class=\"token punctuation\">{<\/span>\n<\/span><span class=\"code-line\">  <span class=\"token property\">background-color<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">oklch<\/span><span class=\"token punctuation\">(<\/span><span class=\"token number\">45<\/span><span class=\"token unit\">%<\/span> <span class=\"token number\">0.2<\/span> <span class=\"token number\">270<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span>\n<\/span><span class=\"code-line\"><span class=\"token punctuation\">}<\/span>\n<\/span><\/code><\/pre>\n<p>If we decide to change the color scheme of the project a little, we\u2019ll need to find every instance of this color (which looks like a magic variable) and update them everywhere. This can be inconsistent and hard to maintain.<\/p>\n<section class=\"ConsultationCtaMini-module--wrapper--8f1eb\"><a class=\"ConsultationCtaMini-module--block--fc64b ConsultationCtaMini-module--ira_chatBlock--b4c7a Clickable-module--root--f3e4f\" href=\"https:\/\/cal.com\/team\/evilmartians\/exploration\" target=\"_blank\" rel=\"noopener noreferrer\" align=\"content\"><\/p>\n<div class=\"ConsultationCtaMini-module--imageContainer--a5aa7 ConsultationCtaMini-module--ira_chatImageContainer--d786b\">\n<div class=\"ConsultationCtaMini-module--indicatorContainer--ec9a7 ConsultationCtaMini-module--ira_chatIndicatorContainer--77546\"><picture><source type=\"image\/avif\" srcset=\"https:\/\/imgproxy.evilmartians.com\/2MTpStA0xGWkFdi0RdM1J3I4KzDhig-ROoEkdSH10mg\/width:192\/quality:80\/format:avif\/aHR0cHM6Ly9ldmlsbWFydGlhbnMuY29tL2ltYWdlcy9jb25zdWx0YXRpb24taXJhLndlYnA_dj1mM2JiYTI2Zg\"\/><source type=\"image\/webp\" srcset=\"https:\/\/imgproxy.evilmartians.com\/7oGOLktDg7C5q3vfL5QMh6rJb5WJaulIeBOP2CLPMXo\/width:192\/quality:80\/format:webp\/aHR0cHM6Ly9ldmlsbWFydGlhbnMuY29tL2ltYWdlcy9jb25zdWx0YXRpb24taXJhLndlYnA_dj1mM2JiYTI2Zg\"\/><\/picture><\/div>\n<\/div>\n<p class=\"ConsultationCtaMini-module--title--94ec5\"><b>Irina Nazarova<\/b> <small>CEO at Evil Martians<\/small><\/p>\n<p class=\"ConsultationCtaMini-module--description--7ba45 ConsultationCtaMini-module--ira_chatDescription--459df ConsultationCtaMini-module--withGhost--c5b43\"><span class=\"ConsultationCtaMini-module--ghost--42764\" aria-hidden=\"true\">We built open source projects PostCSS and Autoprefixer, used by millions of engineers. Hire us to optimize your frontend workflow and build scalable solutions.<\/span><span class=\"ConsultationCtaMini-module--typedText--9c7e1\"\/><\/p>\n<p><\/a><\/section>\n<blockquote class=\"MarkdownInset-module--root--191ed Markdown-module--max--b7164\">\n<p>Design tokens help prevent these problems and ensure uniformity across UI elements.<\/p>\n<\/blockquote>\n<p>Luckily, to implement design tokens, we only need to define them once\u2014directly in your CSS via the <code class=\"language-text\">@theme<\/code> directive (or in <code class=\"language-text\">tailwind.config.js<\/code> if you still use Tailwind v3):<\/p>\n<pre class=\"language-css\"><code class=\"language-css code-highlight\"><span class=\"code-line\">\n<\/span><span class=\"code-line\"><span class=\"token atrule\"><span class=\"token rule\">@theme<\/span><\/span> <span class=\"token punctuation\">{<\/span>\n<\/span><span class=\"code-line\">  <span class=\"token variable\">--color-primary<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">oklch<\/span><span class=\"token punctuation\">(<\/span><span class=\"token number\">45<\/span><span class=\"token unit\">%<\/span> <span class=\"token number\">0.2<\/span> <span class=\"token number\">270<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span>\n<\/span><span class=\"code-line\"><span class=\"token punctuation\">}<\/span>\n<\/span><\/code><\/pre>\n<pre class=\"language-js\"><code class=\"language-js code-highlight\"><span class=\"code-line\">\n<\/span><span class=\"code-line\">module<span class=\"token punctuation\">.<\/span><span class=\"token property-access\">exports<\/span> <span class=\"token operator\">=<\/span> <span class=\"token punctuation\">{<\/span>\n<\/span><span class=\"code-line\">  <span class=\"token literal-property property\">theme<\/span><span class=\"token operator\">:<\/span> <span class=\"token punctuation\">{<\/span>\n<\/span><span class=\"code-line\">    <span class=\"token literal-property property\">colors<\/span><span class=\"token operator\">:<\/span> <span class=\"token punctuation\">{<\/span>\n<\/span><span class=\"code-line\">      <span class=\"token literal-property property\">primary<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"oklch(45% 0.2 270)\"<\/span><span class=\"token punctuation\">,<\/span>\n<\/span><span class=\"code-line\">    <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">,<\/span>\n<\/span><span class=\"code-line\">  <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">,<\/span>\n<\/span><span class=\"code-line\"><span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">;<\/span>\n<\/span><\/code><\/pre>\n<p>After adding a new color with the name <code class=\"language-text\">primary<\/code>, we can use <code class=\"language-text\">bg-primary<\/code> for our background color or <code class=\"language-text\">text-primary<\/code> for the text color throughout the application:<\/p>\n<pre class=\"language-html\"><code class=\"language-html code-highlight\"><span class=\"code-line\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>button<\/span> <span class=\"token attr-name\">class<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=<\/span><span class=\"token punctuation\">\"<\/span>bg-primary<span class=\"token punctuation\">\"<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span>Standard button<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>button<\/span><span class=\"token punctuation\">&gt;<\/span><\/span>\n<\/span><span class=\"code-line\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>div<\/span> <span class=\"token attr-name\">class<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=<\/span><span class=\"token punctuation\">\"<\/span>bg-primary<span class=\"token punctuation\">\"<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span>First tab<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>div<\/span><span class=\"token punctuation\">&gt;<\/span><\/span>\n<\/span><\/code><\/pre>\n<p>This way, when you want to change the color scheme in the project, you only need to replace the color in one place.<\/p>\n<p>It\u2019s better to <strong class=\"MarkdownStrong-module--root--fab94\">avoid using Tailwind if you haven\u2019t considered a design system<\/strong> because you\u2019ll have to write magic values in the class lists (like <code class=\"language-text\">'p-[123px] mb-[11px] gap-[3px]'<\/code>) or add a lot of new tokens (<code class=\"language-text\">15px<\/code>, <code class=\"language-text\">16px<\/code>, <code class=\"language-text\">17px<\/code> in the spacing config), and this will eventually bring a lot of mess to your code.<\/p>\n<blockquote class=\"MarkdownInset-module--root--191ed Markdown-module--max--b7164\">\n<p>Having a consistent design system is good because it can help the development and design teams understand each other better.<\/p>\n<\/blockquote>\n<p>For instance, within Figma, you can have a single shared source of truth for any values in your design system. But to make this system truly maintainable, you\u2019ll need to introduce some conventions regarding token grouping and naming\u2014which we\u2019ll get into later in this article.<\/p>\n<aside class=\"MarkdownSidenote-module--root--21525 Markdown-module--aside--e9b55\" role=\"note\"\/>\n<p>This is the second requirement your project needs to meet: <strong class=\"MarkdownStrong-module--root--fab94\">you should already be using a component-based approach<\/strong>. The utility-first approach can lead to quite cluttered and verbose HTML structures since Tailwind classes apply directly to elements. This can mean the markup is harder to read and maintain, especially noticeable as your project grows.<\/p>\n<blockquote class=\"MarkdownInset-module--root--191ed Markdown-module--max--b7164\">\n<p>The solution: actively using a component-based approach that encapsulates frequently used patterns (in our case, HTML elements appearing more than once) as separate components.<\/p>\n<\/blockquote>\n<p>With this approach, we can keep things <a class=\"Link-module--root--de2eb Clickable-module--root--f3e4f\" href=\"https:\/\/en.m.wikipedia.org\/wiki\/Don't_repeat_yourself\" target=\"_blank\" rel=\"noopener noreferrer\">DRY<\/a>. Moreover, we\u2019ll still have a single source of truth for our Tailwind styles, and we can easily update it together in one place:<\/p>\n<pre class=\"language-jsx\"><code class=\"language-jsx code-highlight\"><span class=\"code-line\"><span class=\"token operator\">&lt;<\/span><span class=\"token operator\">!<\/span><span class=\"token operator\">--<\/span> <span class=\"token maybe-class-name\">Reusable<\/span> button <span class=\"token keyword\">with<\/span> a long list <span class=\"token keyword\">of<\/span> <span class=\"token maybe-class-name\">Tailwind<\/span> classes<span class=\"token operator\">:<\/span> <span class=\"token operator\">--<\/span><span class=\"token operator\">&gt;<\/span>\n<\/span><span class=\"code-line\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>button<\/span>\n<\/span><\/span><span class=\"code-line\"><span class=\"token tag\">  <span class=\"token attr-name\">class<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=<\/span><span class=\"token punctuation\">\"<\/span>bg-yellow-700 border-2 font-semibold border border-gray-300 text-green p-4 rounded<span class=\"token punctuation\">\"<\/span><\/span>\n<\/span><\/span><span class=\"code-line\"><span class=\"token tag\"><span class=\"token punctuation\">&gt;<\/span><\/span><span class=\"token plain-text\">\n<\/span><\/span><span class=\"code-line\"><span class=\"token plain-text\">  Custom Button\n<\/span><\/span><span class=\"code-line\"><span class=\"token plain-text\"\/><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>button<\/span><span class=\"token punctuation\">&gt;<\/span><\/span>\n<\/span><span class=\"code-line\">\n<\/span><span class=\"code-line\"><span class=\"token operator\">&lt;<\/span><span class=\"token operator\">!<\/span><span class=\"token operator\">--<\/span> <span class=\"token maybe-class-name\">Instead<\/span> <span class=\"token keyword\">of<\/span> repeating <span class=\"token keyword\">this<\/span> structure over and over again<span class=\"token punctuation\">,<\/span> create a reusable component<span class=\"token operator\">:<\/span> <span class=\"token operator\">--<\/span><span class=\"token operator\">&gt;<\/span>\n<\/span><span class=\"code-line\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span><span class=\"token class-name\">CustomButton<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span><span class=\"token plain-text\">Custom Button<\/span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span><span class=\"token class-name\">CustomButton<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span>\n<\/span><\/code><\/pre>\n<p>If your development tool doesn\u2019t allow you to split your code into components, it\u2019s likely that the utility-first approach of Tailwind will only make development harder, and you should probably look to other CSS frameworks-for example, <a class=\"Link-module--root--de2eb Clickable-module--root--f3e4f\" href=\"https:\/\/github.com\/css-modules\/css-modules\" target=\"_blank\" rel=\"noopener noreferrer\">CSS Modules<\/a>.<\/p>\n<p>And one last thing regarding a component-based approach: <strong class=\"MarkdownStrong-module--root--fab94\">avoid using the <code class=\"language-text\">@apply<\/code> directive<\/strong>:<\/p>\n<pre class=\"language-css\"><code class=\"language-css code-highlight\"><span class=\"code-line\"><span class=\"token selector\"><span class=\"token class\">.block<\/span><\/span> <span class=\"token punctuation\">{<\/span>\n<\/span><span class=\"code-line\">  <span class=\"token atrule\"><span class=\"token rule\">@apply<\/span> bg-red-500 text-white p-4 rounded-lg <span class=\"token property\">active<\/span><span class=\"token punctuation\">:<\/span>bg-blue-700 <span class=\"token property\">active<\/span><span class=\"token punctuation\">:<\/span>text-yellow-300 <span class=\"token property\">hover<\/span><span class=\"token punctuation\">:<\/span>bg-blue-500 <span class=\"token property\">hover<\/span><span class=\"token punctuation\">:<\/span>text-yellow-300<span class=\"token punctuation\">;<\/span><\/span>\n<\/span><span class=\"code-line\"><span class=\"token punctuation\">}<\/span>\n<\/span><\/code><\/pre>\n<p>Yes, by using this directive, your code may look cleaner, but it throws away the key advantages of Tailwind: less mental overload when coming up with names for CSS classes, and the absence of regressions when changing styles (since with <code class=\"language-text\">@apply<\/code> they won\u2019t be isolated within the component). Further, using it increases CSS bundle size.<\/p>\n<p>In Tailwind v4, <code class=\"language-text\">@apply<\/code> also needs an explicit <code class=\"language-text\">@reference<\/code> import to access your theme when used in a separately bundled stylesheet (CSS Modules, or a <code class=\"language-text\">&lt;style&gt;<\/code> block in Vue, Svelte, or Astro)\u2014another reason to prefer CSS variables there instead.<\/p>\n<p>If you met both requirements, Tailwind CSS is likely a good framework option for you! Here are the most helpful practices for improving your long-term experience with it.<\/p>\n<h2 class=\"MarkdownHeading-module--root--01c0e Markdown-module--max--b7164\" id=\"1-use-fewer-utility-classes-when-possible\">1. Use fewer utility classes when possible<\/h2>\n<p>When you build a list of utility classes for an HTML element, each new class adds additional complexity for the developers, and they\u2019ll have to analyze and work with the code later (and this includes you, too). Of course, these lists are an essential and inherent feature of Tailwind, but nevertheless, it\u2019s better to write as little utility classes as possible.<\/p>\n<p>Here are a few ways you can decrease the number of classes and get exactly the same results:<\/p>\n<ul class=\"MarkdownUL-module--root--74925\">\n<li class=\"MarkdownLI-module--root--d3fdc\">Instead of setting <code class=\"language-text\">pt-4<\/code> <code class=\"language-text\">pb-4<\/code>, you can just use <code class=\"language-text\">py-4<\/code>. This also applies with the <code class=\"language-text\">px<\/code>, <code class=\"language-text\">mx<\/code>, and <code class=\"language-text\">my<\/code> properties.<\/li>\n<li class=\"MarkdownLI-module--root--d3fdc\">Instead of <code class=\"language-text\">flex flex-row justify-between<\/code>, you can just use <code class=\"language-text\">flex justify-between<\/code>. This is because <code class=\"language-text\">flex-row<\/code> is the default value of the<code class=\"language-text\">flex-direction<\/code> property in CSS. In general, it can be valuable to remember some default values of other CSS properties (<code class=\"language-text\">flex-wrap<\/code>, for example) to make it easier to spot use cases like this.<\/li>\n<li class=\"MarkdownLI-module--root--d3fdc\">Instead of writing a long class list like <code class=\"language-text\">border border-dotted border-2 border-black border-opacity-50<\/code>, you can set <code class=\"language-text\">border-dotted border-2 border-black\/50<\/code> and this will have the same effect: <code class=\"language-text\">border-2<\/code> implies that <code class=\"language-text\">border<\/code> is set, and <code class=\"language-text\">border-black\/50<\/code> represents a shorthand for the RGBA format.<\/li>\n<\/ul>\n<p>With a shorter list of classes, the next time you inspect the structure of your application, it\u2019ll be much easier to analyze what\u2019s going on.<\/p>\n<h2 class=\"MarkdownHeading-module--root--01c0e Markdown-module--max--b7164\" id=\"2-group-design-tokens-and-name-them-semantically\">2. Group design tokens and name them semantically<\/h2>\n<p>When working on a team, you probably agree that some clean coding practices (like the clear naming of variables) are really important for long-term development.<\/p>\n<p>That said, even if you\u2019re working alone, it also can be worth setting some rules for code clarity, otherwise, you could get confused about your own project (for example, when returning after a break).<\/p>\n<p>This approach is especially important while working with Tailwind because reckless usage of such a large number of classes and design tokens can really bring confusion into your code.<\/p>\n<p>As discussed above, using design tokens is a great practice, but just pasting them haphazardly can lead to chaos in your Tailwind configuration.<\/p>\n<p>To remedy this, group related tokens together\u2014in your <code class=\"language-text\">@theme<\/code> block (v4) or <code class=\"language-text\">tailwind.config.js<\/code> (v3). This means that design tokens for breakpoints, colors, and so on, will be in specific areas and won\u2019t mess with each other:<\/p>\n<pre class=\"language-css\"><code class=\"language-css code-highlight\"><span class=\"code-line\">\n<\/span><span class=\"code-line\"><span class=\"token atrule\"><span class=\"token rule\">@theme<\/span><\/span> <span class=\"token punctuation\">{<\/span>\n<\/span><span class=\"code-line\">  <span class=\"token variable\">--color-primary<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">oklch<\/span><span class=\"token punctuation\">(<\/span><span class=\"token number\">75<\/span><span class=\"token unit\">%<\/span> <span class=\"token number\">0.18<\/span> <span class=\"token number\">154<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span>\n<\/span><span class=\"code-line\">  <span class=\"token variable\">--color-secondary<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">oklch<\/span><span class=\"token punctuation\">(<\/span><span class=\"token number\">40<\/span><span class=\"token unit\">%<\/span> <span class=\"token number\">0.23<\/span> <span class=\"token number\">283<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span>\n<\/span><span class=\"code-line\">  <span class=\"token variable\">--color-error<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token function\">oklch<\/span><span class=\"token punctuation\">(<\/span><span class=\"token number\">54<\/span><span class=\"token unit\">%<\/span> <span class=\"token number\">0.22<\/span> <span class=\"token number\">29<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span>\n<\/span><span class=\"code-line\">\n<\/span><span class=\"code-line\">  <span class=\"token variable\">--spacing-sm<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token number\">4<\/span><span class=\"token unit\">px<\/span><span class=\"token punctuation\">;<\/span>\n<\/span><span class=\"code-line\">  <span class=\"token variable\">--spacing-md<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token number\">8<\/span><span class=\"token unit\">px<\/span><span class=\"token punctuation\">;<\/span>\n<\/span><span class=\"code-line\">  <span class=\"token variable\">--spacing-lg<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token number\">12<\/span><span class=\"token unit\">px<\/span><span class=\"token punctuation\">;<\/span>\n<\/span><span class=\"code-line\">\n<\/span><span class=\"code-line\">  <span class=\"token variable\">--breakpoint-sm<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token number\">640<\/span><span class=\"token unit\">px<\/span><span class=\"token punctuation\">;<\/span>\n<\/span><span class=\"code-line\">  <span class=\"token variable\">--breakpoint-md<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token number\">768<\/span><span class=\"token unit\">px<\/span><span class=\"token punctuation\">;<\/span>\n<\/span><span class=\"code-line\"><span class=\"token punctuation\">}<\/span>\n<\/span><\/code><\/pre>\n<pre class=\"language-js\"><code class=\"language-js code-highlight\"><span class=\"code-line\">\n<\/span><span class=\"code-line\">module<span class=\"token punctuation\">.<\/span><span class=\"token property-access\">exports<\/span> <span class=\"token operator\">=<\/span> <span class=\"token punctuation\">{<\/span>\n<\/span><span class=\"code-line\">  <span class=\"token literal-property property\">theme<\/span><span class=\"token operator\">:<\/span> <span class=\"token punctuation\">{<\/span>\n<\/span><span class=\"code-line\">    <span class=\"token literal-property property\">colors<\/span><span class=\"token operator\">:<\/span> <span class=\"token punctuation\">{<\/span>\n<\/span><span class=\"code-line\">      <span class=\"token literal-property property\">primary<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"oklch(75% 0.18 154)\"<\/span><span class=\"token punctuation\">,<\/span>\n<\/span><span class=\"code-line\">      <span class=\"token literal-property property\">secondary<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"oklch(40% 0.23 283)\"<\/span><span class=\"token punctuation\">,<\/span>\n<\/span><span class=\"code-line\">      <span class=\"token literal-property property\">error<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"oklch(54% 0.22 29)\"<\/span><span class=\"token punctuation\">,<\/span>\n<\/span><span class=\"code-line\">    <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">,<\/span>\n<\/span><span class=\"code-line\">    <span class=\"token literal-property property\">spacing<\/span><span class=\"token operator\">:<\/span> <span class=\"token punctuation\">{<\/span>\n<\/span><span class=\"code-line\">      <span class=\"token literal-property property\">sm<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"4px\"<\/span><span class=\"token punctuation\">,<\/span>\n<\/span><span class=\"code-line\">      <span class=\"token literal-property property\">md<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"8px\"<\/span><span class=\"token punctuation\">,<\/span>\n<\/span><span class=\"code-line\">      <span class=\"token literal-property property\">lg<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"12px\"<\/span><span class=\"token punctuation\">,<\/span>\n<\/span><span class=\"code-line\">    <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">,<\/span>\n<\/span><span class=\"code-line\">    <span class=\"token literal-property property\">screens<\/span><span class=\"token operator\">:<\/span> <span class=\"token punctuation\">{<\/span>\n<\/span><span class=\"code-line\">      <span class=\"token literal-property property\">sm<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"640px\"<\/span><span class=\"token punctuation\">,<\/span>\n<\/span><span class=\"code-line\">      <span class=\"token literal-property property\">md<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"768px\"<\/span><span class=\"token punctuation\">,<\/span>\n<\/span><span class=\"code-line\">    <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">,<\/span>\n<\/span><span class=\"code-line\">  <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">,<\/span>\n<\/span><span class=\"code-line\">  \n<\/span><span class=\"code-line\"><span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">;<\/span>\n<\/span><\/code><\/pre>\n<blockquote class=\"MarkdownInset-module--root--191ed Markdown-module--max--b7164\">\n<p>Here\u2019s another important thing: keeping a single semantic naming convention for your tokens will make it easier to find the necessary tokens and expand the system as the application grows.<\/p>\n<\/blockquote>\n<p>For example, to add a color for your error state, don\u2019t just copy and paste the <code class=\"language-text\">bright-red<\/code> token from your Figma file into your Tailwind configuration: put it into the colors section and give a more concise name like <code class=\"language-text\">error<\/code>. This will make the system much more consistent.<\/p>\n<h2 class=\"MarkdownHeading-module--root--01c0e Markdown-module--max--b7164\" id=\"3-keep-class-ordering\">3. Keep class ordering<\/h2>\n<p>Here\u2019s another clean coding convention: using a consistent order makes classes easier to read and understand. To illustrate, let\u2019s take a look at some HTML elements with unsorted classes:<\/p>\n<pre class=\"language-html\"><code class=\"language-html code-highlight\"><span class=\"code-line\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>div<\/span> <span class=\"token attr-name\">class<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=<\/span><span class=\"token punctuation\">\"<\/span>p-2 w-1\/2 flex bg-black h-2 font-bold<span class=\"token punctuation\">\"<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span>\n<\/span><span class=\"code-line\">  First block with unsorted classes\n<\/span><span class=\"code-line\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>div<\/span><span class=\"token punctuation\">&gt;<\/span><\/span>\n<\/span><span class=\"code-line\">\n<\/span><span class=\"code-line\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>div<\/span> <span class=\"token attr-name\">class<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=<\/span><span class=\"token punctuation\">\"<\/span>italic font-mono bg-white p-4 h-2 w-3 flex<span class=\"token punctuation\">\"<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span>\n<\/span><span class=\"code-line\">  Second block with unsorted classes\n<\/span><span class=\"code-line\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>div<\/span><span class=\"token punctuation\">&gt;<\/span><\/span>\n<\/span><\/code><\/pre>\n<p>In the blocks above, there are classes for different categories: dealing with the box model, display, typography, and so on\u2014but they don\u2019t have any sort of presentational order. We can apply a unified order to sort classes by categories:<\/p>\n<pre class=\"language-html\"><code class=\"language-html code-highlight\"><span class=\"code-line\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>div<\/span> <span class=\"token attr-name\">class<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=<\/span><span class=\"token punctuation\">\"<\/span>flex h-2 w-1\/2 bg-black p-2 font-bold<span class=\"token punctuation\">\"<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span>\n<\/span><span class=\"code-line\">  First block with sorted classes\n<\/span><span class=\"code-line\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>div<\/span><span class=\"token punctuation\">&gt;<\/span><\/span>\n<\/span><span class=\"code-line\">\n<\/span><span class=\"code-line\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>div<\/span> <span class=\"token attr-name\">class<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=<\/span><span class=\"token punctuation\">\"<\/span>flex h-2 w-3 bg-white p-4 font-mono italic<span class=\"token punctuation\">\"<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span>\n<\/span><span class=\"code-line\">  Second block with sorted classes\n<\/span><span class=\"code-line\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>div<\/span><span class=\"token punctuation\">&gt;<\/span><\/span>\n<\/span><\/code><\/pre>\n<p>Since maintaining class ordering manually requires a lot of time and attention, it\u2019s much better to automate this work using <a class=\"Link-module--root--de2eb Clickable-module--root--f3e4f\" href=\"https:\/\/github.com\/tailwindlabs\/prettier-plugin-tailwindcss\" target=\"_blank\" rel=\"noopener noreferrer\">the official Prettier plugin for Tailwind CSS<\/a>. To learn more about how to get started with it (and the methodology of how the classes are sorted), we recommend reading <a class=\"Link-module--root--de2eb Clickable-module--root--f3e4f\" href=\"https:\/\/tailwindcss.com\/blog\/automatic-class-sorting-with-prettier\" target=\"_blank\" rel=\"noopener noreferrer\">this article<\/a>.<\/p>\n<h2 class=\"MarkdownHeading-module--root--01c0e Markdown-module--max--b7164\" id=\"4-prevent-inconsistencies-when-overriding-and-extending-styles\">4. Prevent inconsistencies when overriding and extending styles<\/h2>\n<p>Imagine that we use a component with a custom button on our page:<\/p>\n<pre class=\"language-js\"><code class=\"language-js code-highlight\"><span class=\"code-line\"><span class=\"token operator\">&lt;<\/span><span class=\"token maybe-class-name\">Button<\/span> className<span class=\"token operator\">=<\/span><span class=\"token string\">\"bg-black\"<\/span> <span class=\"token operator\">\/<\/span><span class=\"token operator\">&gt;<\/span>\n<\/span><\/code><\/pre>\n<p>And we have a <code class=\"language-text\">Button<\/code> component that has some default style:<\/p>\n<pre class=\"language-js\"><code class=\"language-js code-highlight\"><span class=\"code-line\"><span class=\"token keyword module\">export<\/span> <span class=\"token keyword\">const<\/span> <span class=\"token function-variable function\"><span class=\"token maybe-class-name\">Button<\/span><\/span> <span class=\"token operator\">=<\/span> <span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token arrow operator\">=&gt;<\/span> <span class=\"token punctuation\">{<\/span>\n<\/span><span class=\"code-line\">  <span class=\"token keyword control-flow\">return<\/span> <span class=\"token operator\">&lt;<\/span>button className<span class=\"token operator\">=<\/span><span class=\"token string\">\"bg-white\"<\/span><span class=\"token operator\">&gt;<\/span><span class=\"token maybe-class-name\">Test<\/span> button<span class=\"token operator\">&lt;<\/span><span class=\"token operator\">\/<\/span>button<span class=\"token operator\">&gt;<\/span><span class=\"token punctuation\">;<\/span>\n<\/span><span class=\"code-line\"><span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">;<\/span>\n<\/span><\/code><\/pre>\n<p>In this case, the button will remain white since Tailwind doesn\u2019t automatically override style and apply the black color, so we need to specify it in the <code class=\"language-text\">Button<\/code> component:<\/p>\n<pre class=\"language-js\"><code class=\"language-js code-highlight\"><span class=\"code-line\"><span class=\"token keyword module\">export<\/span> <span class=\"token keyword\">const<\/span> <span class=\"token maybe-class-name\">Button<\/span> <span class=\"token operator\">=<\/span> <span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">{<\/span> className <span class=\"token operator\">=<\/span> <span class=\"token string\">\"bg-white\"<\/span> <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token arrow operator\">=&gt;<\/span> <span class=\"token punctuation\">{<\/span>\n<\/span><span class=\"code-line\">  <span class=\"token keyword control-flow\">return<\/span> <span class=\"token operator\">&lt;<\/span>button className<span class=\"token operator\">=<\/span><span class=\"token punctuation\">{<\/span>className<span class=\"token punctuation\">}<\/span><span class=\"token operator\">&gt;<\/span><span class=\"token maybe-class-name\">Test<\/span> button<span class=\"token operator\">&lt;<\/span><span class=\"token operator\">\/<\/span>button<span class=\"token operator\">&gt;<\/span><span class=\"token punctuation\">;<\/span>\n<\/span><span class=\"code-line\"><span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">;<\/span>\n<\/span><\/code><\/pre>\n<p>There\u2019s nothing inherently wrong about this aspect of Tailwind, but if we want to customize some appearance by overriding or extending a lot of styles, it can be cumbersome to pass classes via props each time.<\/p>\n<p>Moreover, there is one more drawback to this approach: accepting utilities via props can make it harder to ensure a consistent component view. This approach encourages using any utility combination for the same component across the app which can lead to a lack of visual consistency.<\/p>\n<p>So, what can we do with it?<\/p>\n<p>Instead of allowing any arbitrary utility classes to be passed via props, define a set of predefined variants:<\/p>\n<pre class=\"language-js\"><code class=\"language-js code-highlight\"><span class=\"code-line\"><span class=\"token keyword\">const<\/span> <span class=\"token constant\">BUTTON_VARIANTS<\/span> <span class=\"token operator\">=<\/span> <span class=\"token punctuation\">{<\/span>\n<\/span><span class=\"code-line\">  <span class=\"token literal-property property\">primary<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"bg-blue-500 hover:bg-blue-600 text-white\"<\/span><span class=\"token punctuation\">,<\/span>\n<\/span><span class=\"code-line\">  <span class=\"token literal-property property\">secondary<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"bg-gray-500 hover:bg-gray-600 text-white\"<\/span><span class=\"token punctuation\">,<\/span>\n<\/span><span class=\"code-line\">  <span class=\"token literal-property property\">danger<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"bg-red-500 hover:bg-red-600 text-white\"<\/span><span class=\"token punctuation\">,<\/span>\n<\/span><span class=\"code-line\"><span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">;<\/span>\n<\/span><\/code><\/pre>\n<p>Then, change the <code class=\"language-text\">Button<\/code> component so it can accept a <code class=\"language-text\">variant<\/code> prop. To make constructing <code class=\"language-text\">className<\/code> more convenient, you can use <a class=\"Link-module--root--de2eb Clickable-module--root--f3e4f\" href=\"https:\/\/github.com\/lukeed\/clsx\" target=\"_blank\" rel=\"noopener noreferrer\">clsx<\/a>:<\/p>\n<pre class=\"language-js\"><code class=\"language-js code-highlight\"><span class=\"code-line\"><span class=\"token keyword module\">export<\/span> <span class=\"token keyword\">const<\/span> <span class=\"token function-variable function\"><span class=\"token maybe-class-name\">Button<\/span><\/span> <span class=\"token operator\">=<\/span> <span class=\"token punctuation\">(<\/span><span class=\"token parameter\"><span class=\"token punctuation\">{<\/span> className<span class=\"token punctuation\">,<\/span> variant <span class=\"token operator\">=<\/span> <span class=\"token constant\">BUTTON_VARIANTS<\/span><span class=\"token punctuation\">.<\/span><span class=\"token property-access\">primary<\/span> <span class=\"token punctuation\">}<\/span><\/span><span class=\"token punctuation\">)<\/span> <span class=\"token arrow operator\">=&gt;<\/span> <span class=\"token punctuation\">{<\/span>\n<\/span><span class=\"code-line\">  <span class=\"token keyword control-flow\">return<\/span> <span class=\"token operator\">&lt;<\/span>button className<span class=\"token operator\">=<\/span><span class=\"token punctuation\">{<\/span><span class=\"token function\">clsx<\/span><span class=\"token punctuation\">(<\/span>className<span class=\"token punctuation\">,<\/span> variant<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">}<\/span><span class=\"token operator\">&gt;<\/span><span class=\"token maybe-class-name\">Test<\/span> <span class=\"token maybe-class-name\">Button<\/span><span class=\"token operator\">&lt;<\/span><span class=\"token operator\">\/<\/span>button<span class=\"token operator\">&gt;<\/span><span class=\"token punctuation\">;<\/span>\n<\/span><span class=\"code-line\"><span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">;<\/span>\n<\/span><\/code><\/pre>\n<p>Tip: using <code class=\"language-text\">clsx<\/code> would be also especially handy if you need to construct classes conditionally.<\/p>\n<p>After constructing <code class=\"language-text\">className<\/code> for the component, just use it, passing the desired variant:<\/p>\n<pre class=\"language-js\"><code class=\"language-js code-highlight\"><span class=\"code-line\"><span class=\"token operator\">&lt;<\/span><span class=\"token maybe-class-name\">Button<\/span> variant<span class=\"token operator\">=<\/span><span class=\"token string\">\"secondary\"<\/span> <span class=\"token operator\">\/<\/span><span class=\"token operator\">&gt;<\/span>\n<\/span><\/code><\/pre>\n<p>Now, consistency is ensured, and despite the fact that we added a restriction on full customization, flexibility remains; we can add any new variant for the component or edit an existing one.<\/p>\n<p>And the other benefit of this approach is that it allows for simpler maintenance: changes to utility classes can be made in one place, and then propagated to every component of that variant in the app.<\/p>\n<p>If for some reason you don\u2019t want to use the sets of predefined variants, you can try the package <a class=\"Link-module--root--de2eb Clickable-module--root--f3e4f\" href=\"https:\/\/github.com\/dcastil\/tailwind-merge\" target=\"_blank\" rel=\"noopener noreferrer\">tailwind-merge<\/a>, which provides utility function <code class=\"language-text\">twMerge<\/code> to merge Tailwind classes in JS without style conflicts. That said, it should be used carefully and only when necessary, since it is not the most lightweight and increases bundle size.<\/p>\n<h2 class=\"MarkdownHeading-module--root--01c0e Markdown-module--max--b7164\" id=\"5-minimize-build-size\">5. Minimize build size<\/h2>\n<p>Heavy CSS bundles mean slow-loading pages and frustrated users, so it\u2019s worth making sure your production CSS is properly minified.<\/p>\n<p><strong class=\"MarkdownStrong-module--root--fab94\">TL;DR:<\/strong> if you\u2019re on <strong class=\"MarkdownStrong-module--root--fab94\">Tailwind v4<\/strong>, you don\u2019t need to do anything\u2014minification is automatic. If you\u2019re on <strong class=\"MarkdownStrong-module--root--fab94\">Tailwind v3<\/strong>, you\u2019ll need to set it up yourself.<\/p>\n<h3 class=\"MarkdownHeading-module--root--01c0e Markdown-module--max--b7164\" id=\"tailwind-v4-nothing-to-configure\">Tailwind v4: nothing to configure<\/h3>\n<p>Minification is handled automatically. Tailwind v4 is built on Lightning CSS, a Rust-based CSS parser and transformer, which handles parsing, vendor prefixing, and minification all in a single pass. This means you don\u2019t need a separate minifier or autoprefixer in your build pipeline.<\/p>\n<h3 class=\"MarkdownHeading-module--root--01c0e Markdown-module--max--b7164\" id=\"tailwind-v3-set-up-minification\">Tailwind v3: set up minification<\/h3>\n<p>Minification removes all unnecessary characters (like whitespace, comments, and so on) and this will noticeably reduce file size.<\/p>\n<aside class=\"MarkdownSidenote-module--root--21525 Markdown-module--aside--e9b55\" role=\"note\"\/>\n<p>Using the CLI, this can be done by setting the <code class=\"language-text\">--minify<\/code> flag:<\/p>\n<p><code class=\"language-text\">npx tailwindcss -o build.css --minify<\/code><\/p>\n<p>If you\u2019ve installed Tailwind as a PostCSS plugin instead, you can add <a class=\"Link-module--root--de2eb Clickable-module--root--f3e4f\" href=\"https:\/\/cssnano.co\" target=\"_blank\" rel=\"noopener noreferrer\">cssnano<\/a> to your plugin list for minification.<\/p>\n<p>If you don\u2019t consider optimization, the size of your CSS can end up really big (more than several tens of kilobytes). Even in a small project with a few components with styles, there is a meaningful size difference after minifying CSS.<\/p>\n<p>If you want to learn more about minification and compression for Tailwind v3, <a class=\"Link-module--root--de2eb Clickable-module--root--f3e4f\" href=\"https:\/\/tailwindcss.com\/docs\/optimizing-for-production\" target=\"_blank\" rel=\"noopener noreferrer\">check this section of the documentation<\/a>.<\/p>\n<h2 class=\"MarkdownHeading-module--root--01c0e Markdown-module--max--b7164\" id=\"summing-up-how-to-use-and-how-not-to-use-tailwind\">Summing up: how to use (and how not to use) Tailwind<\/h2>\n<p>Tailwind is a powerful tool, but it\u2019s important to use it while following some rules to prevent chaos from erupting in your project. Let\u2019s sum up the above principles.<\/p>\n<p>First, to get the most out of these practices, you should use Tailwind when you already have a design system and consistent design tokens and have opted for a component-based approach. Without breaking reusable elements into components, using Tailwind will become painful sooner or later, leading to repetitive or verbose HTML structures.<\/p>\n<ol class=\"MarkdownOL-module--root--75052\">\n<li class=\"MarkdownLI-module--root--d3fdc\">Minimize the number of utility classes where possible<\/li>\n<li class=\"MarkdownLI-module--root--d3fdc\">Formulate code conventions within your team, for example, by grouping design tokens and naming them semantically<\/li>\n<li class=\"MarkdownLI-module--root--d3fdc\">Likewise, implement consistent class ordering and set up linters to ensure code cleanliness<\/li>\n<li class=\"MarkdownLI-module--root--d3fdc\">When appropriate, try to define a set of predefined variants for your components; this will help avoid problems with inconsistencies and style overriding<\/li>\n<li class=\"MarkdownLI-module--root--d3fdc\">Minimize your bundle sizes: if you\u2019re still on Tailwind v3, always minify the final CSS for your production build<\/li>\n<\/ol>\n<p>By following these rules, you\u2019ll be able to use Tailwind for the long haul, with pleasure and without problems, all while giving your team the chance to revel in all the benefits it provides.<\/p>\n<div class=\"MarkdownHR-module--root--bee14\" role=\"separator\"><img decoding=\"async\" src=\"data:image\/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMzAiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAxMzAgMjQiPgogICAgPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNNDUgMGExIDEgMCAwIDAtMSAxdjExYTEgMSAwIDEgMCAyIDBWMWExIDEgMCAwIDAtMS0xek0xMiAxMGExIDEgMCAxIDEgMiAwdjJhMSAxIDAgMSAxLTIgMHYtMnptLTQgMmExIDEgMCAxIDEgMiAwIDEgMSAwIDAgMS0yIDB6bTktMWExIDEgMCAxIDAgMCAyIDEgMSAwIDAgMCAwLTJ6bTcgMWExIDEgMCAxIDEgMiAwIDEgMSAwIDAgMS0yIDB6bTktMWExIDEgMCAxIDAgMCAyIDEgMSAwIDAgMCAwLTJ6bTcgMWExIDEgMCAxIDEgMiAwIDEgMSAwIDAgMS0yIDB6bTktMWExIDEgMCAxIDAgMCAyIDEgMSAwIDAgMCAwLTJ6bTcgMWExIDEgMCAxIDEgMiAwIDEgMSAwIDAgMS0yIDB6bTUtMWExIDEgMCAxIDAgMCAyIDEgMSAwIDAgMCAwLTJ6bTcgMWExIDEgMCAxIDEgMiAwIDEgMSAwIDAgMS0yIDB6bTktMWExIDEgMCAxIDAgMCAyIDEgMSAwIDAgMCAwLTJ6bTMgMWExIDEgMCAxIDEgMiAwIDEgMSAwIDAgMS0yIDB6bTktMWExIDEgMCAxIDAgMCAyIDEgMSAwIDAgMCAwLTJ6bTcgMWExIDEgMCAxIDEgMiAwIDEgMSAwIDAgMS0yIDB6bTktMWExIDEgMCAxIDAgMCAyIDEgMSAwIDAgMCAwLTJ6bTcgMWExIDEgMCAxIDEgMiAwIDEgMSAwIDAgMS0yIDB6bTktMWExIDEgMCAxIDAgMCAyIDEgMSAwIDAgMCAwLTJ6bTMgMWExIDEgMCAxIDEgMiAwIDEgMSAwIDAgMS0yIDB6bTUtMWExIDEgMCAxIDAgMCAyIDEgMSAwIDAgMCAwLTJ6TTQgMTJhMSAxIDAgMSAxIDIgMCAxIDEgMCAwIDEtMiAwem0tMy0xYTEgMSAwIDEgMCAwIDIgMSAxIDAgMCAwIDAtMnptMTkgMWExIDEgMCAxIDEgMiAwdjNhMSAxIDAgMSAxLTIgMHYtM3ptOSAwYTEgMSAwIDAgMC0xIDF2MWExIDEgMCAxIDAgMiAwdi0xYTEgMSAwIDAgMC0xLTF6bTcgMGExIDEgMCAxIDEgMiAwdjNhMSAxIDAgMSAxLTIgMHYtM3ptMTctMWExIDEgMCAwIDAtMSAxdjdhMSAxIDAgMSAwIDIgMHYtN2ExIDEgMCAwIDAtMS0xem0xOSAxYTEgMSAwIDEgMSAyIDB2MTFhMSAxIDAgMSAxLTIgMFYxMnptMjEtMWExIDEgMCAwIDAtMSAxdjRhMSAxIDAgMSAwIDIgMHYtNGExIDEgMCAwIDAtMS0xem0xNSAxYTEgMSAwIDAgMSAyIDB2MmExIDEgMCAwIDEtMiAwdi0yek02NCA3YTEgMSAwIDEgMSAyIDB2NWExIDEgMCAxIDEtMiAwVjd6bTIxLTFhMSAxIDAgMCAwLTEgMXY1YTEgMSAwIDEgMCAyIDBWN2ExIDEgMCAwIDAtMS0xem0xNSAzYTEgMSAwIDAgMSAyIDB2M2ExIDEgMCAwIDEtMiAwVjl6bTE3IDJhMSAxIDAgMSAwIDAgMiAxIDEgMCAwIDAgMC0yeiIgY2xpcC1ydWxlPSJldmVub2RkIi8+Cjwvc3ZnPgo=\" alt=\"Radio wave representing wind sounds on Mars\" aria-hidden=\"true\" class=\"ariaHidden\" loading=\"lazy\"\/><\/div>\n<div id=\"skill-tailwind-best-practices\" class=\"MarkdownAgentSkillReference-module--anchor--ad2aa\">\n<aside class=\"MarkdownAgentSkillReference-module--root--98bb8\" style=\"--rgb-theme-logo:62 0 53;--oklch-theme-logo:24.3300% 0.1190 335.4300;--opacity-theme-logo:11.08%;--switch-theme-logo:1;--rgb-theme-title:62 0 53;--oklch-theme-title:24.3300% 0.1190 335.4300;--opacity-theme-title:11.08%;--rgb-theme-navigation:62 0 53;--oklch-theme-navigation:24.3300% 0.1190 335.4300;--opacity-theme-navigation:11.08%;--rgb-theme-text:255 239 255;--oklch-theme-text:97.0000% 0.0296 328.0000;--opacity-theme-text:29.25%;--rgb-theme-button:62 0 53;--oklch-theme-button:24.3300% 0.1190 335.4300;--opacity-theme-button:11.08%;--rgb-theme-background:87 185 225;--oklch-theme-background:74.2774% 0.1080 227.7094;--opacity-theme-background:100%\" data-with-theme=\"true\">\n<div class=\"MarkdownAgentSkillReference-module--label--eb402\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"24\" height=\"24\" fill=\"none\" viewbox=\"0 0 24 24\" class=\"Icon-module--icon24--b74c8 MarkdownAgentSkillReference-module--labelIcon--f66ca ariaHidden\" aria-hidden=\"true\"><path fill=\"currentColor\" d=\"M22.586 4c-.965 0-1.517-.552-1.517-1.517A.471.471 0 0 0 20.586 2a.471.471 0 0 0-.483.483c0 .551.138 1.034.345 1.448l-1.31 1.38c-1.035-.828-2.345-1.242-4.069-1.242h-6c-1.724 0-3.035.414-4.069 1.241L3.69 4c.276-.414.344-.897.344-1.448 0-.345-.275-.552-.551-.552S3 2.207 3 2.483C3 3.448 2.448 4 1.483 4 1.207 4 1 4.207 1 4.483s.207.483.483.483c.551 0 1.034-.138 1.448-.345l1.38 1.31C3.482 6.966 3.068 8.276 3.068 10v8.552A3.415 3.415 0 0 0 6.517 22h11.035A3.415 3.415 0 0 0 21 18.552V10c0-1.724-.414-3.034-1.241-4.069l1.31-1.31c.414.276.897.345 1.448.345.276 0 .483-.207.483-.483S22.862 4 22.586 4zM8.931 16.483c-1.31 0-2.414-1.104-2.414-2.414s1.104-2.414 2.414-2.414 2.414 1.104 2.414 2.414-1.104 2.414-2.414 2.414zm6.207 0c-1.31 0-2.414-1.104-2.414-2.414s1.104-2.414 2.414-2.414 2.414 1.104 2.414 2.414-1.104 2.414-2.414 2.414z\"\/><path fill=\"currentColor\" fill-rule=\"evenodd\" d=\"M15.113 13.156a.956.956 0 1 0 0 1.913.956.956 0 0 0 0-1.913zm-1.457.956a1.456 1.456 0 1 1 2.913 0 1.456 1.456 0 0 1-2.913 0zm-4.7-.956a.956.956 0 1 0 0 1.913.956.956 0 0 0 0-1.913zm-1.456.957a1.456 1.456 0 1 1 2.913 0 1.456 1.456 0 0 1-2.913 0z\" clip-rule=\"evenodd\"\/><\/svg>Install this skill in your agent<\/div>\n<div class=\"MarkdownAgentSkillReference-module--summary--2db88\">\n<h3 class=\"MarkdownAgentSkillReference-module--title--32370\">tailwind-best-practices<\/h3>\n<p class=\"MarkdownAgentSkillReference-module--description--6ef5f\">Writes and audits Tailwind CSS with the five practices that keep a fast-to-write codebase maintainable: design tokens over magic values, short and consistently ordered class lists, semantically grouped tokens, and fixed variants for design-system components instead of arbitrary className props.<\/p>\n<\/div>\n<div class=\"AgentSkillActions-module--root--a7cc4\">\n<p><button class=\"Button-module--root--c1f31 Button-module--size_sm--63d55 Button-module--variant_solid--d7dbc Button-module--theme_current_text--4627d Button-module--hoverable--69e49 Clickable-module--root--f3e4f\" type=\"button\" tabindex=\"0\" role=\"tab\" aria-selected=\"true\">Claude Code<\/button><button class=\"Button-module--root--c1f31 Button-module--size_sm--63d55 Button-module--variant_translucent--d26fb Button-module--theme_current_text--4627d Button-module--hoverable--69e49 Clickable-module--root--f3e4f\" type=\"button\" tabindex=\"0\" role=\"tab\" aria-selected=\"false\">Cursor<\/button><button class=\"Button-module--root--c1f31 Button-module--size_sm--63d55 Button-module--variant_translucent--d26fb Button-module--theme_current_text--4627d Button-module--hoverable--69e49 Clickable-module--root--f3e4f\" type=\"button\" tabindex=\"0\" role=\"tab\" aria-selected=\"false\">Codex<\/button><button class=\"Button-module--root--c1f31 Button-module--size_sm--63d55 Button-module--variant_translucent--d26fb Button-module--theme_current_text--4627d Button-module--hoverable--69e49 Clickable-module--root--f3e4f\" type=\"button\" tabindex=\"0\" role=\"tab\" aria-selected=\"false\">GitHub Copilot<\/button><button class=\"Button-module--root--c1f31 Button-module--size_sm--63d55 Button-module--variant_translucent--d26fb Button-module--theme_current_text--4627d Button-module--hoverable--69e49 Clickable-module--root--f3e4f\" type=\"button\" tabindex=\"0\" role=\"tab\" aria-selected=\"false\">Gemini CLI<\/button><\/p>\n<p><button class=\"Button-module--root--c1f31 Button-module--size_sm--63d55 Button-module--variant_solid--d7dbc Button-module--theme_current_text--4627d Button-module--hoverable--69e49 Clickable-module--root--f3e4f\" type=\"button\" tabindex=\"0\" role=\"tab\" aria-selected=\"true\">npx skills<\/button><button class=\"Button-module--root--c1f31 Button-module--size_sm--63d55 Button-module--variant_translucent--d26fb Button-module--theme_current_text--4627d Button-module--hoverable--69e49 Clickable-module--root--f3e4f\" type=\"button\" tabindex=\"0\" role=\"tab\" aria-selected=\"false\">claude plugin<\/button><button class=\"Button-module--root--c1f31 Button-module--size_sm--63d55 Button-module--variant_translucent--d26fb Button-module--theme_current_text--4627d Button-module--hoverable--69e49 Clickable-module--root--f3e4f\" type=\"button\" tabindex=\"0\" role=\"tab\" aria-selected=\"false\">gh skill<\/button><button class=\"Button-module--root--c1f31 Button-module--size_sm--63d55 Button-module--variant_translucent--d26fb Button-module--theme_current_text--4627d Button-module--hoverable--69e49 Clickable-module--root--f3e4f\" type=\"button\" tabindex=\"0\" role=\"tab\" aria-selected=\"false\">curl<\/button><\/p>\n<div class=\"AgentSkillActions-module--commandRow--8e2a4\"><code class=\"AgentSkillActions-module--command--1ed25\">npx skills add https:\/\/evilmartians.com\/agent-skills --skill tailwind-best-practices -a claude-code -g<\/code><button class=\"Button-module--root--c1f31 Button-module--size_sm--63d55 Button-module--variant_translucent--d26fb Button-module--theme_current_text--4627d AgentSkillActions-module--copy--2d5b3 Button-module--hoverable--69e49 Clickable-module--root--f3e4f\" type=\"button\" aria-label=\"Copy install command\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"16\" height=\"16\" fill=\"none\" viewbox=\"0 0 16 16\" class=\"Icon-module--icon16--25a2c ariaHidden\" aria-hidden=\"true\"><path stroke=\"currentColor\" d=\"M5.5 5.5h8v8h-8z\"\/><path d=\"M10.5 5.5v-3h-8v8h3\" stroke=\"currentColor\"\/><\/svg><\/button><\/div>\n<\/div>\n<\/aside>\n<\/div>\n<\/div>\n<p><a href=\"https:\/\/evilmartians.com\/chronicles\/5-best-practices-for-preventing-chaos-in-tailwind-css?utm_source=tldrdev\">Source link <\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Working with Tailwind CSS is pretty fast and easy (that\u2019s why it\u2019s received such wide recognition). You just paste a list of different classes in your HTML\u2014and your interface immediately becomes attractive! But, as the application grows, the lists of classes grow. Then, one day you realize you can\u2019t understand your code, you\u2019re confused with [&hellip;]<\/p>\n","protected":false},"author":16,"featured_media":23125,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[143],"tags":[],"class_list":["post-23124","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-ai"],"_links":{"self":[{"href":"https:\/\/scannn.com\/lv\/wp-json\/wp\/v2\/posts\/23124","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/scannn.com\/lv\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/scannn.com\/lv\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/scannn.com\/lv\/wp-json\/wp\/v2\/users\/16"}],"replies":[{"embeddable":true,"href":"https:\/\/scannn.com\/lv\/wp-json\/wp\/v2\/comments?post=23124"}],"version-history":[{"count":0,"href":"https:\/\/scannn.com\/lv\/wp-json\/wp\/v2\/posts\/23124\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/scannn.com\/lv\/wp-json\/wp\/v2\/media\/23125"}],"wp:attachment":[{"href":"https:\/\/scannn.com\/lv\/wp-json\/wp\/v2\/media?parent=23124"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/scannn.com\/lv\/wp-json\/wp\/v2\/categories?post=23124"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/scannn.com\/lv\/wp-json\/wp\/v2\/tags?post=23124"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}