Skip to content

Commit 9cdfa98

Browse files
committed
chore(v7): trim docs duplication, fix stale gradient/filter/@supports claims
- whats-new: tighten Highlights bullets, link out to native + plugins sections instead of restating their content; drop the disableCSSOMInjection mention that appeared in both Highlights and Removed. - migration: collapse the dedicated rscPlugin / rtlPlugin / SCPlugin sections into a single pointer at the plugins page; defer native specifics to native.mdx and the compatibility matrix. - native: qualify hover with the RN 0.85 feature-flag default, flag the conic-gradient gap and platform-conditional filter / blend-mode / skew rows in Limitations. - cssCompat: add @supports row. The native parser routes its condition through the same evaluator as @media / @container, which only understands media features, so feature-test conditions never gate anything on native and the inner block always applies. - Bump styled-components prerelease to 20260513034901.
1 parent 544eab7 commit 9cdfa98

6 files changed

Lines changed: 74 additions & 87 deletions

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
"react-live-runner": "^1.0.7",
4040
"react-transition-group": "^4.4.5",
4141
"server-only": "^0.0.1",
42-
"styled-components": "7.0.0-prerelease-20260511181437",
42+
"styled-components": "7.0.0-prerelease-20260513034901",
4343
"styled-theming": "^2.2.0",
4444
"stylis": "^4.2.0",
4545
"stylis-plugin-rtl": "^2.1.1"

pnpm-lock.yaml

Lines changed: 22 additions & 22 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

sections/v7/migration.mdx

Lines changed: 8 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -46,68 +46,33 @@ The result is plain CSS, safe to inject into another document via `innerHTML`. T
4646

4747
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.
4848

49-
### `stylisPluginRSC` moved to a subpath
49+
### Plugins moved to a subpath
5050

51-
The top-level export has been removed. Import from `styled-components/plugins` instead, and pass via the renamed `plugins` prop:
51+
`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:
5252

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

5757
-<StyleSheetManager stylisPlugins={[stylisPluginRSC]}>
5858
+<StyleSheetManager plugins={[rscPlugin]}>
5959
```
6060

61-
### RTL is now first-party
62-
63-
`stylis-plugin-rtl` is no longer needed:
64-
65-
```diff
66-
-import rtl from 'stylis-plugin-rtl';
67-
+import { rtlPlugin } from 'styled-components/plugins';
68-
69-
-<StyleSheetManager stylisPlugins={[rtl]}>
70-
+<StyleSheetManager plugins={[rtlPlugin]}>
71-
```
72-
73-
`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.
74-
75-
### Custom stylis plugins need to port
76-
77-
Custom plugins authored against the v6 stylis contract no longer load. Implement the v7 plugin shape:
78-
79-
```ts
80-
import type { SCPlugin } from 'styled-components/plugins';
81-
82-
const scopePlugin: SCPlugin = {
83-
name: 'scope',
84-
// `rw` runs on every fully-resolved selector after `&` substitution and
85-
// namespace prepending. Return a new selector string.
86-
rw: selector => `.app ${selector}`,
87-
// `decl` runs on every emitted `prop: value` pair. Return `{ prop, value }`
88-
// to rewrite, or `undefined` to leave the pair unchanged.
89-
decl: (prop, value) => ({ prop, value }),
90-
};
91-
```
92-
93-
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.
61+
`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.
9462

9563
### Global styles emit once per component
9664

9765
`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.
9866

9967
### React Native bumps and changes
10068

101-
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.
102-
103-
If you're on React Native:
69+
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:
10470

10571
- The peer floor moves to RN ≥ 0.85.
106-
- 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.
107-
- `transform: matrix(...)` / `matrix3d(...)` and bare-number `translateX(N)` work on native.
108-
- `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.
10972
- `border: none` now emits `border-style: none` (previously `solid`, which produced surprising hairlines).
110-
- `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.
73+
- 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.
74+
75+
[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.
11176

11277
### TypeScript
11378

sections/v7/native.mdx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ const Toggle = styled.Pressable<{ 'aria-pressed'?: boolean }>`
6262

6363
The same CSS works on web and native. Anchor pseudo-states with `&` (bare `:hover` parses as a descendant selector, not a state).
6464

65-
**Pseudo-states.** `&:hover`, `&:focus`, `&:focus-visible`, `&:pressed`, `&:disabled`. Hover on native uses Pressable's pointer events; React Native ≥ 0.85.
65+
**Pseudo-states.** `&:hover`, `&:focus`, `&:focus-visible`, `&:pressed`, `&:disabled`. Hover on native uses Pressable's pointer events on RN ≥ 0.85, but stock RN gates them behind `ReactNativeFeatureFlags.shouldPressibilityUseW3CPointerEventsForHover`, which defaults to FALSE in 0.85 — enable it at startup to get `&:hover` to fire.
6666

6767
**Attribute selectors.** The full CSS Selectors 4 grammar works on native:
6868

@@ -189,11 +189,18 @@ These spec features pass through to react-native-web but do not render on React
189189

190190
- `::before` / `::after` / `::placeholder` / `::marker` / `::selection`
191191
- `backdrop-filter`, `mask` / `mask-image` (community packages cover both)
192-
- `background-image: url()` for raster images (gradient `background-image` works)
192+
- `background-image: url()` for raster images (linear / radial gradients work; conic-gradient parses but does not paint on native)
193193
- `clip-path`
194194
- `position: fixed`, `position: sticky`, `position: anchor()` / `anchor-name`
195195
- `text-indent`, `word-spacing`, `text-box-trim`, `text-spacing-trim`
196196
- `transform-style: preserve-3d` (basic `rotateX` / `rotateY` / `translateZ` / `perspective` do work)
197197
- CSS Grid (`display: grid`, `grid-template-*`)
198198
- Form-state pseudos (`:invalid`, `:required`, `:read-only`, `:checked`)
199+
- `@supports` is parsed but its condition is never evaluated against the runtime — declarations inside always apply on native. Branch with `Platform.OS` instead.
199200
- Scroll-snap, view transitions, scroll-driven animations
201+
202+
Platform-conditional features (the matrix has the full story):
203+
204+
- `filter` — only `brightness` and `opacity` apply on iOS without the SwiftUI opt-in (set `ReactNativeReleaseLevel: experimental` in `Info.plist` / `ios.infoPlist`); Android `blur` and `drop-shadow` require API 31+.
205+
- `mix-blend-mode` — all 16 non-Normal modes on iOS; Android needs API 29+.
206+
- `transform: skewX/skewY` — iOS renders correctly; Android silently drops the shear pending an upstream fix.

0 commit comments

Comments
 (0)