Repository navigation
docs: migrating from eslint-plugin-tailwindcss - #233
Merged
Merged
Conversation
eslint-plugin-tailwindcss (francoismassart) reads Tailwind v4 since its 4.x releases, and had no guide here. /migration/from-eslint-plugin-tailwindcss (EN/ES) maps each of 4.4.0's 9 rules and 7 settings, with what differs, and walks from an ESLint flat config to an .oxlintrc.json. Everything it says comes from the 4.4.0 package or from running both plugins: - Their canonical rule folds in what has its own rule here (v3 renames, bg-[var(--x)], !p-4, -m-[5px]), and rewrites what this one leaves because the CSS differs ([&>*]: → *:, aspect-[16/9] → aspect-video). - Their shorthand also makes truncate; four corners fold at once here. - Their no-unnecessary-arbitrary-value turns m-[8px] / w-[20rem] into tokens: prefer-scale-token here, as a suggestion. - Settings: theirs replace the defaults, ours add to them; functions → callees + tags (classNames(…) and tw(…) as a call aren't read here); keys of an object are classes in any callee here, only in parseKeyFunctions there; a relative cssConfigPath resolves against the nearest eslint.config.* or package.json, entryPoint against the nearest oxlint config. - Both plugins are named `tailwindcss`: oxlint refuses to load the two side by side, so the guide says to remove theirs in the same step. Data-driven like the better-tailwindcss guide: data/eslint-plugin-tailwindcss.json renders the rules, settings and "rules they don't have" blocks through migration* functions in scripts/blocks.ts, which the btw* blocks now share. Sidebar and FAQ entries in both locales. Tests: blocks.test.ts for the three blocks, and eslint-plugin-tailwindcss-map.test.ts for this plugin's side (rules, settings and options exist, each mapped once, and the prose names the data's version and rule count in both locales). Claude-Session: https://claude.ai/code/session_019vTh6S5A41M1HLkmk3FaM1
…t the plugin bench/interop.mjs now does for eslint-plugin-tailwindcss what it does for better-tailwindcss: every row's example must be reported by their rule and by ours, and every rule of theirs must have a row. Pinned at 4.4.0 in bench/package.json; interop.yml also installs @latest weekly. It runs as an oxlint JS plugin, but registers as `tailwindcss` like this one, so oxlint refuses to load both ("Plugin name 'tailwindcss' is already registered"): it is linted on its own. A relative cssConfigPath resolves against the nearest eslint.config.* or package.json above the linted file — bench/'s for the interop project — so it gets an absolute one. mappingGaps takes the guide's file prefix and plugin name (defaults: btw, better-tailwindcss), with a test. A mutated example (inset-px) fails both sides, exit 1. Claude-Session: https://claude.ai/code/session_019vTh6S5A41M1HLkmk3FaM1
sergioazoc
added a commit
that referenced
this pull request
Oct 10, 2026
- packages/oxlint-tailwindcss/package.json and the Claude Code plugin's plugin.json at 1.16.0. - CHANGELOG: Unreleased → 1.16.0 — Features (#216, #232: wrapStrings "all") and Documentation (#233: the eslint-plugin-tailwindcss migration guide). Nothing changes with the same config. - bench/results/latest.json regenerated after the bump (only the version and timings move), /benchmark and /comparison regenerated from it. Claude-Session: https://claude.ai/code/session_019vTh6S5A41M1HLkmk3FaM1
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A guide for the most-used Tailwind lint plugin, eslint-plugin-tailwindcss. Its
latestis 4.4.0, with Tailwind v4 and 9 rules. The guide is built like/migration/from-better-tailwindcss: data-driven, in EN/ES, and checked against the plugin itself./migration/from-eslint-plugin-tailwindcss(EN/ES) has:.oxlintrc.json, step by step, with a before/after;It's in the sidebar of both locales and has an FAQ entry.
Data and generation:
data/eslint-plugin-tailwindcss.jsonrenders through the samemigration*functions inscripts/blocks.ts. The btw guide's output is unchanged:generateleaves no diff.Checks:
tests/docs/eslint-plugin-tailwindcss-map.test.ts: every rule, option and setting of ours exists, and the prose names the data's version and rule count.bench/interop.mjs, weekly ininterop.yml: every row's example is reported by both rules, and every rule of theirs has a row, against the pinned 4.4.0 and@latest.How their plugin runs: as an oxlint JS plugin, no ESLint needed. It registers as
tailwindcsstoo, so oxlint won't load it beside ours ("Plugin name 'tailwindcss' is already registered"). The interop lints it on its own, with an absolutecssConfigPath, since a relative one resolves against the nearesteslint.config.*/package.json. The guide's step 4 tells users to remove it in the same change.@shadcn/lintgets no migration guide: it's a complement, not a replacement (see/shadcn).Test plan
pnpm test(3821 + 318), format, lint,lint:types, typecheck.generateleaves no diff, andpnpm -C packages/docs build:check-distok.npm test(67).node interop.mjs, pinned and@latest: "9 rules map". Changing an example toinset-pxmakes it fail on both sides.🤖 Generated with Claude Code
https://claude.ai/code/session_019vTh6S5A41M1HLkmk3FaM1