| | |

Prettier 26 ๐ŸŽจ prettier-plugin-tailwindcss โ€” Class sorting for Tailwind

โฑ๏ธ Estimated read: 11 min | |

The prettier-plugin-tailwindcss plugin does one thing: it sorts Tailwind CSS classes in the order that Tailwind’s own tooling recommends. It is not a linter, and it does not detect unused or conflicting classes. It reads the class strings in your markupโ€”the class attribute, the framework-specific equivalents like className, and the function calls you configureโ€”and rewrites them so that the order is consistent across the codebase . The plugin was built by the Tailwind Labs team, and it is the official sorting mechanism that the Tailwind documentation points to.

The plugin’s value is the elimination of order debates. Two developers can write the same set of classes in different orders, and the rendered result is identical, but the diffs are noisy and the code review comments are about preference rather than substance. The plugin makes the order deterministic, which means the diff is empty when the classes are the same and the review is about the classes that actually changed. The sorting is based on Tailwind’s recommended order, which is the order that the Tailwind team uses in its own documentation and examples .

Key point: The plugin requires Prettier v3 and is ESM-only as of v0.5.x. It needs access to the Tailwind configurationโ€”tailwindStylesheet for Tailwind v4, tailwindConfig for Tailwind v3โ€”to sort custom classes correctly. It sorts the class attribute and the framework equivalents by default, and the tailwindAttributes and tailwindFunctions options extend the scope to custom attributes and function calls.


Why the plugin exists

The order-consistency problem. Tailwind’s utility classes are order-independent in the CSS output. flex p-4 and p-4 flex produce the same styles. But the source code is read by humans, and a consistent order makes the classes easier to scan. The plugin enforces the order that Tailwind’s own documentation uses, which means the codebase matches the examples that developers learn from. The plugin’s README states that it sorts “based on our recommended class order” .

The configuration-access problem. A project that customizes Tailwindโ€”a custom color, a custom spacing scale, a custom utilityโ€”needs the plugin to know about those customizations, or the sorting will place the custom classes in the wrong position. The plugin reads the Tailwind configuration to build the sort order. For Tailwind v3, the configuration is the tailwind.config.js file, and the tailwindConfig option points to it. For Tailwind v4, the configuration lives in the CSS entry point, and the tailwindStylesheet option points to it . Without the configuration, the plugin falls back to the default Tailwind order, and the custom classes are sorted as if they were unknown.

The ESM-only constraint. As of v0.5.x, the plugin requires Prettier v3 and is ESM-only. It cannot be loaded with require(). A CommonJS Prettier configuration must either switch to the ESM syntax or use a dynamic import. The migration guide in the plugin’s repository explains the upgrade path . The constraint is a consequence of Prettier 3’s ESM-first design, and it is the first thing to check when the plugin does not load.

The trade-off. The plugin adds a dependency and a Prettier configuration entry. The dependency is a dev dependency, and the configuration entry is a single line in .prettierrc. The plugin runs during prettier --write and during the editor’s format-on-save, so the sorting is applied consistently. The cost is the dependency and the configuration, and the benefit is the elimination of the order inconsistency.


a. The installation and the configuration

The installation is two packages: Prettier and the plugin. The plugin is a dev dependency.

# Install Prettier and the plugin.
npm install -D prettier prettier-plugin-tailwindcss

The configuration is a plugins entry in .prettierrc. The plugin is added to the array, and Prettier loads it when it runs.

// .prettierrc โ€” the plugin configuration
{
  "plugins": ["prettier-plugin-tailwindcss"]
}

The JavaScript configuration form is the alternative, and it provides the type hints for the plugin options.

// prettier.config.js โ€” the typed configuration
/** @type {import('prettier').Config & import('prettier-plugin-tailwindcss').PluginOptions} */
export default {
  plugins: ["prettier-plugin-tailwindcss"],
};

The plugin’s README states that the configuration is the plugins array, and the JavaScript form is the one that provides the IntelliSense for the plugin’s options . The .prettierrc form is the simpler one for a project that does not need the types.


b. The Tailwind configuration options

The plugin needs the Tailwind configuration to sort custom classes correctly. The option differs between Tailwind v3 and Tailwind v4.

// .prettierrc โ€” Tailwind v4
{
  "plugins": ["prettier-plugin-tailwindcss"],
  "tailwindStylesheet": "./resources/css/app.css"
}

