English
Interop with oxfmt and prettier-plugin-tailwindcss
enforce-sort-order produces the official Tailwind class order — the same order prettier-plugin-tailwindcss produces, and oxfmt's sortTailwindcss, which implements the same algorithm. The formatter and this plugin agree on every class string the formatter touches, once both read the same CSS and the formatter knows your class helpers. Two settings do it.
1. The same stylesheet
By default the formatter reads the theme bundled in the installed tailwindcss package — not your project's CSS — so it doesn't know your @theme tokens and orders them differently: bg-brand and text-brand are sorted as unknown classes. Point it at the file this plugin reads.
2. Your class helpers
The formatter sorts class attributes (className, class) and only the functions you list. cn("p-4 flex") stays unsorted unless cn is in functions, while this plugin sorts every class string it extracts. List the helpers you use:
jsonc
// .oxfmtrc.json
{
"sortTailwindcss": {
"stylesheet": "./src/styles.css",
"functions": ["cn", "clsx", "cva", "tv"]
}
}The same two settings for prettier:
jsonc
// .prettierrc
{
"plugins": ["prettier-plugin-tailwindcss"],
"tailwindStylesheet": "./src/styles.css",
"tailwindFunctions": ["cn", "clsx", "cva", "tv"]
}Who does what
With both settings, running the formatter leaves enforce-sort-order nothing to report in class attributes and listed helpers, and running oxlint --fix leaves the formatter nothing to change. Class strings the formatter never formats — a const classes = "…" variable, for instance — stay the linter's.
The formatter also drops duplicate classes and collapses whitespace in the strings it formats, so it overlaps with no-duplicate-classes and no-unnecessary-whitespace there; the lint rules keep covering everything else.
That includes the line breaks of a class string that enforce-consistent-line-wrapping wrapped into a block, whether a class attribute (wrapStrings: "jsx") or a template in a helper the formatter sorts (cn(…) with wrapStrings: "all"): the formatter puts it back on one line, and each undoes the other. Set preserveWhitespace: true in sortTailwindcss to keep the block.
--fix more than once
When several rules fix the same class string (a duplicate, extra whitespace and the order), oxlint applies one of those fixes per run: it has no multi-pass fixing. Run oxlint --fix again, or let the formatter do the sorting, de-duplication and whitespace in one go.
Why this isn't fixed upstream
The Tailwind team intentionally requires explicit config for the stylesheet in v4. There's no convention like tailwind.config.js to auto-detect in v4 — CSS files can live anywhere and be named anything. The plugin defaults to the bundled theme.css rather than guess.
oxlint-tailwindcss v1 follows the same philosophy (explicit entryPoint), so the only step needed for consistency is to tell each tool the same path.
What about tailwindcss-animate and @tailwindcss/typography?
If you use plugins that register classes (e.g. prose-*, animate-in), they're imported via your @import in CSS — both tools will pick them up automatically as long as they're reading the same stylesheet.
Multiple stylesheets per project
If different parts of your monorepo use different CSS files, see the monorepo guide. The same patterns apply to oxfmt: its overrides can point different file globs at different stylesheets.
jsonc
// .oxfmtrc.json
{
"sortTailwindcss": { "functions": ["cn"] },
"overrides": [
{
"files": ["packages/admin/**"],
"options": {
"sortTailwindcss": { "stylesheet": "./packages/admin/src/admin.css", "functions": ["cn"] }
}
}
]
}