Skip to content

Scoped styles behave differently in Astro 6 #15907

Closed
withastro/compiler
#1153

Description

@jmbockhorst

Astro Info

Astro                    v6.0.4
Vite                     v7.3.1
Node                     v22.22.0
System                   MacOS (arm64)
Package Manager          pnpm
Output                   static
Adapter                  none
Integrations             none

If this issue only occurs in one browser, which browser is a problem?

No response

Describe the Bug

Scoped styles behave differently in Astro 6, which is causing our codebase to break. This seems like a regression, unless it was an intentional breaking change. Seems related to #14032.

When I have an Astro component like this:

<style>
    nav {
      a {
        color: deeppink;
      }
    }
</style>

<nav>
    <Link />
</nav>

and Link.astro is:

<a href="#">test</a>

What's the expected result?

Astro 5 produced this output:

<nav data-astro-cid-hujapecf> 
    <a href="#">test</a> 
</nav>
nav[data-astro-cid-hujapecf] {
    a { 
        color: deeppink; 
    }
}

Astro 6 produces this output:

<nav data-astro-cid-hujapecf> 
    <a href="#">test</a> 
</nav>
nav[data-astro-cid-hujapecf] {
    a[data-astro-cid-hujapecf] { 
        color:deeppink 
    }
}

Link to Minimal Reproducible Example

https://stackblitz.com/~/github.com/jmbockhorst/astro-scoping-bug

Participation

  • I am willing to submit a pull request for this issue.

Activity

  1. changed the title [-]Astro v5.10.2 Node v22.14.0 System macOS (arm64) Package Manager pnpm Output static Adapter none Integrations none[/-] [+]Scoped styles behave differently in Astro 6[/+] on Mar 13, 2026
  2. self-assigned this
    on Mar 13, 2026
  3. matthewp commented on Mar 13, 2026

    @matthewp
    Contributor

    Possibly caused by this, withastro/compiler#1144 i'll take a look

  4. jmbockhorst commented on Mar 13, 2026

    @jmbockhorst
    Author

    I forgot to mention that I believe this regressed in v6.0.0-beta.10.

  5. astrobot-houston commented on Mar 13, 2026

    @astrobot-houston
    Contributor

    I was able to reproduce this issue. The root cause is the @astrojs/compiler upgrade from v2.x to v3.0.0 that ships with Astro 6. In compiler v2.x, CSS nested selectors without & (like nav { a { ... } }) were incorrectly parsed as declarations rather than selector rules, so the inner a was never scoped. Compiler v3.0 correctly parses these as nested selector rules and applies scoping to all selectors, including the inner a, which causes a[data-astro-cid-xxx] to not match <a> elements rendered by child components (since those elements don't carry the parent component's scoping attribute).

    I was unable to find a fix for this issue. A fix is already in progress in the compiler repository: withastro/compiler#1153 ("fix: avoid re-scoping nested selectors without &"). In the meantime, a workaround is to use :global() on nested selectors that target child component elements, e.g. nav { :global(a) { color: deeppink; } }.

    P4: important. This is a behavioral regression from Astro 5 to Astro 6 that was not documented as a breaking change in the upgrade guide. It affects any codebase using CSS nesting (without &) in scoped styles to target elements rendered by child components — a common pattern. While there is a straightforward workaround (:global()), the change silently breaks existing styles, which violates expected behavior.

    Full Triage Report

    Triage Report: Issue #15907 — Scoped styles behave differently in Astro 6

    Reproduction

    Status: Reproduced

    Created a minimal reproduction with:

    • index.astro — a page with a <nav> wrapping a <Link /> component, with nested CSS nav { a { color: deeppink; } }
    • Link.astro — a simple component rendering <a href="#">test</a>

    Build output confirmed the issue:

    HTML:

    <nav data-astro-cid-j7pv25f6> <a href="#">test</a> </nav>

    CSS:

    nav[data-astro-cid-j7pv25f6]{a[data-astro-cid-j7pv25f6]{color:#ff1493}}

    The <a> element from the child Link component does NOT have data-astro-cid-j7pv25f6, but the CSS requires it via a[data-astro-cid-j7pv25f6]. The style therefore does not apply.

    Root Cause

    The behavior change was introduced by the @astrojs/compiler upgrade from v2.x to v3.0.0, which ships with Astro 6.

    Specifically, compiler commit 615eb21 (PR withastro/compiler#1144) fixed a bug where CSS nested selectors without & (like nav { a { ... } }) were incorrectly parsed as declarations instead of selector rules. In compiler v2.x, the inner a was never run through the scoping logic, so it remained unscoped. In v3.0, the parser correctly recognizes it as a nested selector rule and applies scoping to it.

    This was an intentional bug fix for issue #10721 (:global selector in CSS nesting was broken because nested selectors without & were not parsed at all). However, it has the unintended side effect of breaking styles that target child component elements via CSS nesting.

    The scopedStyleStrategy default ('attribute') has NOT changed between Astro 5 and Astro 6.

    Key files:

    • Compiler: lib/esbuild/css_parser/css_parser.go — shouldParseNestedSelector() function (added in v3.0)
    • Compiler: lib/esbuild/css_printer/astro_features.go — printCompoundSelector() function
    • Astro: packages/astro/package.json line 120 — @astrojs/compiler: ^3.0.0

    Workaround

    Using :global() on the nested selector prevents scoping:

    nav {
      :global(a) {
        color: deeppink;
      }
    }

    This produces:

    nav[data-astro-cid-xxx]{a{color:#ff1493}}

    Which correctly matches the child component's <a> element.

    Fix Status

    A fix is already in progress: withastro/compiler#1153 ("fix: avoid re-scoping nested selectors without &"). This PR avoids injecting Astro scope for nested selector rules that omit &, which restores the Astro 5 behavior.

    Impact

    This affects any codebase that uses CSS nesting (without &) in Astro scoped styles to target elements rendered by child components. This is a common pattern and the behavioral change was not documented as a breaking change in the Astro 6 upgrade guide.

    This report was made by an LLM. Mistakes happen, check important info.

  6. added
    - P4: importantViolate documented behavior or significantly impacts performance (priority)
    pkg: astroRelated to the core `astro` package (scope)
    and removed on Mar 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

- P4: importantViolate documented behavior or significantly impacts performance (priority)pkg: astroRelated to the core `astro` package (scope)

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions