Custom notebooks for your e-ink tabletSupernote, reMarkable and more.Build yours →

CSS @scope: Scoped Styles Without BEM

Scoped styles without BEM naming

To avoid leaks you used BEM, CSS Modules, or styled-components. @scope limits selectors to a root and optional boundary so you can use short names safely.

Old way8 lines
.card__title   {  font-size: 1.25rem;  margin-bottom: 0.5rem;}.card__body   {  color: #444;}/* HTML: class="card__title" */
Modern
8 lines
@scope (.card)   {  .title   {    font-size: 1.25rem;    margin-bottom: 0.5rem;  }  .body   {    color: #444;  }}/* HTML: class="card", class="title" */
Newly availableSince 202687% global usage

Since 2026 this feature works across the latest devices and browser versions. This feature might not work in older devices or browsers.

Works in all modern browsers. May need a fallback for older browsers.

143+
146+
26.4+
143+

Baseline Newly available since 2026 (Chrome 143, Firefox 146, Safari 26.4, Edge 143). Browsers that don't understand @scope drop the whole block, so .title and .body inside it never apply. Those rules have to live outside the at-rule if those versions still matter.

styles scoped to the card only

Inside @scope

These styles only apply here.

Outside @scope

Same class names, no style leak.

Short names

Use .title and .body. They only apply inside the scoped root, so no collisions.

No build

No CSS Modules hash or styled-components runtime. Plain CSS, native in the browser.

Boundary

Optional to (.root) to (.boundary) so inner components don't get styled by outer scope.

Lines Saved
Same lines, less naming
No BEM prefix
Old Approach
BEM or CSS-in-JS
Long names or build step
Modern Approach
@scope
Native scoping

How it works

Global CSS meant long class names (BEM like .card__title) or a system that generated unique names (CSS Modules, styled-components). The goal was to avoid one component's .title affecting another.

@scope (.card) { .title { ... } } makes .title only match elements inside a .card. You can use simple class names and keep styles local. Add a boundary with @scope (.panel) to (.slot) so the scope doesn't cross into nested components that should stay independent. Browsers that don't understand @scope drop the whole block, so those .title and .body rules never apply.

ESC