You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
feat: add Tailwind class name sorting (#552) - #795
Currently dprint-plugin-typescript preserves the input order, so projects that use dprint cannot opt into that Tailwind ordering for JSX class attributes or common class helper calls.
Fix
Add jsx.sortClassNames with a new tailwind value. The default remains maintain.
When enabled, the formatter sorts Tailwind class lists in:
configured helper calls via jsx.sortClassNames.functions, for example cn, classnames, or tw
configured tagged template literals via the same function list
The sorter follows the same broad behavior as prettier-plugin-tailwindcss for the covered cases: custom classes stay first, whitespace is collapsed, duplicate classes are removed, and variants sort after base utilities.
Behavior
input
config
after
<div className="p-4 flex" />
default
unchanged
<div className="p-4 flex" />
jsx.sortClassNames: tailwind
<div className="flex p-4" />
className={cn("p-4 flex")}
jsx.sortClassNames: tailwind
string inside expression sorted
cn("p-4 flex")
jsx.sortClassNames.functions: ["cn"]
cn("flex p-4")
tw`p-4 flex`
jsx.sortClassNames.functions: ["tw"]
tw`flex p-4`
Spec and docs updates
New JSX attribute specs cover:
default no-op behavior
Tailwind ordering for class and className
public prettier-plugin-tailwindcss examples
custom class ordering
whitespace collapse and duplicate removal
className={...} expression containers
configured function calls and tagged templates
Docs updates cover:
README configuration example
generated schema descriptions for jsx.sortClassNames and jsx.sortClassNames.functions
Cross-referenced against prettier-plugin-tailwindcss docs/source and Oxc's Tailwind sorting tests.
cargo test passes.
todor-a
changed the title
[codex] Add Tailwind class name sorting
feat: add Tailwind class name sorting (#552)
May 28, 2026
The reason will be displayed to describe this comment to others. Learn more.
🟡 Changes recommended
Interpolated templates can change semantics, helper-only configuration does not work as documented, and several common Tailwind classes are ordered incorrectly.
Moves the sorter into a self-contained `tailwind` module and patterns its
handling of whitespace, duplicates, unknown classes and template literals
off prettier-plugin-tailwindcss, porting that plugin's tests.
- keep the whitespace that separates concatenated strings
- sort the text around template literal expressions without moving the
classes that touch an expression
- don't sort the other attributes of an element in a class attribute
- handle the important modifier and sort unknown variants after known ones
- borrow the text when it's already sorted and avoid per class allocations
Replaces the hand-written tables with ones generated from Tailwind CSS 4.3.3
by scripts/generate_tailwind_tables.ts and ports Tailwind's comparisons of
utilities, variants and breakpoints, so that classes sharing a prefix sort by
what they set (ex. `text-sm` before `text-red-500`).
The script also generates class lists sorted by Tailwind, which a test checks
the Rust code sorts the same way.
…ames
Adds config for what the sorter can't know without a project's CSS:
- `jsx.sortClassNames.tailwind.prefix`
- `jsx.sortClassNames.tailwind.theme` for theme variables, which orders custom
breakpoints by size and values by the kind of variable they're for
- `jsx.sortClassNames.tailwind.variants` for custom variants
- `jsx.sortClassNames.tailwind.utilities` for custom utilities, which are
ordered by the CSS properties they set
Also aligns more with prettier-plugin-tailwindcss by adding
`jsx.sortClassNames.attributes`, `jsx.sortClassNames.preserveWhitespace` and
`jsx.sortClassNames.preserveDuplicates`, sorting every string in a class
attribute's expression, and treating a class with an unknown variant as an
unknown class.
The script now also generates class lists sorted by Tailwind for a project
that customizes it, which a test checks the Rust code sorts the same way.
The reason will be displayed to describe this comment to others. Learn more.
Not doing this one. The configuration section was removed from the README on purpose and the PR description predates that; the options are documented in the schema.
Also handles quotes and escapes in arbitrary values, only treats ASCII
whitespace as separating classes at template literal boundaries, and
looks at the text beside a template literal expression when deciding if
a string's whitespace can be removed.
Whitespace-only strings are not collapsed when transformed
src/tailwind/mod.rs:100
This returns a different string as Cow::Borrowed, but gen_string_literal treats every borrowed result as unchanged and discards it (src/generation/generate.rs:4250-4253). Consequently a whitespace-only string such as className={" "} remains unchanged instead of collapsing to one space. Return an owned value whenever the output differs from text.
Property lists over 32 entries are silently truncated
src/tailwind/mod.rs:496
The public utilities option accepts an unbounded property list, but this fixed buffer silently drops every distinct recognized property after the first 32. Two large custom utilities can therefore receive the same truncated sort key and fall back to class-name order even when Tailwind orders them by a later property. Keep the complete property-order vector (or validate and reject oversized lists) rather than truncating it.
Mention numeric theme values in diagnostic guidance
src/configuration/resolve_config.rs:387
This diagnostic says only strings are accepted even though the immediately preceding branch also accepts numeric theme values. Invalid input therefore gets misleading guidance; mention both supported forms.
Reject unsupported slash modifiers during utility validation
src/tailwind/mod.rs:439
Unsupported slash modifiers are treated as valid for every utility because lookup falls back to utility_without_modifier. For example, Tailwind rejects p-4/foo, so it should remain an unknown class and sort before flex; this code assigns it the padding position and leaves flex p-4/foo. Preserve modifier-support metadata from Tailwind (or otherwise validate candidates) before dropping the suffix.
Validate configured breakpoint values for functional variants
src/tailwind/mod.rs:634
Value-ordered functional variants are considered known even when their value is not a configured/default breakpoint. For example, without --breakpoint-foo, Tailwind treats max-foo:flex as unknown and keeps it before p-4, while this path recognizes max and sorts it as a real variant. Validate breakpoint/container values while still permitting bracketed arbitrary values.
The generated tables now have the values each utility accepts, what may
follow the slash after it, and what the value of each variant may be, so
classes like p-banana, p-4/foo, and max-foo:flex are left as unknown.
The reason will be displayed to describe this comment to others. Learn more.
Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.
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
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.
Fixes #552. Adds opt-in Tailwind class sorting aligned with prettier-plugin-tailwindcss.
Transparency note: This PR was prepared with AI assistance (Claude).
Problem
Tailwind users often rely on Prettier's Tailwind plugin to keep utility classes in a stable recommended order.
Currently dprint-plugin-typescript preserves the input order, so projects that use dprint cannot opt into that Tailwind ordering for JSX class attributes or common class helper calls.
Fix
Add
jsx.sortClassNameswith a newtailwindvalue. The default remainsmaintain.When enabled, the formatter sorts Tailwind class lists in:
classandclassNamestring attributesclassName={...}expression containersjsx.sortClassNames.functions, for examplecn,classnames, ortwThe sorter follows the same broad behavior as prettier-plugin-tailwindcss for the covered cases: custom classes stay first, whitespace is collapsed, duplicate classes are removed, and variants sort after base utilities.
Behavior
<div className="p-4 flex" /><div className="p-4 flex" />jsx.sortClassNames: tailwind<div className="flex p-4" />className={cn("p-4 flex")}jsx.sortClassNames: tailwindcn("p-4 flex")jsx.sortClassNames.functions: ["cn"]cn("flex p-4")tw`p-4 flex`jsx.sortClassNames.functions: ["tw"]tw`flex p-4`Spec and docs updates
New JSX attribute specs cover:
classandclassNameclassName={...}expression containersDocs updates cover:
jsx.sortClassNamesandjsx.sortClassNames.functionsCross-referenced against prettier-plugin-tailwindcss docs/source and Oxc's Tailwind sorting tests.
cargo testpasses.