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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
"react-live-runner": "^1.0.7",
"react-transition-group": "^4.4.5",
"server-only": "^0.0.1",
"styled-components": "7.0.0-prerelease-20260511181437",
"styled-components": "7.0.0-prerelease-20260513034901",
"styled-theming": "^2.2.0",
"stylis": "^4.2.0",
"stylis-plugin-rtl": "^2.1.1"
Expand Down
44 changes: 22 additions & 22 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

51 changes: 8 additions & 43 deletions sections/v7/migration.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -46,68 +46,33 @@ The result is plain CSS, safe to inject into another document via `innerHTML`. T

The runtime vendor prefixer has been removed. For the properties that still need prefixing on older Safari (`backdrop-filter`, `mask`, `user-select`), declare both the prefixed and unprefixed forms in your CSS, or run a build-time PostCSS transform.

### `stylisPluginRSC` moved to a subpath
### Plugins moved to a subpath

The top-level export has been removed. Import from `styled-components/plugins` instead, and pass via the renamed `plugins` prop:
`stylisPluginRSC` and the v6 `stylisPlugins` prop are gone. Import the first-party plugins from `styled-components/plugins` and pass them via the renamed `plugins` prop:

```diff
-import { stylisPluginRSC } from 'styled-components';
+import { rscPlugin } from 'styled-components/plugins';
+import { rscPlugin, rtlPlugin } from 'styled-components/plugins';

-<StyleSheetManager stylisPlugins={[stylisPluginRSC]}>
+<StyleSheetManager plugins={[rscPlugin]}>
```

### RTL is now first-party

`stylis-plugin-rtl` is no longer needed:

```diff
-import rtl from 'stylis-plugin-rtl';
+import { rtlPlugin } from 'styled-components/plugins';

-<StyleSheetManager stylisPlugins={[rtl]}>
+<StyleSheetManager plugins={[rtlPlugin]}>
```

`rtlPlugin` swaps physical side properties (`padding-left` ↔ `padding-right`), flips `left` / `right` keyword values on `float` / `clear` / `text-align` / `caption-side`, and mirrors 4-value shorthand positions. Logical properties like `margin-inline-start` pass through unchanged.

### Custom stylis plugins need to port

Custom plugins authored against the v6 stylis contract no longer load. Implement the v7 plugin shape:

```ts
import type { SCPlugin } from 'styled-components/plugins';

const scopePlugin: SCPlugin = {
name: 'scope',
// `rw` runs on every fully-resolved selector after `&` substitution and
// namespace prepending. Return a new selector string.
rw: selector => `.app ${selector}`,
// `decl` runs on every emitted `prop: value` pair. Return `{ prop, value }`
// to rewrite, or `undefined` to leave the pair unchanged.
decl: (prop, value) => ({ prop, value }),
};
```

Legacy stylis function plugins don't run in v7 because they don't expose `rw` or `decl`. Production builds ignore them; development builds warn once per unrecognized plugin name.
`stylis-plugin-rtl` is replaced by the first-party `rtlPlugin`. Custom stylis plugins authored against the v6 middleware contract no longer load and must port to the new `SCPlugin` shape. See [Plugins moved to a dedicated subpath](#plugins-moved-to-a-dedicated-subpath) for details and authoring guidance.

### Global styles emit once per component

`createGlobalStyle` components now emit their CSS once even if you mount the same component multiple times. If your app deliberately remounts the same global to re-apply styles, that pattern no longer works; mount once per global rule set.

### React Native bumps and changes

The [CSS Compatibility matrix](/docs/compatibility) is the per-feature source of truth for what changed between v6 and v7 on web and native; the list below covers the most common cases.

If you're on React Native:
The [CSS Compatibility matrix](/docs/compatibility) is the per-feature source of truth for what changed between v6 and v7 on web and native. The most common gotchas:

- The peer floor moves to RN ≥ 0.85.
- The `lab()`, `lch()`, `oklab()`, `oklch()`, and `color-mix()` notations now resolve to displayable colors with hue-preserving gamut mapping. Wide-gamut inputs that fall outside sRGB land at the closest in-gamut color.
- `transform: matrix(...)` / `matrix3d(...)` and bare-number `translateX(N)` work on native.
- `linear-gradient(...)`, `radial-gradient(...)`, and the full `filter` chain (`blur`, `saturate`, `hue-rotate`, ...) work on native. iOS apps need `ReactNativeReleaseLevel: experimental` in `Info.plist` to enable the SwiftUI filter backend for `blur` / `saturate` / `hue-rotate` / `grayscale` / `contrast` / `drop-shadow`. `brightness` and `opacity` work without it.
- `border: none` now emits `border-style: none` (previously `solid`, which produced surprising hairlines).
- `transition`, `@keyframes`, and `@starting-style` all animate on the native thread by default — no extra import, peer dependency, or configuration. If you prefer to drive animations through reanimated 4's CSS layer, opt in once at your app entry with `import 'styled-components/native/reanimated'`; `react-native-reanimated@^4` becomes a peer dependency only in that case.
- The optional reanimated adapter is opt-in at app entry: `import 'styled-components/native/reanimated'`. `react-native-reanimated@^4` becomes a peer dependency only in that case. The adapter is experimental and not heavily tested yet; the default `Animated`-based adapter runs without any setup.

[React Native gets modern CSS](#react-native-gets-modern-css) walks through the new surface (modern color spaces, gradients, filters, selectors, animations, `createTheme()`) and calls out the platform-level caveats — iOS SwiftUI filter opt-in, hover feature flag, conic-gradient gap, and the rest. The compatibility matrix has the per-feature breakdown.

### TypeScript

Expand Down
Loading
Loading