Skip to content

Commit 036e88f

Browse files
authored
fix: allow :global(..) in compound selectors (#10266)
Someone could programmatically add a class to an element and Svelte doesn't see it, so having global be part of a modifier is necessary so that Svelte doesn't mark it as unused fixes #10210
1 parent 6b0bd8b commit 036e88f

File tree

10 files changed

+46
-27
lines changed

10 files changed

+46
-27
lines changed

.changeset/serious-kids-deliver.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"svelte": patch
3+
---
4+
5+
fix: allow `:global(..)` in compound selectors

packages/svelte/src/compiler/errors.js

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ const css = {
100100
`:global(...) can be at the start or end of a selector sequence, but not in the middle`,
101101
'invalid-css-global-selector': () => `:global(...) must contain exactly one selector`,
102102
'invalid-css-global-selector-list': () =>
103-
`:global(...) cannot be used to modify a selector, or be modified by another selector`,
103+
`:global(...) must not contain type or universal selectors when used in a compound selector`,
104104
'invalid-css-selector': () => `Invalid selector`,
105105
'invalid-css-identifier': () => 'Expected a valid CSS identifier'
106106
};
@@ -447,19 +447,6 @@ const errors = {
447447
// code: 'illegal-variable-declaration',
448448
// message: 'Cannot declare same variable name which is imported inside <script context="module">'
449449
// },
450-
// css_invalid_global_selector: {
451-
// code: 'css-invalid-global-selector',
452-
// message: ':global(...) must contain a single selector'
453-
// },
454-
// css_invalid_global_selector_position: {
455-
// code: 'css-invalid-global-selector-position',
456-
// message:
457-
// ':global(...) not at the start of a selector sequence should not contain type or universal selectors'
458-
// },
459-
// css_invalid_selector: /** @param {string} selector */ (selector) => ({
460-
// code: 'css-invalid-selector',
461-
// message: `Invalid selector "${selector}"`
462-
// }),
463450
// invalid_directive_value: {
464451
// code: 'invalid-directive-value',
465452
// message:

packages/svelte/src/compiler/phases/2-analyze/css/Selector.js

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -177,18 +177,15 @@ export default class Selector {
177177

178178
validate_global_compound_selector() {
179179
for (const block of this.blocks) {
180+
if (block.selectors.length === 1) continue;
181+
180182
for (let i = 0; i < block.selectors.length; i++) {
181183
const selector = block.selectors[i];
182-
if (
183-
selector.type === 'PseudoClassSelector' &&
184-
selector.name === 'global' &&
185-
block.selectors.length !== 1 &&
186-
(i === block.selectors.length - 1 ||
187-
block.selectors
188-
.slice(i + 1)
189-
.some((s) => s.type !== 'PseudoElementSelector' && s.type !== 'PseudoClassSelector'))
190-
) {
191-
error(selector, 'invalid-css-global-selector-list');
184+
if (selector.type === 'PseudoClassSelector' && selector.name === 'global') {
185+
const child = selector.args?.children[0].children[0];
186+
if (child?.type === 'TypeSelector' && !/[.:#]/.test(child.name[0])) {
187+
error(selector, 'invalid-css-global-selector-list');
188+
}
192189
}
193190
}
194191
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { test } from '../../test';
2+
3+
export default test({
4+
warnings: []
5+
});
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
div.svelte-xyz.blue {
2+
color: blue;
3+
}
4+
span.blue.x.svelte-xyz {
5+
color: blue;
6+
}
7+
span.x.svelte-xyz.bg {
8+
background: red;
9+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
<div class="svelte-xyz">someone could programmatically add a class to this, so having global be part of a modifier is necessary</div>
2+
<span class="x svelte-xyz">-</span>
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<div>someone could programmatically add a class to this, so having global be part of a modifier is necessary</div>
2+
<span class="x">-</span>
3+
4+
<style>
5+
div:global(.blue) {
6+
color: blue;
7+
}
8+
span:global(.blue).x {
9+
color: blue;
10+
}
11+
span.x:global(.bg) {
12+
background: red;
13+
}
14+
</style>

packages/svelte/tests/validator/samples/css-invalid-global-placement-4/errors.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[
22
{
33
"code": "invalid-css-global-selector-list",
4-
"message": ":global(...) cannot be used to modify a selector, or be modified by another selector",
4+
"message": ":global(...) must not contain type or universal selectors when used in a compound selector",
55
"start": {
66
"line": 2,
77
"column": 5

packages/svelte/tests/validator/samples/css-invalid-global-placement-5/errors.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[
22
{
33
"code": "invalid-css-global-selector-list",
4-
"message": ":global(...) cannot be used to modify a selector, or be modified by another selector",
4+
"message": ":global(...) must not contain type or universal selectors when used in a compound selector",
55
"start": {
66
"line": 2,
77
"column": 5

sites/svelte-5-preview/src/routes/docs/content/03-appendix/02-breaking-changes.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ Assignments to destructured parts of a `@const` declaration are no longer allowe
7676

7777
### Stricter CSS `:global` selector validation
7878

79-
Previously, a selector like `.foo :global(bar).baz` was valid. In Svelte 5, this is a validation error instead. The reason is that in this selector the resulting CSS would be equivalent to one without `:global` - in other words, `:global` is ignored in this case.
79+
Previously, a compound selector starting with a global modifier which has universal or type selectors (like `:global(span).foo`) was valid. In Svelte 5, this is a validation error instead. The reason is that in this selector the resulting CSS would be equivalent to one without `:global` - in other words, `:global` is ignored in this case.
8080

8181
### CSS hash position no longer deterministic
8282

0 commit comments

Comments
 (0)