Allow multiple @utility definitions with same name but different value types#19777
Allow multiple @utility definitions with same name but different value types#19777mvanhorn wants to merge 1 commit intotailwindlabs:mainfrom
Conversation
…different value types When multiple CSS @Utility definitions share the same name but handle different value types, all handlers should be tried. Previously, a null return from any handler would stop the loop, preventing subsequent handlers from being attempted. The fix distinguishes between CSS @Utility handlers (no typed options) and JS plugin matchUtilities handlers (with explicit types). For CSS @Utility, null means "try the next handler." For typed plugin utilities, null means "the value was invalid for this type, stop." Fixes tailwindlabs#16948 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
WalkthroughThe pull request modifies utility compilation and adds related tests. In compile.ts, the null-handling logic for when a utility's compileFn returns null has been updated to distinguish between typed plugin utilities and CSS 🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/tailwindcss/src/compile.ts (1)
309-312: Consider adding the explanatory comment here for consistency.The fallback utilities loop applies identical null-handling logic but lacks the explanatory comment present in lines 291-294. Adding a brief comment would improve maintainability and make the parallel behavior explicit.
📝 Suggested improvement
if (compiledNodes === null) { + // Same typed vs untyped distinction as above if (utility.options?.types?.length) return asts continue }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/tailwindcss/src/compile.ts` around lines 309 - 312, Add the same explanatory comment that exists earlier for null-handling to the fallback utilities loop where compiledNodes is checked (the block: if (compiledNodes === null) { if (utility.options?.types?.length) return asts continue }). Locate the fallback utilities loop in compile.ts and insert a brief comment above that if-statement explaining why compiledNodes can be null and why we return asts when utility.options?.types?.length is set (mirroring the comment used for the earlier, identical null-handling logic), so the parallel behavior is explicit and maintainable.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@packages/tailwindcss/src/compile.ts`:
- Around line 309-312: Add the same explanatory comment that exists earlier for
null-handling to the fallback utilities loop where compiledNodes is checked (the
block: if (compiledNodes === null) { if (utility.options?.types?.length) return
asts continue }). Locate the fallback utilities loop in compile.ts and insert a
brief comment above that if-statement explaining why compiledNodes can be null
and why we return asts when utility.options?.types?.length is set (mirroring the
comment used for the earlier, identical null-handling logic), so the parallel
behavior is explicit and maintainable.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: c7b0a62d-f8cb-4ef4-817e-22d1599afd98
📒 Files selected for processing (2)
packages/tailwindcss/src/compile.tspackages/tailwindcss/src/utilities.test.ts
Summary
Fixes #16948
When defining multiple CSS
@utility foo-*with different value types (e.g., one for colors, one for numbers), only the first handler was tried. If it returnednull(value didn't match), the compile loop stopped, preventing subsequent handlers from being attempted.Previously,
foo-red-500worked butfoo-123did not (or vice versa depending on definition order).The fix distinguishes between CSS
@utilityhandlers and JS pluginmatchUtilitieshandlers:@utility(no typed options):nullmeans "try the next handler" - allows multiple definitions with different value types to coexistmatchUtilities(with explicit types):nullmeans "the value was invalid for this type, stop" - preserves existing behavior where typed utilities prevent invalid values from falling throughTest plan
@utility foo-*definitions with different value types - verifies bothfoo-red-500(color) andfoo-123(number) produce correct CSSmatchUtilitiestype-safety tests)pnpm build && pnpm testpassesThis contribution was developed with AI assistance (Claude Code).