diff --git a/CHANGELOG.md b/CHANGELOG.md index a84ace364968..52f712c87883 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,8 +14,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Fix Safari devtools rendering issue due to `color-mix` fallback ([#19069](https://github.com/tailwindlabs/tailwindcss/pull/19069)) -- Suppress Lightning CSS warnings about `:deep`, `:slotted` and `:global` ([#19094](https://github.com/tailwindlabs/tailwindcss/pull/19094)) +- Suppress Lightning CSS warnings about `:deep`, `:slotted`, and `:global` ([#19094](https://github.com/tailwindlabs/tailwindcss/pull/19094)) - Fix resolving theme keys when starting with the name of another theme key in JS configs and plugins ([#19097](https://github.com/tailwindlabs/tailwindcss/pull/19097)) +- Allow named groups in combination with `not-*`, `has-*`, and `in-*` ([#19100](https://github.com/tailwindlabs/tailwindcss/pull/19100)) ## [4.1.14] - 2025-10-01 diff --git a/packages/tailwindcss/src/candidate.test.ts b/packages/tailwindcss/src/candidate.test.ts index dfc65ac73c26..3d4aa983b2a0 100644 --- a/packages/tailwindcss/src/candidate.test.ts +++ b/packages/tailwindcss/src/candidate.test.ts @@ -2102,6 +2102,11 @@ const variants = [ // Handle special `@` variants. These shouldn't be printed as `@-` ['@xl:', '@xl:'], ['@[123px]:', '@[123px]:'], + + // Compound variants that forward modifiers + ['not-group-hover/name:', 'not-group-hover/name:'], + ['has-group-peer-hover/name:', 'has-group-peer-hover/name:'], + ['in-group-peer-hover/name:', 'in-group-peer-hover/name:'], ] let combinations: [string, string][] = [] diff --git a/packages/tailwindcss/src/candidate.ts b/packages/tailwindcss/src/candidate.ts index a9ba2d6e200f..df5998d9e81f 100644 --- a/packages/tailwindcss/src/candidate.ts +++ b/packages/tailwindcss/src/candidate.ts @@ -806,6 +806,13 @@ export function parseVariant(variant: string, designSystem: DesignSystem): Varia case 'compound': { if (value === null) return null + // Forward the modifier of the compound variants to its subVariant. + // This allows for `not-group-hover/name:flex` to work. + if (modifier && (root === 'not' || root === 'has' || root === 'in')) { + value = `${value}/${modifier}` + modifier = null + } + let subVariant = designSystem.parseVariant(value) if (subVariant === null) return null diff --git a/packages/tailwindcss/src/variants.test.ts b/packages/tailwindcss/src/variants.test.ts index f9d054a21656..a2540e698d7b 100644 --- a/packages/tailwindcss/src/variants.test.ts +++ b/packages/tailwindcss/src/variants.test.ts @@ -2586,6 +2586,24 @@ test('matchVariant sorts deterministically', async () => { } }) +test('move modifier of compound variant to sub-variant if its also a compound variant', async () => { + expect( + await run([ + 'not-group-focus/name:flex', + 'has-group-focus/name:flex', + 'in-group-focus/name:flex', + + // Keep the `name` on the `group`, don't move it to the `peer` because + // that would be a breaking change. + 'group-peer-focus/name:flex', + ]), + ).toMatchInlineSnapshot(` + ".not-group-focus\\/name\\:flex:not(:is(:where(.group\\/name):focus *)), .group-peer-focus\\/name\\:flex:is(:where(.group\\/name):is(:where(.peer):focus ~ *) *), :where(:is(:where(.group\\/name):focus *)) .in-group-focus\\/name\\:flex, .has-group-focus\\/name\\:flex:has(:is(:where(.group\\/name):focus *)) { + display: flex; + }" + `) +}) + test.each([ // These are style rules [['.foo'], Compounds.StyleRules],