From 5ea81bb4b74859e38d8756e6bb5a1906df6c83e5 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Thu, 17 Jul 2025 18:22:19 -0400 Subject: [PATCH 1/2] Add error messages for likely functional but otherwise invalid utility names --- packages/tailwindcss/src/index.test.ts | 24 ++++++++++++++++++++++++ packages/tailwindcss/src/index.ts | 12 ++++++++++++ 2 files changed, 36 insertions(+) diff --git a/packages/tailwindcss/src/index.test.ts b/packages/tailwindcss/src/index.test.ts index 430c3a71dff1..a19fcf96d979 100644 --- a/packages/tailwindcss/src/index.test.ts +++ b/packages/tailwindcss/src/index.test.ts @@ -4354,6 +4354,30 @@ describe('@utility', () => { `[Error: \`@utility 💨\` defines an invalid utility name. Utilities should be alphanumeric and start with a lowercase letter.]`, ) }) + + test('A functional @utility must end in -*', () => { + return expect( + compileCss(css` + @utility foo* { + color: red; + } + `), + ).rejects.toThrowErrorMatchingInlineSnapshot( + `[Error: \`@utility foo*\` defines an invalid utility name. A functional utility must end in \`-*\`.]`, + ) + }) + + test('Only the last part of a functional @utility can be dynamic', () => { + return expect( + compileCss(css` + @utility my-*-utility { + color: red; + } + `), + ).rejects.toThrowErrorMatchingInlineSnapshot( + `[Error: \`@utility my-*-utility\` defines an invalid utility name. The dynamic portion marked by \`-*\` must appear once at the end.]`, + ) + }) }) test('addBase', async () => { diff --git a/packages/tailwindcss/src/index.ts b/packages/tailwindcss/src/index.ts index 4907306eee84..07a23a3251d2 100644 --- a/packages/tailwindcss/src/index.ts +++ b/packages/tailwindcss/src/index.ts @@ -229,6 +229,18 @@ async function parseCss( let utility = createCssUtility(node) if (utility === null) { + if (!node.params.endsWith('-*')) { + if (node.params.endsWith('*')) { + throw new Error( + `\`@utility ${node.params}\` defines an invalid utility name. A functional utility must end in \`-*\`.`, + ) + } else if (node.params.includes('*')) { + throw new Error( + `\`@utility ${node.params}\` defines an invalid utility name. The dynamic portion marked by \`-*\` must appear once at the end.`, + ) + } + } + throw new Error( `\`@utility ${node.params}\` defines an invalid utility name. Utilities should be alphanumeric and start with a lowercase letter.`, ) From e17066c21eb217f77dce98c39bf19cee806e687a Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Fri, 18 Jul 2025 09:38:37 -0400 Subject: [PATCH 2/2] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f088d873a217..0b09cfdb1a70 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Ignore consecutive semicolons in the CSS parser ([#18532](https://github.com/tailwindlabs/tailwindcss/pull/18532)) - Center the dropdown icon added to an input with a paired datalist ([#18511](https://github.com/tailwindlabs/tailwindcss/pull/18511)) - Extract candidates in Slang templates ([#18565](https://github.com/tailwindlabs/tailwindcss/pull/18565)) +- Improve error messages when encountering invalid functional utility names ([#18568](https://github.com/tailwindlabs/tailwindcss/pull/18568)) ## [4.1.11] - 2025-06-26