For Tailwind v4, the tailwindStylesheet option points to the CSS file that contains the @import "tailwindcss" and the @theme block. The path is resolved relative to the Prettier configuration file . The CSS file is the entry point that includes the theme and the custom utilities, and the plugin reads it to build the sort order.

// .prettierrc โ€” Tailwind v3
{
  "plugins": ["prettier-plugin-tailwindcss"],
  "tailwindConfig": "./styles/tailwind.config.js"
}

For Tailwind v3, the tailwindConfig option points to the tailwind.config.js file. The path is resolved relative to the Prettier configuration file. If the file is not found, the plugin falls back to the default Tailwind configuration . The fallback is the reason a project with a custom configuration may see the custom classes sorted incorrectly: the plugin did not find the configuration, and it used the default order.


c. The custom attributes and function calls

The plugin sorts the class attribute and the framework-specific equivalentsโ€”className in React, :class in Vue, [ngClass] in Angularโ€”by default. The tailwindAttributes option extends the scope to custom attributes.

// .prettierrc โ€” the custom attributes
{
  "plugins": ["prettier-plugin-tailwindcss"],
  "tailwindAttributes": ["myClassList", "/data-.*/"]
}

The tailwindAttributes array accepts attribute names and regular expressions. The regex pattern is enclosed in forward slashes, and the plugin sorts any attribute that matches . The pattern /data-.*/ matches every attribute that starts with data-, which is the mechanism for a project that stores classes in data attributes.

The tailwindFunctions option extends the scope to function calls and tagged template literals. The array lists the function names that the plugin should treat as class-list containers.

// .prettierrc โ€” the function calls
{
  "plugins": ["prettier-plugin-tailwindcss"],
  "tailwindFunctions": ["clsx", "tw"]
}

The clsx function is the common case: the plugin sorts the string arguments and the object keys that are passed to clsx() . The tw function is the tagged template case: the plugin sorts the classes inside the template literal that is tagged with tw . The tagged template pattern is the one that twrnc and similar libraries use, and the tailwindFunctions option is the mechanism that tells the plugin to treat the tag as a class list.


Complete Example Session

// ============================================
// PART 1: THE INSTALLATION
// ============================================

// npm install -D prettier prettier-plugin-tailwindcss

// ============================================
// PART 2: THE BASIC CONFIGURATION
// ============================================

// .prettierrc
{
  "plugins": ["prettier-plugin-tailwindcss"]
}

// The plugin sorts the class attribute and the
// framework-specific equivalents.

// ============================================
// PART 3: THE TAILWIND V4 CONFIGURATION
// ============================================

// .prettierrc
{
  "plugins": ["prettier-plugin-tailwindcss"],
  "tailwindStylesheet": "./src/styles/global.css"
}

// The tailwindStylesheet points to the CSS entry point.
// The plugin reads the theme and custom utilities.

// ============================================
// PART 4: THE TAILWIND V3 CONFIGURATION
// ============================================

// .prettierrc
{
  "plugins": ["prettier-plugin-tailwindcss"],
  "tailwindConfig": "./styles/tailwind.config.js"
}

// The tailwindConfig points to the JavaScript config.
// The plugin reads the custom colors and spacing.

// ============================================
// PART 5: THE CUSTOM ATTRIBUTES
// ============================================

// .prettierrc
{
  "plugins": ["prettier-plugin-tailwindcss"],
  "tailwindAttributes": ["myClassList", "/data-.*/"]
}

// The plugin sorts the myClassList attribute
// and any attribute that starts with data-.

// ============================================
// PART 6: THE FUNCTION CALLS
// ============================================

// .prettierrc
{
  "plugins": ["prettier-plugin-tailwindcss"],
  "tailwindFunctions": ["clsx"]
}

// The plugin sorts the classes inside clsx() calls.
import clsx from 'clsx';
const classes = clsx('rounded bg-blue-500 px-4 py-2 text-base text-white');

// The output is the sorted order.

// ============================================
// PART 7: THE TAGGED TEMPLATE
// ============================================

// .prettierrc
{
  "plugins": ["prettier-plugin-tailwindcss"],
  "tailwindFunctions": ["tw"]
}

// The plugin sorts the classes inside tw`...`.
import tw from 'twrnc';
const classes = tw`bg-white p-4 dark:bg-black`;

// The output is the sorted order.

// ============================================
// PART 8: THE ESM CONSTRAINT
// ============================================

