Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Handle `'` syntax in ClojureScript when extracting classes ([#18888](https://github.com/tailwindlabs/tailwindcss/pull/18888))
- Handle `@variant` inside `@custom-variant` ([#18885](https://github.com/tailwindlabs/tailwindcss/pull/18885))
- Merge suggestions when using `@utility` ([#18900](https://github.com/tailwindlabs/tailwindcss/pull/18900))

## [4.1.13] - 2025-09-03

Expand Down
33 changes: 33 additions & 0 deletions packages/tailwindcss/src/intellisense.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,39 @@ test('Custom functional @utility', async () => {
expect(classMap.get('example-xs')?.modifiers).toEqual(['normal', 'foo', 'bar'])
})

test('Custom utilities sharing a root with built-in utilities should merge suggestions', async () => {
let input = css`
@import 'tailwindcss/utilities';
@theme {
--font-sans: sans-serif;
}

@theme {
--font-weight-custom: 1234;
--font-weight-bold: bold; /* Overlap with existing utility */
}

@utility font-* {
--my-font-weight: --value(--font-weight- *);
}
`

let design = await __unstable__loadDesignSystem(input, {
loadStylesheet: async (_, base) => ({
path: '',
base,
content: '@tailwind utilities;',
}),
})

let classMap = new Map(design.getClassList())
let classNames = Array.from(classMap.keys())

expect(classNames).toContain('font-sans') // Existing font-family utility
expect(classNames).toContain('font-bold') // Existing font-family utility & custom font-weight utility
expect(classNames).toContain('font-custom') // Custom font-weight utility
})

test('Theme keys with underscores are suggested with underscores', async () => {
let input = css`
@import 'tailwindcss/utilities';
Expand Down
3 changes: 3 additions & 0 deletions packages/tailwindcss/src/intellisense.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ export function getClassList(design: DesignSystem): ClassEntry[] {
item.fraction ||= fraction
item.modifiers.push(...group.modifiers)
}

// Deduplicate modifiers
item.modifiers = Array.from(new Set(item.modifiers))
}
}
}
Expand Down
9 changes: 6 additions & 3 deletions packages/tailwindcss/src/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,12 @@ export class Utilities {
}

suggest(name: string, groups: () => SuggestionGroup[]) {
// TODO: We are calling this multiple times on purpose but ideally only ever
// once per utility root.
this.completions.set(name, groups)
let existingGroups = this.completions.get(name)
if (existingGroups) {
this.completions.set(name, () => [...existingGroups?.(), ...groups?.()])
} else {
this.completions.set(name, groups)
}
}

keys(kind: 'static' | 'functional') {
Expand Down