prettier-plugin-tailwindcss: what it sorts, what it quietly skips, and how it fails
A Prettier plugin for Tailwind CSS that automatically sorts classes based on our recommended class order.
At a glance
- What is it?
- The Tailwind Labs Prettier plugin is a class reordering layer with a narrow default scope and a set of opt ins for everything outside it. Its two failure modes are worth knowing before you install it: a missing Tailwind config degrades silently to the default configuration, and since v0.5 the package is ESM only, so require() no longer loads it.
- Who is it for?
- Install it if your classes already live in the places it recognizes, which for most React, Vue and Angular codebases means class, className and @apply. Add tailwindAttributes and tailwindFunctions before you assume a helper is covered, because the plugin leaves unknown strings exactly as written and will not tell you it skipped them.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 46 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.
Star history
- tailwindlabs/prettier-plugin-tailwindcss7,134 ★ · +2
| Repository | 2026-09-23 | 2026-11-14 |
|---|---|---|
| tailwindlabs/prettier-plugin-tailwindcss | 7.1k | 7.1k |
2 Stars in the last 52 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
Tailwind v3 and v4 want different pointers, and only one gets used
The package installs as an ordinary dev dependency, then registers itself as a plugin:
npm install -D prettier prettier-plugin-tailwindcssOn Tailwind CSS v4 the plugin needs the CSS entry point, because that file is where your theme, custom utilities and other configuration live. You hand it over with the tailwindStylesheet option:
// .prettierrc
{
"tailwindStylesheet": "./resources/css/app.css"
}On v3 the equivalent input is the JavaScript config file, handed over with tailwindConfig, and the plugin looks for it next to your Prettier configuration file unless you say otherwise.
Both paths resolve relative to the Prettier configuration file, not relative to the file being formatted or the directory you happen to be standing in. In a monorepo where every package carries its own Prettier config, that is the difference between a config that loads and one that does not, and the failure is not loud.
The quiet failure lives in the fallback. If a local Tailwind configuration file cannot be found, the plugin falls back to the default Tailwind configuration instead of stopping. Your custom theme extensions then are not part of the sort order, so classes you defined yourself land in the wrong position and nothing explains why. Confirm the path resolves from the config file's directory before you blame the ordering.
The default scope is class, className, :class, [ngClass] and @apply, and nothing else
Out of the box the plugin touches a specific set of places: the class attribute, the framework specific equivalents including className, :class and [ngClass], plus any Tailwind @apply directives. Anything outside that list is left exactly as you wrote it.
The opt in for other attributes is tailwindAttributes, an array of names. Add myClassList to it and the classes inside that attribute get sorted along with everything else, which is how you cover a wrapper component that renames the prop.
Function calls are a separate opt in. tailwindFunctions takes a list of function names, and the documented uses are clsx and cva. It also covers tagged template literals, so registering tw makes the plugin sort the contents of tw tags, which is what twrnc relies on. If you roll your own tagged template instead, you can define an identity function yourself and register that name in the same array.
The cost of the narrow default is that a project routing classes through a helper of its own keeps those strings unsorted until somebody names the helper in one of these arrays.
Attribute patterns must be slash delimited strings, not JS regex literals
You can pass regular expressions to tailwindAttributes, and the documented form is a string wrapped in forward slashes, as in "/data-.*/". That pattern sorts classes in every attribute whose name starts with data-, covering data-theme and data-classes style props without listing them one at a time.
JS regex literals do not work in this position. The docs call that out for Prettier configurations, so the bare literal form is not an option, and a pattern written the way you would write it in a module will not behave the same way in a config file.
Two things to keep in mind when a pattern does not fire. Patterns are matched against attribute names, so a pattern covering attributes you no longer use sorts nothing and stays silent. And because sorting only applies to strings the plugin recognises as class lists, a pattern over an attribute holding something other than Tailwind classes leaves you with reformatted text and none of the benefit.
The sorter entrypoint hands you Tailwind's order without Prettier in the loop
If you want the same ordering outside of Prettier, the package exposes a sorter entrypoint with a createSorter function. You pass a base directory and a stylesheet path, and the returned object has two sorting methods: sortClassAttributes for space separated strings, and sortClassLists for arrays of class names. The docs show the same two input lists coming back reordered, with the plain utility placed ahead of the variant.
The options are few and each one changes how a path resolves. base is where relative paths resolve and it defaults to the current working directory. filepath is the file being formatted, and when you supply it Tailwind itself is resolved relative to that path. configPath points at a v3 config, stylesheetPath at a v4 stylesheet, and both resolve against base. preserveWhitespace decides whether whitespace around classes survives, and it defaults to false.
So the API is usable and also narrow. You get ordering, not formatting, and the whitespace default means a caller who needs the original spacing has to know to ask for it.
Since v0.5 the plugin is ESM only, so require() no longer loads it
As of v0.5.x this plugin requires Prettier v3 and ships as ESM only. It cannot be loaded through require(), which removes the CommonJS path entirely for anyone still wiring Prettier up from a CJS config or from a tool that resolves plugins itself.
The upgrade note points at an issue thread in the repository as the reference for that migration. What it does not offer is a compatibility shim, so there is no fallback flag and no legacy entry point to route through.
The release cadence is worth planning around too. The newest tag listed is v0.8.1, and v0.8.0 and v0.7.4 landed on the same day in April, while the last commit went in at the end of September. The tree moves faster than the published tags do, so read the changelog when you pin a version instead of assuming the tip of main matches the newest release.
vitest does not start until a separate script installs the fixture dependencies
The test command is vitest, but on a clean clone it never runs on its own. A pretest hook executes node scripts/install-fixture-deps.js first, so the suite pulls fixture dependencies before any test executes. That is the shape of a suite that formats real projects rather than snippets.
The dev dependencies say what those fixtures are. You find a Pug parser, a Liquid plugin, a Twig parser, a Marko compiler, two separate import sorting plugins, and two alternative Prettier parser plugins for oxc and hermes. None of them is a runtime dependency. They exist so the sorter gets exercised against templates and parsers where class attributes look nothing like the JSX case.
For a user that means the framework coverage is tested rather than assumed. For a contributor it means a test run contains a network step, and when that install step fails the symptom looks like a broken suite rather than a missing download.
Publishing runs tsdown, then copies dependency licenses into dist
The build is tsdown, with dev running the same tool in watch mode. The published surface is declared in package.json and it is two entries, the main entry and the sorter entry, both .mjs files with .d.mts type declarations alongside. Only dist ships, since the files array contains just that directory.
Publishing is not a bare build. prepublishOnly runs the build and then node scripts/copy-licenses.js, so bundled dependency licenses are copied into the package before it goes out. If anything is vendored into dist, that script is where the license obligations get handled, and it runs on publish rather than on a local build, which means your own build directory and the published one are not identical.
The repo also formats itself with a setup most users will not copy. The format script passes --print-width 100 --single-quote --no-semi and globs only src TypeScript, scripts JavaScript and the test files, so no template or JSX file in this repository is a formatting target. Linting is knip plus oxlint with type aware checks over src and tests.
Editorial conclusion
Install it if your classes already live in the places it recognizes, which for most React, Vue and Angular codebases means class, className and @apply. Add tailwindAttributes and tailwindFunctions before you assume a helper is covered, because the plugin leaves unknown strings exactly as written and will not tell you it skipped them. If you are on Tailwind v4, set tailwindStylesheet and confirm the path resolves from the Prettier config directory; on v3, a Tailwind config that is not found falls back to the default configuration instead of erroring. On the CJS side, check your Prettier loading path first: v0.5 dropped require() support and offers no shim.
Frequently asked questions
what is prettier plugin tailwindcss
It is a Prettier v3+ plugin for Tailwind CSS v3.0 and later that automatically sorts classes following the Tailwind team's recommended class order, licensed under MIT.
how to install prettier plugin tailwindcss
Install it as a dev dependency with npm install -D prettier prettier-plugin-tailwindcss, then add prettier-plugin-tailwindcss to the plugins array in your Prettier configuration.
how to use prettier plugin tailwindcss
Add the plugin to your Prettier config, point tailwindConfig at your Tailwind v3 config or tailwindStylesheet at your v4 CSS entry point, then list any extra attributes or helper functions in tailwindAttributes and tailwindFunctions.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/tailwindlabs-prettier-plugin-tailwindcss)Star history chart for your README
[](https://hysenlabs.com/projects/tailwindlabs-prettier-plugin-tailwindcss)Was this useful?