// As of v0.5.x, the plugin requires Prettier v3.
// The plugin is ESM-only.
// A CommonJS config must use the ESM syntax or dynamic import.

// ============================================
// PART 9: THE COMPATIBILITY
// ============================================

// The plugin is incompatible with some other Prettier plugins
// that use the same Prettier APIs.
// The plugin's README lists the workarounds.
// The plugin must be loaded last in the plugins array.

// ============================================
// PART 10: THE VERIFICATION
// ============================================

// [ ] The plugin is installed as a dev dependency.
// [ ] The plugin is in the Prettier plugins array.
// [ ] The tailwindStylesheet (v4) or tailwindConfig (v3) is set.
// [ ] The tailwindAttributes are set for custom attributes.
// [ ] The tailwindFunctions are set for function calls.
// [ ] The plugin is loaded last if other plugins are used.
// [ ] The Prettier version is v3 or later.

The ten parts covered the installation, the basic configuration, the Tailwind v4 configuration, the Tailwind v3 configuration, the custom attributes, the function calls, the tagged template, the ESM constraint, the compatibility, and the verification. The through-line is that the plugin is a sorting mechanism, and the configuration is the scope of the sorting.


Quick Reference

The installation

PackageCommand
Prettier + pluginnpm install -D prettier prettier-plugin-tailwindcss

The configuration options

OptionTailwind versionPurpose
pluginsBothThe plugin entry
tailwindStylesheetv4The CSS entry point
tailwindConfigv3The JS config path
tailwindAttributesBothCustom attributes
tailwindFunctionsBothFunction calls

The ESM constraint

VersionRequirement
v0.5.x+Prettier v3, ESM-only
OlderPrettier v2, CommonJS

Best Practices

โœ… Do This:

// Set the Tailwind configuration path
"tailwindStylesheet": "./src/styles/global.css"                  // โœ…
// Extend the scope to custom attributes
"tailwindAttributes": ["myClassList", "/data-.*/"]               // โœ…
// Extend the scope to function calls
"tailwindFunctions": ["clsx", "tw"]                              // โœ…

โŒ Don’t Do This:

// Use require() with the ESM-only plugin
const plugin = require('prettier-plugin-tailwindcss');           // โŒ
// Omit the Tailwind configuration path
// The custom classes are sorted with the default order.        // โŒ

Common Pitfalls

PitfallWhy It HappensFix
The plugin does not loadPrettier v2 or CommonJS configUse Prettier v3 and ESM
The custom classes are not sortedThe Tailwind config is not foundSet tailwindStylesheet or tailwindConfig
The classes are not sorted in a custom attributeThe attribute is not in tailwindAttributesAdd the attribute name or regex
The classes are not sorted in clsx()The function is not in tailwindFunctionsAdd the function name
The plugin conflicts with another pluginThe plugin must be loaded lastPut it last in the plugins array

Real-World Examples

1. The basic config

{ "plugins": ["prettier-plugin-tailwindcss"] }

2. The Tailwind v4 config

{ "plugins": ["prettier-plugin-tailwindcss"], "tailwindStylesheet": "./src/app.css" }

3. The Tailwind v3 config

{ "plugins": ["prettier-plugin-tailwindcss"], "tailwindConfig": "./tailwind.config.js" }

4. The custom attribute

{ "tailwindAttributes": ["myClassList"] }

5. The regex attribute

{ "tailwindAttributes": ["/data-.*/"] }

6. The function call

{ "tailwindFunctions": ["clsx"] }

7. The tagged template

{ "tailwindFunctions": ["tw"] }

8. The ESM config

/** @type {import('prettier').Config & import('prettier-plugin-tailwindcss').PluginOptions} */
export default { plugins: ["prettier-plugin-tailwindcss"] };

9. The plugin order

{ "plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"] }

10. The sorting

// Before: <div className="p-4 flex bg-white" />
// After:  <div className="flex bg-white p-4" />

Visual

The Plugin’s Scope

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  WHAT THE PLUGIN SORTS                                        โ”‚
โ”‚                                                              โ”‚
โ”‚  Default:                                                    โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                                    โ”‚
โ”‚  โ”‚ class attribute     โ”‚                                    โ”‚
โ”‚  โ”‚ className (React)   โ”‚                                    โ”‚
โ”‚  โ”‚ :class (Vue)        โ”‚                                    โ”‚
โ”‚  โ”‚ [ngClass] (Angular) โ”‚                                    โ”‚
โ”‚  โ”‚ @apply directives   โ”‚                                    โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                                    โ”‚
โ”‚                                                              โ”‚
โ”‚  Extended:                                                   โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                                    โ”‚
โ”‚  โ”‚ tailwindAttributes  โ”‚  Custom attributes                 โ”‚
โ”‚  โ”‚ tailwindFunctions   โ”‚  Function calls and templates      โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                                    โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

The Configuration Path

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  THE PLUGIN NEEDS THE TAILWIND CONFIG                         โ”‚
โ”‚                                                              โ”‚
โ”‚  Tailwind v4:                                                โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                                    โ”‚
โ”‚  โ”‚ tailwindStylesheet  โ”‚  โ†’ ./src/app.css                   โ”‚
โ”‚  โ”‚                     โ”‚  The CSS entry point               โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                                    โ”‚
โ”‚                                                              โ”‚
โ”‚  Tailwind v3:                                                โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                                    โ”‚
โ”‚  โ”‚ tailwindConfig      โ”‚  โ†’ ./tailwind.config.js            โ”‚
โ”‚  โ”‚                     โ”‚  The JS config                     โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                                    โ”‚
โ”‚                                                              โ”‚
โ”‚  Without the config, the custom classes are sorted           โ”‚
โ”‚  with the default order.                                    โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

The ESM Constraint

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  v0.5.x REQUIRES PRETTIER v3 AND ESM                          โ”‚
โ”‚                                                              โ”‚
โ”‚  โœ… ESM config:                                               โ”‚
โ”‚  export default { plugins: ["prettier-plugin-tailwindcss"] } โ”‚
โ”‚                                                              โ”‚
โ”‚  โŒ CommonJS config:                                          โ”‚
โ”‚  module.exports = { plugins: [require("...")] }              โ”‚
โ”‚                                                              โ”‚
โ”‚  The plugin cannot be loaded via require().                 โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Summary

ItemValue
Packageprettier-plugin-tailwindcss
RequiresPrettier v3, ESM-only (v0.5.x+)
Default scopeclass, className, :class, [ngClass], @apply
Tailwind v4 optiontailwindStylesheet
Tailwind v3 optiontailwindConfig
Custom attributestailwindAttributes
Function callstailwindFunctions
Plugin orderMust be last if other plugins are used

Key takeaways:

  • The plugin sorts classes in Tailwind’s recommended order. It is the official sorting mechanism, and it eliminates the order inconsistency that makes diffs noisy and reviews about preference rather than substance .
  • The plugin needs the Tailwind configuration. For Tailwind v4, the tailwindStylesheet option points to the CSS entry point. For Tailwind v3, the tailwindConfig option points to the JavaScript config. Without the configuration, the custom classes are sorted with the default order .
  • The tailwindAttributes option extends the scope to custom attributes. The array accepts attribute names and regular expressions. The regex pattern is enclosed in forward slashes .
  • The tailwindFunctions option extends the scope to function calls and tagged templates. The clsx function is the common case, and the tw tag is the tagged template case .
  • The plugin is ESM-only as of v0.5.x. It requires Prettier v3, and it cannot be loaded with require(). A CommonJS configuration must switch to the ESM syntax or use a dynamic import .

Remember: The prettier-plugin-tailwindcss plugin is a sorting mechanism, not a linter. It reads the class strings and rewrites them in Tailwind’s recommended order. The configuration is the scope: the tailwindStylesheet or tailwindConfig tells the plugin where the custom classes are defined, and the tailwindAttributes and tailwindFunctions options tell it where the class strings live. The plugin is ESM-only, and it must be loaded last if other Prettier plugins are used. The sorting is applied during prettier --write and during format-on-save, and the result is a codebase where the class order is consistent and the diffs are about substance.

Was this helpful?


Stop using slow, ad-bloated tool sites! ๐Ÿคฎ

๐Ÿ”Ž Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
โœ… Finance (Mortgage, Interest, Inflation)
โœ… Tech (Base64, JSON, Dev Suite, IP)
โœ… Health (BMI, BMR, TDEE)
โœ… Productivity (Timer, Workspace, QR)

โšก๏ธ Fast & Private
๐Ÿ”’ No data leaves your device
๐Ÿ’Ž 100% Free

๐Ÿ”— Use it now: https://tools.kandz.me
๐Ÿ”– Bookmark itโ€”youโ€™ll need it later!