Releases

Updating styled components is usually as simple as npm install. Only major versions have the potential to introduce breaking changes (noted in the following release notes).

styled-components@6.5.3

Patch Changes

  • 3470387: Fix TypeScript errors in projects that augment React HTML props with a data-* template-literal index signature.

styled-components@6.6.0-prerelease-20260815222953

Minor Changes

  • 7ce6aea: Added a StyledComponent<Target, Props> type for annotating explicitly-typed styled component exports.

    Packages that emit their own declaration files, including any project using isolatedDeclarations, must annotate every exported styled component, and there was no public type for it: consumers reached into internal paths or hand-assembled one that dropped members like a wrapped component's hoisted statics.

    StyledComponent is exported from the web and native entries. Name the target and props as you passed them to styled:

    import styled, { type StyledComponent } from 'styled-components';
    
    export const Card: StyledComponent<'div', { $active?: boolean }> = styled.div<{ $active?: boolean }>`...`;
    export const CloseButton: StyledComponent<typeof IconButton> = styled(IconButton)`...`;

    It resolves to the exact type styled(Target)<Props> produces, so the annotation is not lossy.

Full Changelog: https://github.com/styled-components/styled-components/compare/styled-components%406.5.3...styled-components%406.6.0-prerelease-20260815222953

styled-components@6.5.3-prerelease-20260815150702

Patch Changes

  • 3470387: Fix TypeScript errors in projects that augment React HTML props with a data-* template-literal index signature.

Full Changelog: https://github.com/styled-components/styled-components/compare/styled-components%406.5.2...styled-components%406.5.3-prerelease-20260815150702

styled-components@6.5.2

Patch Changes

  • 00b9ee2: .attrs() is cheaper to type-check.

    Two costs on the .attrs path are gone. Object-form .attrs() left the rendered target unchanged but still re-resolved that target's whole prop bag on every call, making .attrs on an HTML or SVG tag far costlier than on a wrapped component; it now reuses the props already resolved for the tag. Separately, making attrs-provided keys optional ran an avoidably expensive pass over the target's full prop set on every attrs component. Together these cut consumer type-check work measurably across every .attrs form, with no change to the resulting component's accepted props. Redirecting the target with .attrs({ as }), including the function form, is unaffected.

  • 00b9ee2: Explicitly annotated styled components type-check faster.

    Assigning a styled component to an explicit type, as isolatedDeclarations and any package that emits .d.ts files must (const Button: IStyledComponentBase<'web', ...> = styled.button``), used to be several times more expensive to check than an inferred one, because the annotation'sstyleand the component's widenedstyle` were two different csstype representations that the checker compared property by property.

    The inline style widening now builds on React's own CSSProperties, the same type a hand-written annotation carries, so that comparison short-circuits. On a 40-component fixture this cut the types created for the annotated pattern by about 21%, with no change to what style accepts: CSS custom properties, a component's own narrow style, and style={undefined} all behave exactly as before.

  • 00b9ee2: styled() wrapping a generic polymorphic component keeps its declared props narrow.

    Wrapping a component whose props are generic over an element type, such as the common <C extends React.ElementType>(props: PolymorphicProps<C, OwnProps>) pattern, used to let the styled result accept prop values the component itself rejects: styled(Button) would take variant="anything" even though <Button variant="anything"> is a type error. The wrapper now narrows those props exactly as the direct component does, so a bad value is caught in both places. Valid props, children, and plain (non-generic) targets are unaffected.

styled-components@6.5.2-prerelease-20260810214005

Patch Changes

  • 00b9ee2: .attrs() is cheaper to type-check.

    Two costs on the .attrs path are gone. Object-form .attrs() left the rendered target unchanged but still re-resolved that target's whole prop bag on every call, making .attrs on an HTML or SVG tag far costlier than on a wrapped component; it now reuses the props already resolved for the tag. Separately, making attrs-provided keys optional ran an avoidably expensive pass over the target's full prop set on every attrs component. Together these cut consumer type-check work measurably across every .attrs form, with no change to the resulting component's accepted props. Redirecting the target with .attrs({ as }), including the function form, is unaffected.

  • 00b9ee2: Explicitly annotated styled components type-check faster.

    Assigning a styled component to an explicit type, as isolatedDeclarations and any package that emits .d.ts files must (const Button: IStyledComponentBase<'web', ...> = styled.button``), used to be several times more expensive to check than an inferred one, because the annotation'sstyleand the component's widenedstyle` were two different csstype representations that the checker compared property by property.

    The inline style widening now builds on React's own CSSProperties, the same type a hand-written annotation carries, so that comparison short-circuits. On a 40-component fixture this cut the types created for the annotated pattern by about 21%, with no change to what style accepts: CSS custom properties, a component's own narrow style, and style={undefined} all behave exactly as before.

  • 00b9ee2: styled() wrapping a generic polymorphic component keeps its declared props narrow.

    Wrapping a component whose props are generic over an element type, such as the common <C extends React.ElementType>(props: PolymorphicProps<C, OwnProps>) pattern, used to let the styled result accept prop values the component itself rejects: styled(Button) would take variant="anything" even though <Button variant="anything"> is a type error. The wrapper now narrows those props exactly as the direct component does, so a bad value is caught in both places. Valid props, children, and plain (non-generic) targets are unaffected.

Full Changelog: https://github.com/styled-components/styled-components/compare/styled-components%406.5.1...styled-components%406.5.2-prerelease-20260810214005

styled-components@7.0.0-prerelease-20260808041113

styled-components@6.5.1

Patch Changes

  • a0a92cd: Fix a styled component silently dropping props declared as a union whose members have no prop in common, which left every one of those props rejected. The same applied when as pointed at a component with such props. Where every member's props are optional the union is still flattened, so declare the combined optional shape instead.
  • a0a92cd: Styled components now report the same debug value to React DevTools on every render. Previously the value was only reported on renders that recomputed styles, so it disappeared from the DevTools panel whenever a component re-rendered with unchanged style props.
  • a0a92cd: Fix wrapping a component whose props are a union. Since 6.5.0 the wrapped version accepted only the props common to every member of the union, so a prop belonging to just one member was rejected even though the unwrapped component accepted it.

styled-components@7.0.0-prerelease-20260807223715

Minor Changes

  • createGlobalStyle rules land before any consumer layout effect. (global-styles-before-layout-effects.md)

    Global styles now write from an insertion effect, which React runs for the whole tree before any layout effect. A component measuring itself in useLayoutEffect reads the styled measurement, where before it could read the unstyled one depending on where the global style component sat in the tree.

    If you were compensating for that ordering, for example by measuring in a passive effect or on a later tick, that workaround can come out.

  • styled-components does no work in a passive or layout effect on its render path. (no-passive-or-layout-effects.md)

    This is a correctness and predictability guarantee rather than a speed one. Where the library needs a lifecycle hook it uses the narrowest thing that fits: a ref callback for teardown that needs a committed host, useSyncExternalStore for external mutable state, and useInsertionEffect for stylesheet writes.

    On React Native several teardowns now run before paint instead of after, so a sibling reading a scroll-snap or anchor registry never paints a frame against a stale entry. The render-count effect is small and was measured rather than assumed: position: sticky elements render once per layout change instead of twice. Scrolling itself is unchanged, and no timing benchmark was run.

    On React Native, anchor-name and scroll-snap-align now require the styled target to forward its ref, because the library registers and deregisters through a ref callback. styled.View and every other host target already do. styled(YourComponent) needs YourComponent to pass ref down to the host element it renders; if it does not, the declaration is inert and says so in development rather than stranding an entry nothing can remove.

    Three carve-outs remain, each documented at its site, so this is a guarantee about the library's own render path rather than an absolute: the position: sticky overlay publish and its paired deregistration, the reanimated @starting-style two-pass flip, and the default Animated adapter's unmount teardown, which is on the path of every animated native component.

Patch Changes

  • Renaming anchor-name on React Native releases the old anchor. (anchor-name-rename-releases-old-rect.md)

    The old name's rect stayed in the registry until the element unmounted, so anchor() and anchor-size() consumers resolving it kept reading a position nothing updated. The rect is now released when the name changes, as documented.

  • A React Native scroller only snaps if it declared scroll-snap-type itself. (scroll-snap-needs-a-declared-type.md)

    scroll-snap-align on a child used to make any styled ScrollView snap, even one that never opted in. Two scrollers sharing a card component meant the one meant to drift freely snapped along with the one that asked to. This matches css-scroll-snap-1, where the initial scroll-snap-type: none makes an element a non-snapping container and a descendant's scroll-snap-align has no effect there.

Full Changelog: https://github.com/styled-components/styled-components/compare/styled-components%407.0.0-prerelease-20260806233720...styled-components%407.0.0-prerelease-20260807223715

styled-components@7.0.0-prerelease-20260806233720

Minor Changes

  • Cut the TypeScript cost of using styled components in an app. A render target's props are resolved once per target instead of once per JSX call site, which is where most of the work was going. Against a fixture of 100 styled components the type count drops to roughly a sixth and peak memory to roughly a quarter, putting v7 slightly under v6 on both. (consumer-type-check-cost.md)
  • A declared style type now constrains the fields it names and leaves the rest of CSS accepted, instead of replacing the target's style outright. Wrap the declaration in the new CustomStyle export to forbid everything it omits rather than writing never for every property by hand. The constraint holds through as and forwardedAs. (declared-style-merges.md)

    Under exactOptionalPropertyTypes a component with a declared style rejects an explicit style={undefined}; declare style?: X | undefined to allow it. Omitting the prop is unaffected.

  • React Native style props are checked against React Native's own style types. The CSS-custom-property widening the web entry applies was reaching the native entry too, so web-only CSS and custom properties were accepted on native components that cannot render them. (native-style-typing.md)

Patch Changes

  • Fix a styled component silently dropping props declared as a union whose members have no prop in common, which left every one of those props rejected. Where every member's props are optional the union is still flattened, so declare the combined optional shape instead. (disjoint-union-props.md)
  • Fix wrapping a component whose props are a union. The wrapped version accepted only the props common to every member, so a prop belonging to just one member was rejected even though the unwrapped component accepts it. The same applied when as pointed at such a component. (union-props-survive-styled.md)
  • Fix wrapping a component whose props cannot be inspected statically, such as the polymorphic factory components Mantine ships. Every prop was rejected, children included. Declaring props of your own on the wrapper no longer switches the behavior back off either. (untyped-target-props.md)

Full Changelog: https://github.com/styled-components/styled-components/compare/styled-components%407.0.0-prerelease-20260731041038...styled-components%407.0.0-prerelease-20260806233720

styled-components@6.5.1-prerelease-20260806232123

Patch Changes

  • a0a92cd: Fix a styled component silently dropping props declared as a union whose members have no prop in common, which left every one of those props rejected. The same applied when as pointed at a component with such props. Where every member's props are optional the union is still flattened, so declare the combined optional shape instead.
  • a0a92cd: Styled components now report the same debug value to React DevTools on every render. Previously the value was only reported on renders that recomputed styles, so it disappeared from the DevTools panel whenever a component re-rendered with unchanged style props.
  • a0a92cd: Fix wrapping a component whose props are a union. Since 6.5.0 the wrapped version accepted only the props common to every member of the union, so a prop belonging to just one member was rejected even though the unwrapped component accepted it.

Full Changelog: https://github.com/styled-components/styled-components/compare/styled-components%406.5.0...styled-components%406.5.1-prerelease-20260806232123

styled-components@6.5.0

Minor Changes

  • dfe4baf: React Native components now check style against React Native's own style types. Web-only CSS such as float, and CSS custom properties such as --brand, were previously accepted even though React Native has never done anything with them at runtime. They now surface as a type error where you write them instead of silently doing nothing.

    const Card = styled.View``;
    
    <Card style={{ padding: 16 }} />; // unchanged
    <Card style={{ float: 'left' }} />; // now a type error

    Web components are unaffected and still accept custom properties.

  • dfe4baf: Declaring your own style prop type now constrains the fields you name while leaving the rest of CSS alone. Previously a declaration like styled.div<{ style?: { width: number } }> was quietly ignored, because the built-in style type was applied after your props, so any CSS value was still accepted. Now width has to be a number, while color, custom properties, and everything else you did not mention keep working as before.

    To remove a field rather than constrain it, declare it as never. To make your type the only thing accepted, wrap it in the new CustomStyle helper, which removes every field you did not list:

    const Box = styled.div<{ style?: CustomStyle<{ width: number }> }>``;

    The constraint holds when the component is rendered through as or forwardedAs, so it cannot be sidestepped by rendering the same component as a different tag. Note that CustomStyle removes CSS custom properties too, since they are among the fields you did not list.

    One thing to know if you use exactOptionalPropertyTypes: on a component that declares its own style, passing style={undefined} explicitly is now rejected. Leaving the prop off is unaffected. Write style?: { width: number } | undefined in your declaration if you need to pass it explicitly.

    Relatedly, reading the style type back off a component (for example with React.ComponentProps) now reports that CSS custom properties are accepted, which matches what was already allowed when rendering.

  • 2949923: Large TypeScript projects type-check dramatically faster. On a 500-component app, tsc check time drops to under a quarter of what 6.4.4 takes and peak memory to under a third, which resolves the out-of-memory failures some projects hit after upgrading past 6.4.2. Both are now better than 6.4.2 was, so there is no longer a reason to pin to it. Editor responsiveness improves by the same margin, and autocomplete on as targets is unchanged.

Patch Changes

  • dfe4baf: Fixed ref being rejected on React Native components created with the shorthand syntax, such as styled.TextInput. Passing a ref, or a ref callback whose parameter you have not annotated, now works the same way it does with styled(TextInput).

    Also fixed a type error when a component's attrs callback is given an explicit parameter type, as in styled.div.attrs<MyProps>(props => props).

  • dfe4baf: Fixed components built on targets whose props cannot be inspected, such as Mantine's polymorphic components, rejecting children and the target's own props once you added a prop of your own:

    const Styled = styled(MantineButton)<{ $variant: 'a' | 'b' }>``;
    
    <Styled $variant="a" variant="filled">
      this now works
    </Styled>;

    Wrapping such a target without adding props already worked; adding one turned the permissiveness off. Your own declared props stay strictly typed either way.

styled-components@6.5.0-prerelease-20260804151232

Minor Changes

  • dfe4baf: React Native components now check style against React Native's own style types. Web-only CSS such as float, and CSS custom properties such as --brand, were previously accepted even though React Native has never done anything with them at runtime. They now surface as a type error where you write them instead of silently doing nothing.

    const Card = styled.View``;
    
    <Card style={{ padding: 16 }} />; // unchanged
    <Card style={{ float: 'left' }} />; // now a type error

    Web components are unaffected and still accept custom properties.

  • dfe4baf: Declaring your own style prop type now constrains the fields you name while leaving the rest of CSS alone. Previously a declaration like styled.div<{ style?: { width: number } }> was quietly ignored, because the built-in style type was applied after your props, so any CSS value was still accepted. Now width has to be a number, while color, custom properties, and everything else you did not mention keep working as before.

    To remove a field rather than constrain it, declare it as never. To make your type the only thing accepted, wrap it in the new CustomStyle helper, which removes every field you did not list:

    const Box = styled.div<{ style?: CustomStyle<{ width: number }> }>``;

    The constraint holds when the component is rendered through as or forwardedAs, so it cannot be sidestepped by rendering the same component as a different tag. Note that CustomStyle removes CSS custom properties too, since they are among the fields you did not list.

    One thing to know if you use exactOptionalPropertyTypes: on a component that declares its own style, passing style={undefined} explicitly is now rejected. Leaving the prop off is unaffected. Write style?: { width: number } | undefined in your declaration if you need to pass it explicitly.

    Relatedly, reading the style type back off a component (for example with React.ComponentProps) now reports that CSS custom properties are accepted, which matches what was already allowed when rendering.

  • dfe4baf: Large TypeScript projects type-check dramatically faster. On a 500-component app, tsc check time drops to under a quarter of what 6.4.4 takes and peak memory to under a third, which resolves the out-of-memory failures some projects hit after upgrading past 6.4.2. Both are now better than 6.4.2 was, so there is no longer a reason to pin to it. Editor responsiveness improves by the same margin, and autocomplete on as targets is unchanged.

Patch Changes

  • dfe4baf: Fixed ref being rejected on React Native components created with the shorthand syntax, such as styled.TextInput. Passing a ref, or a ref callback whose parameter you have not annotated, now works the same way it does with styled(TextInput).

    Also fixed a type error when a component's attrs callback is given an explicit parameter type, as in styled.div.attrs<MyProps>(props => props).

  • dfe4baf: Fixed components built on targets whose props cannot be inspected, such as Mantine's polymorphic components, rejecting children and the target's own props once you added a prop of your own:

    const Styled = styled(MantineButton)<{ $variant: 'a' | 'b' }>``;
    
    <Styled $variant="a" variant="filled">
      this now works
    </Styled>;

    Wrapping such a target without adding props already worked; adding one turned the permissiveness off. Your own declared props stay strictly typed either way.

Full Changelog: https://github.com/styled-components/styled-components/compare/styled-components%406.4.4...styled-components%406.5.0-prerelease-20260804151232

styled-components@7.0.0-prerelease-20260731041038

styled-components@7.0.0-prerelease-20260731035917

Minor Changes

  • Client styles inject through useInsertionEffect. (buffered-injection-default.md)

    Class names are still resolved during render so elements get the right class on the first paint, but the stylesheet write runs in the insertion effect after React commits. Discarded concurrent renders no longer leave rules in the document, and a committed update still gets its rules even when an earlier concurrent attempt for the same styles was discarded. Blocking updates (concurrent features off) behave the same: styles apply on commit, not mid-render.

    ServerStyleSheet SSR and React Server Components still flush during render, where insertion effects do not run.

  • Smaller bundles: styled.div and every other element shorthand is built the first time it is read, so an app ships no table of element names and pays only for the tags it uses. (lazy-element-shorthands.md)

    styled.div, styled.feBlend and the rest behave exactly as before, including returning the same component factory on repeated reads, and 'div' in styled still answers true. Two things differ if you inspect styled itself: Object.keys(styled) no longer lists every tag, and reading a lowercase name that is not a standard element (styled.blink) now hands back a working factory rather than undefined, matching what styled('blink') has always done. CamelCase probes such as toJSON stay undefined.

    Published bundles are also emitted as ES2020 rather than ES2015. Every supported peer (React 19, React Native 0.85, Node 16) runs that syntax natively.

Full Changelog: https://github.com/styled-components/styled-components/compare/styled-components%407.0.0-prerelease-20260731032118...styled-components%407.0.0-prerelease-20260731035917

styled-components@7.0.0-prerelease-20260731032118

styled-components@7.0.0-prerelease-20260731031704

styled-components@7.0.0-prerelease-20260730220331

styled-components@7.0.0-prerelease-20260730205751

styled-components@7.0.0-prerelease-20260730200819

Consolidates the pending v7 changesets by feature area; no behavior or API change. The consolidated entries will appear in the v7.0.0 release notes.

Full Changelog: https://github.com/styled-components/styled-components/compare/styled-components%407.0.0-prerelease-20260730182818...styled-components%407.0.0-prerelease-20260730200819

styled-components@7.0.0-prerelease-20260730182818

Patch Changes

  • A development warning fires when server-rendered styles reach the browser inside a <style> tag that React manages through its precedence attribute. React serves such a tag under its own attributes, so styled-components cannot recognize the styles as its own and injects every rule a second time on the client. The page still looks correct, which is why this goes unnoticed, and the warning names the fix: emit the tag from ServerStyleSheet#getStyleElement() and pass neither precedence nor href. (warn-unadoptable-server-styles.md)

    The warning covers server styles found in the document or in a shadow root at the moment styles are adopted. Styles that arrive later, such as those flushed for a Suspense boundary that resolves after adoption, are outside its reach.

Full Changelog: https://github.com/styled-components/styled-components/compare/styled-components%407.0.0-prerelease-20260730182544...styled-components%407.0.0-prerelease-20260730182818

styled-components@7.0.0-prerelease-20260730182544

Major Changes

  • Raised peer dependency floors: (peer-floors.md)

    • react and react-dom now require >= 19.0.0 (was >= 16.8).
    • react-native now requires >= 0.85.0 (was >= 0.68).
    • css-to-react-native is no longer a peer dependency. Apps that listed it solely for styled-components can drop it from their package.json.

    Older React / React Native projects should stay on styled-components v6.

  • Plugins moved to a dedicated styled-components/plugins subpath, and first-party plugins ship there. (plugins-subpath.md)

    import { StyleSheetManager } from 'styled-components';
    import { rtlPlugin, rscPlugin } from 'styled-components/plugins';
    
    <StyleSheetManager plugins={[rtlPlugin]}>
      <App />
    </StyleSheetManager>;

    The stylisPlugins prop on <StyleSheetManager> is now plugins, the top-level stylisPluginRSC export has moved into the new subpath as rscPlugin, and the enableVendorPrefixes prop has been removed in favor of the opt-in prefixPlugin.

    Migration:

    -import { rtl, stylisPluginRSC } from 'styled-components';
    +import { prefixPlugin, rtlPlugin, rscPlugin } from 'styled-components/plugins';
    
    -<StyleSheetManager stylisPlugins={[rtl, stylisPluginRSC]} enableVendorPrefixes>
    +<StyleSheetManager plugins={[prefixPlugin, rtlPlugin, rscPlugin]}>

    rtlPlugin replaces stylis-plugin-rtl for users coming from v6: it 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.

    prefixPlugin adds vendor prefixes to the CSS you author. It is opt-in per subtree; a <StyleSheetManager> without it emits unprefixed CSS. The prefix set is scoped to the browsers that support the JavaScript APIs React requires (Chrome 45, Firefox 36, Safari 9 / iOS 9, Edge 12), and a construct is prefixed only where one of those browsers still needs it: appearance, user-select, backdrop-filter, position: sticky, filter, clip-path, the mask* family, tab-size, writing-mode, hyphens, image-set() in values, multi-column column*, line-clamp, font-feature-settings, box-decoration-break, text-size-adjust, scroll-snap-type, the inline logical margin and padding longhands, and the ::placeholder, :read-only, and :read-write selectors. Prefixed declarations are emitted ahead of the standard one, so a browser that understands the standard form uses it.

    Flexbox, transforms, transitions, animations, and gradients are left unprefixed, since those browsers need no prefix for them. Declarations you author already prefixed pass through untouched. For a different browser floor or prefix set, declare both forms yourself or write a plugin that emits the prefixes you need. Prefixing applies to web output; see https://styled-components.com/docs/compatibility for the React Native picture.

    Custom plugins authored against the v6 stylis contract need to port to the narrower plugin interface, which exposes rw (selector rewrite) and decl (declaration rewrite) hooks; implement either or both. A hook may return one result or an array (one authored declaration or selector expands into several).

    import type { SCPlugin } from 'styled-components/plugins';
    
    // `rw` runs on every fully-resolved selector after `&` substitution and
    // namespace prepending. Return a new selector string, or an array of
    // selectors to emit one rule per entry.
    const scopePlugin: SCPlugin = {
      name: 'scope',
      rw: selector => `.app ${selector}`,
    };
    
    // `decl` runs on every emitted `prop: value` pair (top-level decls, decl-body
    // at-rules, keyframe frames). Return `{ prop, value }` to rewrite, an array
    // to expand one declaration into several, or `void` to leave the pair unchanged.
    const remToPxPlugin: SCPlugin = {
      name: 'rem-to-px',
      decl: (prop, value) => {
        const match = value.match(/^(-?\d*\.?\d+)rem$/);
        return match ? { prop, value: `${parseFloat(match[1]) * 16}px` } : undefined;
      },
    };

    Custom plugins compose with the first-party ones left to right: pass plugins={[prefixPlugin, myPlugin]} and myPlugin runs on every declaration and selector prefixPlugin emitted.

    The name field is required and identifies the plugin so different plugin sets across nested <StyleSheetManager> trees stay isolated. Each plugin is tree-shaken out of any bundle that doesn't import it.

Full Changelog: https://github.com/styled-components/styled-components/compare/styled-components%407.0.0-prerelease-20260730151206...styled-components%407.0.0-prerelease-20260730182544

styled-components@7.0.0-prerelease-20260730151206

styled-components@7.0.0-prerelease-20260730150545

styled-components@7.0.0-prerelease-20260719013821

Minor Changes

  • Polymorphic as-target attribute autocompletion now works in editors. Typing <StyledComponent as="video" and then a partial attribute name surfaces that target's attributes (loop, muted, controls, poster, ...), including while the attribute name is still being typed. Plain usage keeps completing the component's own props, and forwardedAs targeting is unchanged. Runtime behavior is identical. (polymorphic-as-target-autocomplete.md)

Full Changelog: https://github.com/styled-components/styled-components/compare/styled-components%407.0.0-prerelease-20260611043336...styled-components%407.0.0-prerelease-20260719013821

styled-components@6.4.4

Patch Changes

  • 537ea42: Reduce TypeScript type-checking cost for styled components, most noticeably styled(Component) wrappers and polymorphic as usage. Large codebases that saw elevated tsc memory and type-instantiation counts get lower type-check memory and time, with no change to the emitted types or runtime behavior.

styled-components@6.4.4-prerelease-20260718230802

Patch Changes

  • 537ea42: Reduce TypeScript type-checking cost for styled components, most noticeably styled(Component) wrappers and polymorphic as usage. Large codebases that saw elevated tsc memory and type-instantiation counts get lower type-check memory and time, with no change to the emitted types or runtime behavior.

Full Changelog: https://github.com/styled-components/styled-components/compare/styled-components%406.4.3...styled-components%406.4.4-prerelease-20260718230802

styled-components@6.4.3

Patch Changes

  • f692ec2: Fix a TypeScript error when wrapping a component whose props can't be statically read, such as Mantine v7's polymorphic-factory components (Button, Card, Menu.Item, and similar). These styled components no longer reject every prop, including children; arbitrary props are accepted again at the JSX call site and via .attrs(), while components with readable prop types stay fully type-checked.
  • f692ec2: Keep TypeScript attribute autocomplete working while you type props on a polymorphic styled component. When a component renders a different element through as (for example as="video"), beginning to type a new prop name could make the whole suggestion list vanish; the rendered element's props now keep autocompleting as you go.

styled-components@7.0.0-prerelease-20260611043336

Major Changes

  • React Native: createTheme() works the same way it does on the web. Pass the returned object to ThemeProvider, reference leaves in your styled components, and the current theme resolves automatically. (createTheme-native-parity.md)

    import styled, { createTheme, ThemeProvider } from 'styled-components/native';
    
    const theme = createTheme({
      colors: { bg: '#ffffff', text: '#111111' },
    });
    
    const Card = styled.View`
      background-color: ${theme.colors.bg};
      border-color: ${theme.colors.text};
    `;
    
    <ThemeProvider theme={{ colors: { bg: '#111', text: '#eee' } }}>
      <Card />
    </ThemeProvider>;

    Nested ThemeProviders on React Native deep-merge their theme objects so an inner override that only touches one leaf keeps the siblings it inherited; a child provider that sets colors.text keeps colors.bg from the ancestor. Behavior on the web is unchanged.

  • A styled component does not honor defaultProps, and it does not inherit a wrapped component's defaultProps. React 19 removed defaultProps support from function components. (drop-default-props.md)

    Migration: use .attrs() for prop defaults. The object form always wins over user-provided props (this is intentional, see the attrs FAQ). The function form lets user-provided props override the default:

    // Before (v6, no longer applies in v7)
    const Button = styled.button``;
    Button.defaultProps = { type: 'button' };
    
    // After (object form always wins)
    const Button = styled.button.attrs({ type: 'button' })``;
    
    // After (user-provided overrides allowed)
    const Button = styled.button.attrs<{ type?: string }>(p => ({
      type: p.type ?? 'button',
    }))``;

    For a default theme, wrap the tree in <ThemeProvider theme={...}> instead.

  • Browser builds use a single fast injection path; dev and production behave identically. The disableCSSOMInjection prop on <StyleSheetManager> and the SC_DISABLE_SPEEDY / REACT_APP_SC_DISABLE_SPEEDY environment variables are removed, and there is no runtime toggle into a text-based injection mode. A new extractCSS export is available. (extract-css-and-drop-speedy-toggle.md)

    To make CSS visible as text (for static-render pipelines, micro-frontend cloning, embedding into iframes or Shadow DOM, or extraction tooling), call extractCSS() after render to get the current CSS as a plain string:

    import { extractCSS } from 'styled-components';
    
    // after rendering
    const css = extractCSS();

    The result is plain CSS without the rehydration markers used by ServerStyleSheet, so it can be injected directly into another document, stamped into a cloned DOM tree, or written to disk.

  • Mounting the same createGlobalStyle component multiple times emits its CSS only once. Rendering output stays byte-stable across SSR, client, and Server Components. (global-style-useid.md)
  • React Native: isolation: isolate is supported on iOS, Android, and the web. Blended descendants (mix-blend-mode) composite against the isolated element's own group, matching across all three targets. Separately, when a filter on iOS uses effects the platform only renders at the experimental release level, development builds warn that the effect is invisible and that it suspends descendant mix-blend-mode compositing while mounted. (isolation-isolate-android-layer.md)
  • React Native: CSS-to-style-object translation is built in. The native path supports a broad set of modern CSS: (native-transform-layer.md)

    • transform: matrix(...) / matrix3d(...).
    • transform: translateX(10) (bare number, no unit).
    • background-image: linear-gradient(...) / radial-gradient(...).
    • filter: blur(4px) saturate(1.5) and the full filter-function chain.
    • Modern color notations: rgb(r g b / a) slash-alpha, hwb(), hsl().
    • box-shadow with spread and inset.
    • mix-blend-mode, isolation, cursor.
    import styled from 'styled-components/native';
    
    const Tile = styled.View`
      background-image: linear-gradient(135deg, hsl(220 80% 60%), hsl(280 70% 50%));
      filter: blur(2px) saturate(1.5);
      box-shadow: 0 4px 12px rgb(0 0 0 / 0.2);
      transform: matrix(1, 0, 0, 1, 8, 0);
    `;

    border: none emits border-style: none on native, matching the rest of the ecosystem.

    text-decoration: underline without a color follows the text color, matching CSS's currentcolor initial value; an authored color still applies (on iOS and the web; Android always paints decorations in the text color and warns in development when a color is authored).

    iOS setup note for filters: in React Native 0.85, the filter primitives blur, saturate, hue-rotate, grayscale, contrast, and drop-shadow only render when your iOS app opts into the SwiftUI-based filter backend. Set ReactNativeReleaseLevel to experimental in your iOS Info.plist (or ios.infoPlist in app.json for Expo) to enable it. brightness and opacity are supported without this flag.

  • react-native-web: CSS the browser implements natively reaches it untouched. This covers math functions with units (calc(), min(), max(), clamp(), round() and friends), viewport units (dvh / svh / lvh stay distinct), standalone translate / rotate / scale (3D values keep their Z component on the web), transform-style, transform-box, perspective, light-dark(), CSS system color keywords, wide-gamut color functions with theme values, hyphens, text-wrap, caret-color, accent-color, overscroll-behavior, scrollbar-width, field-sizing, interactivity, and direction. Native-only prop mappings and their platform-limitation warnings are scoped to the native targets and do not appear on the web. (rn-web-browser-native-passthrough.md)
  • React Native: @supports conditions are evaluated as real feature queries. A condition like @supports (display: grid) answers based on what the current platform can actually render, not / and / or combinations follow the CSS grammar (invalid mixes are ignored as the spec requires), unknown future syntax such as selector(...) evaluates to false, and on the web the browser answers directly. Probing for an unsupported feature inside @supports is silent: the query is the supported way to ask, so it does not emit the development warning for that feature. (supports-real-feature-queries.md)
  • React Native: z-index: auto resolves to the platform default stacking (the behavior CSS defines for auto) on iOS and Android, and passes through to the browser on the web. (z-index-auto-native.md)

Minor Changes

  • Added a second argument to function-form attrs((props, ast) => ...) callbacks for bridging styles into props on third-party components. The ast accessor exposes peek (read a value) and pop (read and remove from the rendered style), and accepts either a CSS property name or a typed dot-separated theme path (e.g. 'color.red.500'). Path autocomplete and value-type inference flow from your augmented theme. (attrs-ast-bridge.md)

    import { Path } from 'react-native-svg';
    
    const Icon = styled(Path).attrs((_props, ast) => ({
      fill: ast.pop('color'), // lift CSS decl into a prop
      stroke: ast.peek('palette.brand'), // read from theme via typed path
    }))`
      color: red;
    `;

    Both methods take an optional fallback as the second argument, returned when the value is missing. Supported on the web and React Native, with no per-render overhead when the callback resolves entirely from static declarations.

  • React Native: modern CSS functions are supported in styles. Values that can be calculated immediately are converted before they reach React Native, while values that depend on the device, like viewport size, safe area, container size, or color scheme, update when those inputs change. (modern-css-polyfills.md)

    import styled from 'styled-components/native';
    
    const Card = styled.View`
      width: clamp(240px, 80vw, 480px);
      background-color: light-dark(white, #111);
      padding-top: env(safe-area-inset-top);
      border-radius: 8px;
    
      @container card (min-width: 320px) {
        padding: 24px;
      }
    `;
    • clamp(10px, 50%, 400px), min(100px, 50vw), max(200px, 100vh), and calc(100vw - 40px).
    • Math functions like round(), mod(), rem(), sin(), cos(), tan(), pow(), sqrt(), hypot(), log(), exp(), abs(), and sign() when their inputs are known before render.
    • oklch(...), oklab(...), lch(...), lab(...) resolve to a color React Native can render. Wide-gamut inputs that fall outside sRGB are mapped to the closest in-gamut color while preserving hue, so the rendered result stays as close as possible to what was written.
    • color-mix(in <space>, …) mixes through the requested space (srgb, oklab, oklch, lab, lch) and converts back to sRGB for display.
    • Viewport units vw / vh / vmin / vmax / dvh / svh / lvh scale to the current window dimensions.
    • Container query units cqw / cqh / cqmin / cqmax scale to the nearest ancestor container.
    • light-dark(light, dark) swaps based on OS appearance.
    • env(safe-area-inset-top | right | bottom | left) reads from the device safe area.
    • Logical shorthands margin-inline, margin-block, padding-inline, padding-block, inset-inline, inset-block apply as authored.
    • line-clamp: N truncates to N lines.
    • &:is(:hover, :focus) and &:where(:pressed, :disabled) apply the styles to each listed state.
    • @media (min-aspect-ratio: 16/9), (max-aspect-ratio: 1/1), and exact (aspect-ratio: 4/3) match the device's current width-to-height ratio. Bare numbers are treated like <n>/1, matching browser behavior.
    • @starting-style { ... } declarations apply on first mount: the starting values are the initial state and any transitions on the same component animate from there toward the resolved values.

    The full, current support matrix for CSS on React Native lives at https://styled-components.com/docs/compatibility.

  • React Native: accent-color is supported on every target. Applied to a styled.Switch, it tints the on-state surface so the control picks up the value (the closest analog to the behavior on the web of tinting a checked checkbox). Both <color> values and accent-color: auto are accepted; auto resolves to the platform's accent color. (native-accent-color.md)

    The same color forms apply here as in every other color slot in styled-components: HTML named colors, CSS Color 4 system keywords, hex, modern color functions, and theme tokens.

    For wrapping a third-party component (Slider, Checkbox, ProgressBar, etc.) whose tint prop isn't <Switch>.trackColor, use the function form of .attrs(...) with the AST bridge to forward the resolved value:

    const ThemedSlider = styled(Slider).attrs<{ thumbTintColor?: string }>((_props, ast) => ({
      thumbTintColor: ast.pop('accentColor'),
    }))`
      accent-color: red;
    `;

    ast.pop('accentColor') returns the resolved value and removes it from the style bag so it doesn't reach the wrapped component as an unrecognized style key. Cascade-style inheritance from an ancestor accent-color declaration down to a descendant <Switch> is not implemented in this release; declare accent-color on the Switch itself (or use the attrs recipe above when wrapping).

  • Added CSS anchor positioning on React Native (core subset). Declare anchor-name: --save on any styled element and position absolutely-placed siblings against it in pure CSS: top: anchor(--save bottom); left: anchor(--save left); width: anchor-size(--save width);. Anchored elements track the anchor as it moves or resizes, fallback values apply when the anchor is missing, position-anchor supplies an implicit target, and the functions compose inside calc(). Supported subset: physical side keywords in top/left insets, with the anchor and positioned element sharing a parent; unsupported forms fall back with a development warning. On the web the browser handles the same declarations natively. (native-anchor-positioning.md)
  • React Native: CSS transition, @keyframes, and @starting-style animate. (native-animation-adapter.md)

    const fade = keyframes`
      from { opacity: 0; }
      to   { opacity: 1; }
    `;
    
    const Toast = styled.View`
      background-color: ${p => p.$bg};
      transition: background-color 280ms ease-out;
      animation: ${fade} 240ms ease-out both;
      @starting-style {
        opacity: 0;
      }
    `;

    Animation is on by default. No extra import, peer dependency, or configuration. Eligible properties (opacity, every color, all border radius corners, transforms, shadows, filter) run on the native thread for jank-free 60 fps playback. Keyframes drive multi-segment interpolations with per-frame easing, and the full grammar of animation-direction, animation-fill-mode, animation-play-state, and animation-iteration-count (integer, fractional, or infinite) is supported. Spec-correct color interpolation in oklab keeps mid-transition colors faithful.

    Spec-correct CSS easing: ease, ease-in, ease-out, ease-in-out, cubic-bezier(), steps(), and linear() all map to their W3C-spec curves. The CSS ease keyword maps to the W3C ease curve, not React Native's Easing.ease (which is the ease-in curve and a common source of subtle visual mismatches in other libraries).

    Honors prefers-reduced-motion: when the OS setting is on, durations collapse to 0 and animations snap.

    If your app already uses react-native-reanimated@^4 on Fabric (New Architecture), you can route animations through its UI-thread-compiled CSS layer instead by importing the alternate adapter once at your app entry:

    import 'styled-components/native/reanimated';

    This is purely opt-in; everything above works without it. react-native-reanimated is an optional peer dependency and is only required if you take this import.

  • React Native: the CSS attr() function is supported. Styles can read the component's own props as typed CSS values: width: attr(data-size px, 48px) sizes from a data-size prop and uses the fallback when the prop is missing or invalid. Supported types include unit names (px, %, deg, ...), number, raw-string, and type() forms for lengths, numbers, percentages, and colors. attr() composes inside calc(), and fallbacks can themselves be dynamic values like light-dark(). (native-attr-function.md)
  • React Native supports :not(<simple-selector>). Rules such as :not(:hover), :not(:focus), :not([disabled]), and :not([data-state='loading']) apply when the inner condition does not match. More complex forms, including multiple selectors or nested descendant selectors, are not supported on native: they show a development warning and are ignored. (native-attr-operators-and-not.md)
  • React Native: attribute selectors apply styles based on the rendered element's props. (native-attribute-selectors.md)

    const Toggle = styled.Pressable`
      background: white;
      &[aria-pressed='true'] {
        background: yellow;
      }
    `;
    
    <Toggle aria-pressed={true} />; // yellow background

    The same CSS is supported on the web and on React Native. This is especially useful for aria-* props, since React Native passes them to platform accessibility services. Presence checks like &[attr] match when the prop is defined, and exact matches like &[attr='value'] compare the rendered prop value as text, so aria-pressed={true} and aria-pressed="true" both match [aria-pressed='true']. Substring, prefix, suffix, word, and case-insensitive matches are supported too.

  • React Native: box-sizing and hyphens are supported. (native-box-sizing-and-hyphens.md)

    import styled from 'styled-components/native';
    
    const Card = styled.View`
      box-sizing: border-box;
      padding: 16px;
      border: 1px solid #ccc;
    `;
    
    const Paragraph = styled.Text`
      hyphens: auto;
    `;

    box-sizing: border-box | content-box flows through unchanged on iOS, Android, and react-native-web.

    hyphens: none | manual | auto controls automatic word-breaking. On Android the value drives the system hyphenation frequency. On iOS automatic hyphenation can't be enabled programmatically, so auto falls back to manual breaking; embed soft-hyphens (U+00AD) in source text to control break points there. On react-native-web the browser handles it natively.

  • React Native: several CSS properties are supported across platforms: caret-color, object-fit, vertical-align, backface-visibility, and outline-offset. (native-caret-color-and-passthroughs.md)

    import styled from 'styled-components/native';
    
    const SearchField = styled.TextInput`
      caret-color: #00aacc;
      border: 1px solid #ccc;
    `;
    
    const Avatar = styled.Image`
      object-fit: cover;
      width: 64px;
      height: 64px;
    `;
    
    const Badge = styled.Text`
      vertical-align: middle;
    `;

    caret-color: auto | <color> colors the text-insertion caret. On Android the color is applied to the caret only, leaving selection-range highlight untouched. On react-native-web the browser handles it natively. iOS keeps its default caret color in this release: React Native's iOS selection API tints the caret and selection range together, which would violate the spec's "caret only" contract. Pass selectionColor directly on <TextInput> if an iOS-specific tint is needed.

    object-fit, vertical-align, backface-visibility, and outline-offset flow through unchanged on iOS, Android, and react-native-web.

  • React Native: em, lh, and rlh length units are supported. Values like padding: 1em, gap: 0.5lh, and min(10px, 5em) resolve against the current text size and line height, so typography-based spacing can be shared across the web and React Native without rewriting everything to pixels. (native-cascade-em-lh-direction-aware-text-align.md)

    text-align: start, text-align: end, and text-align: match-parent resolve under both left-to-right and right-to-left writing directions on React Native, matching the direction-aware behavior on the web.

    Components whose CSS declares font-size, line-height, or direction pass the resolved value to descendants, so one text size at the top of a card can drive the relative spacing inside it.

  • React Native: descendant and child combinator selectors are supported across styled components. (native-combinator-selectors.md)

    const Card = styled.View`
      padding: 16px;
    `;
    const Title = styled.Text`
      font-size: 14px;
      ${Card} & {
        font-size: 18px;
      }
    `;
    
    <Card>
      <Title>Bigger inside a Card</Title>
    </Card>
    <Title>Default size when standalone</Title>

    The descendant form ${Card} & matches whenever the component is rendered anywhere inside Card. The child form ${Card} > & only matches when Card is the nearest styled parent. Regular React Native components can sit between styled components without breaking selector matching.

    The same selectors are supported on the web. This also fixes a web bug where ${Component} { ... } rules placed after another declaration could lose the component selector and target too broadly.

  • React Native: the corner-shape property is supported. round renders iOS's circular corner curve and squircle (along with nearby superellipse() values) renders the Apple-smooth continuous curve. Contours React Native can't draw (bevel, notch, scoop, square, far-out superellipse values, and corners that mix shapes) drop with a development warning suggesting round or squircle. Android renders circular corners and warns that the curve only takes effect on iOS. On the web the value passes through to browsers that support it. (native-corner-shape.md)

    const Card = styled.View`
      border-radius: 16px;
      corner-shape: squircle;
    `;
  • React Native supports CSS custom properties through the component cascade. (native-css-var-warn.md)

    Declare a property on any styled component (--brand: tomato;) and descendants can read it back through the standard var() syntax (color: var(--brand);). The substitution honors the full CSS Variables Module Level 1 contract: fallbacks (var(--maybe, default)), nested resolution (var(--a, var(--b, default))), nested resolution in the name argument (var(var(--name-of-name))), cycle detection, and case-sensitive names. A substituted shorthand expands to its longhands like authored CSS, so margin: var(--spacing); with --spacing: 4px 8px; sets the individual margin sides.

    Spec compliance touches:

    • --foo: initial correctly resets a custom property to the guaranteed-invalid value, so a downstream var(--foo, fallback) substitutes the fallback.
    • Trailing !important is stripped from custom property values before they reach the cascade.
    • A literal var(--name) inside a quoted CSS string (e.g. content: "var(--brand)") is preserved verbatim.
    • Bare -- declarations are dropped (reserved for future use per the spec) and never leak as a style key.

    The react-native-web bundle leaves both the declarations and var() references in place so the browser's own cascade handles them. A development warning fires on a var() reference only when no ancestor declared the property and no fallback was provided.

  • React Native: field-sizing: content makes a TextInput autosize to its content. (native-field-sizing-content.md)

    const Note = styled.TextInput`
      field-sizing: content;
      min-height: 44px;
      padding: 8px 12px;
      border: 1px solid #ddd;
    `;
    
    <Note placeholder="Start typing…" />;

    The field grows in height as the user types, no controlled height state, no onContentSizeChange wiring. Pass multiline={false} explicitly to keep a fixed single-line field (a development warning points out that autosize is off in that case).

    On react-native-web the declaration is handed straight to the browser, which has supported field-sizing natively since Chrome 123.

  • CSS font-size keywords produce identical pixel sizes on iOS, Android, and the web. Absolute-size keywords (xx-small, x-small, small, medium, large, x-large, xx-large, xxx-large) resolve to 9, 10, 13, 16, 18, 24, 32, 48 (the reference table modern browsers use at the default medium of 16px). Relative-size keywords (smaller, larger) resolve at render time against the inherited cascade font-size, stepping to the next entry on the absolute-size ramp when the inherited size matches a keyword and otherwise multiplying by 1.2. (native-font-keyword-parity.md)

    Other CSS Fonts shorthand keyword classes that React Native cannot replicate exactly drop with a development warning that names the offending keyword and suggests a concrete alternative:

    • Font-width / font-stretch keywords (condensed, expanded, etc.) drop because React Native does not control glyph width.
    • System font names (caption, icon, menu, message-box, small-caption, status-bar) drop because the per-platform meaning has no cross-platform mapping; pick a font-family explicitly.
  • Four React Native CSS surfaces are supported: (native-font-line-height-caret-line-width.md)

    • font-size accepts the full CSS length grammar: absolute-size keywords (xx-small through xxx-large), relative-size keywords (larger / smaller), absolute lengths (pt, pc, in, cm, mm, Q), font-relative units (em, rem, lh, rlh plus the font-metric forms ex, cap, ch, ic and their r-variants), viewport units (vh, vw, dvh, svh, lvh and width counterparts), container-query units (cqh, cqw, cqi, cqb, cqmin, cqmax), and percentages. Keyword sizes resolve to a fixed pixel ramp on every platform; everything else folds against the current environment at render time.
    • line-height accepts the same expanded set: absolute lengths, font-relative units (including font-metric forms), viewport units, container-query units, and percentages all resolve against the cascade.
    • caret-color on iOS applies the authored color to the text input's caret. iOS exposes a single surface for the caret and selection highlight, so the selection picks up the same color as a side-effect (a development warning names the deviation). Android maps the color to the caret; react-native-web lets the browser handle it.
    • round(line-width, A) snaps A to the device pixel grid at render time using the platform's pixel ratio, matching the CSS Values 4 "snap a length as a line width" algorithm. Useful for hairline borders that should align to physical pixels regardless of screen scale.

    translate: x y z keeps its Z value on React Native; the three-argument translate(x, y, z) form is supported on iOS and Android.

    transform-style: preserve-3d is isolated automatically for animated 3D transforms; the development warning for static declarations names that they have no effect on iOS without a perspective surface.

  • React Native: a display: grid layout subset is supported. A grid container written as display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; lays its direct styled children into equal columns, sizing each child to its share of the measured container width. Use grid-column: span 2 to make a child span multiple columns. (native-grid-subset.md)

    const Grid = styled.View`
      display: grid;
      grid-template-columns: repeat(3, 1fr);
      gap: 12px;
    `;
    const Wide = styled.View`
      grid-column: span 2;
    `;

    The supported subset is equal 1fr columns (repeat(N, 1fr) or a 1fr 1fr 1fr track list) plus gap / row-gap / column-gap and grid-column: span N on direct children. Anything outside it, including fixed-pixel tracks, minmax(), auto-fill / auto-fit, unequal fractions, and line-number or named-line placement, is ignored with a development warning that names a supported alternative, and the container falls back to a wrapping row. On the web the browser lays out the full grid as written.

    A grid container that also declares container-type is a container-query container at the same time: descendants can use @container rules and cq* units against its measured box.

  • React Native supports the :has(<simple>) selector. (native-has-selector.md)

    const Card = styled.View`
      padding: 16px;
      &:has(${Icon}) {
        padding-left: 48px;
      }
      &:has([data-state='active']) {
        background-color: tomato;
      }
    `;
    
    <Card>
      <Icon />
    </Card>;

    The rule checks the component's children at render time and applies when any descendant matches. Two forms are supported on native:

    • ${Component}: matches when the referenced styled component appears anywhere inside.
    • [attr] and [attr=value]: match when any descendant has the named prop. Value checks compare the rendered prop value as text, so aria-pressed={true} and aria-pressed="true" both match [aria-pressed='true'].

    More complex selectors inside :has(), such as descendant chains, sibling selectors, and nested :has() calls, are not supported on native.

  • React Native supports CSS !important. (native-important-support.md)

    Authoring color: red !important; inside a styled component on native behaves like the web:

    • The !important marker is stripped from the rendered value, and the declaration applies its color.
    • Important declarations beat any normal declaration on the same property, regardless of source order, including overrides from matched @media, @container, @supports, attribute selectors, pseudo states (:hover, :focus, :active, :disabled), :has(), :nth-child(), and combinator selectors.
    • A shorthand marked !important propagates to every longhand (padding: 4px 8px !important is important across padding-top / -right / -bottom / -left).
    • Importance carries through var() substitution and render-time resolvers (light-dark(), env(), viewport units, theme tokens).
    • Spec-aligned with the web: a styled component's !important beats a runtime style={{ ... }} prop, while normal declarations stay overridden by the runtime style prop.
    • Case-insensitive on the marker (!IMPORTANT) and tolerant of whitespace between ! and important.

    !important inside @keyframes is ignored, matching the CSS Animations spec.

    Cross-component cascade of !important for inherited properties (a parent's !important font-size defeating a child's normal one) is not supported; coverage is within-component only.

  • React Native: :nth-child(an+b of S) and :nth-last-child(an+b of S) are supported. The formula counts position within the filter, so :nth-child(2n+1 of [data-active]) selects every odd active sibling regardless of inactive siblings between them. The of S inner accepts a styled component reference or a single attribute selector (the same simple-selector forms :has() accepts on native). Complex inner selectors with combinators or descendant chains warn and fall through. (native-nth-child-of-selector.md)

    const Row = styled.View`
      background: white;
      &:nth-child(2n + 1 of [data-active]) {
        background: silver;
      }
    `;
  • React Native: position: sticky is supported. Direct styled children of a styled ScrollView stick to the top edge and hold position exactly through flings and fast scrolling, with literal declarations and function interpolations alike. On the web the browser handles it. The current support matrix lives at https://styled-components.com/docs/compatibility. (native-position-sticky.md)
  • React Native: the @property rule is supported. Custom properties can be registered with a typed syntax, an initial value, and an inheritance switch: an unset registered property resolves var() references to its typed initial value, and inherits: false registrations stop ancestor values from leaking into descendants. Invalid rules (missing descriptors, initial values that don't match the declared syntax) are ignored with a development warning, matching the spec. On the web, registrations forward to the browser's own CSS.registerProperty(). (native-property-rule.md)
  • React Native: relative color syntax is supported for the rgb(), hsl(), hwb(), and color() forms, alongside oklch() / oklab() / lch() / lab(). A value like color: rgb(from ${theme.brand} r g b) resolves to a color React Native can display on iOS, Android, and react-native-web, whether the base is a literal color, another color function, or a resolved theme value. (native-relative-color-completion.md)
  • React Native: relative color syntax is supported. You can write values like oklch(from #f00 calc(l - 0.15) c h) to derive a new color from a base color, and styled-components renders the result consistently on iOS, Android, and the web. The oklch, oklab, lch, and lab forms are supported. (native-relative-color-fold.md)

    The base color can be a literal color, another modern color function, or a theme value such as oklch(from ${theme.colors.brand} calc(l - 0.15) c h). That makes it possible to build lighter, darker, or more transparent variants from one source color without maintaining a separate shade table.

  • React Native: CSS scroll-driven animations are supported. animation-timeline: scroll() binds any @keyframes animation's progress to the scroll position of the nearest styled ScrollView, enabling parallax, scroll progress bars, and reveal-on-scroll in plain CSS. Scrollers can declare named timelines with scroll-timeline: --name for descendants to reference, and animation-range limits an animation to a slice of the scroll distance (animation-range: entry 25% 75%, lengths and calc() included). Iteration counts and all four direction modes apply across the scroll range. The same declarations are supported on the web. (native-scroll-driven-animations.md)
  • React Native: CSS scroll snap is supported on styled.ScrollView. Declare scroll-snap-type on the scroller and scroll-snap-align: start | center | end on its children, exactly like the web: the children become real snap positions (mixed sizes welcome), and scroll-snap-stop: always on a child keeps a fast fling from skipping past it. A settle guarantee makes mandatory literal on Android, where the platform engine can otherwise leave a caught scroller resting between snap points. (native-scroll-snap.md)

    Without aligned children, mandatory approximates with full-scrollport paging and a development warning; for manual control pass snapToInterval or snapToOffsets on the ScrollView and your props win. proximity applies fast deceleration only. On the web the browser handles all of these properties directly.

  • React Native: CSS overscroll-behavior and scrollbar-width are supported. Apply them to a styled.ScrollView, styled.FlatList, styled.SectionList, or styled.VirtualizedList: (native-scroll-surfaces.md)

    • overscroll-behavior: contain | none disables both bounce on iOS and the over-scroll glow on Android. overscroll-behavior: auto (the initial value) restores the platform defaults.
    • scrollbar-width: none hides both scroll indicators; auto and thin keep the platform default (React Native does not expose a thin-scrollbar surface). thin is equivalent to auto on native per the spec note that user agents may disregard thin.

    Web builds continue to forward the declaration so the browser handles it natively.

  • React Native: styled scrollers (styled.ScrollView, styled.FlatList, and friends) nest like the web. A vertical scroller inside another vertical scrollable receives gestures on Android without passing nestedScrollEnabled yourself; iOS and the web behave this way too. Passing the prop explicitly still wins. (native-scroller-ergonomics.md)

    Declared scroller dimensions hold. React Native's ScrollView stretches and shrinks with its flex parent by default, so height: 280px on a styled scroller could render taller or shorter than written. A styled scroller that declares an explicit width or height keeps it, matching how CSS sizes a scroll container on the web. Scrollers without a declared dimension keep the fill-parent behavior, and declaring any flex property yourself takes precedence.

  • React Native: styled.ScrollView defaults to flex-shrink: 0, matching styled.View. An explicit width: or height: declaration pins reliably even when the component sits in a flex parent. Declare flex-shrink: 1 in your own template to let the layout engine resize it instead. (native-scrollview-flex-shrink.md)
  • React Native: sibling combinator selectors and the :nth-child family are supported. (native-sibling-and-nth-child.md)

    const Card = styled.View`
      padding: 16px;
    `;
    const Divider = styled.View`
      height: 1px;
      ${Card} + & {
        margin-top: 8px;
      }
    `;
    
    const ListItem = styled.View`
      padding: 8px;
      &:nth-child(odd) {
        background-color: gainsboro;
      }
      &:first-child {
        border-top-width: 0;
      }
    `;

    Supported selector forms include:

    • Adjacent sibling: ${Component} + &, which applies when the previous styled sibling is the referenced component.
    • General sibling: ${Component} ~ &, which applies when any earlier styled sibling is the referenced component.
    • :first-child, :last-child, :only-child.
    • :nth-child(N), :nth-child(an+b), :nth-child(odd), :nth-child(even).
    • :nth-last-child(...) (same syntax as :nth-child, counting from the end).
    • :first-of-type, :last-of-type, :only-of-type, :nth-of-type(...), and :nth-last-of-type(...), which count siblings of the same element type.

    These selectors follow the component's JSX position among its siblings. Regular React Native components can sit between styled components without breaking selector matching.

  • React Native: system color keywords such as Canvas, CanvasText, Field, FieldText, GrayText, Highlight, and LinkText are supported when used alone or inside composite declarations such as border, outline, background, text-decoration, text-shadow, box-shadow, filter / drop-shadow(), multi-value border-color, and two-token caret-color values. Values like color: CanvasText and background-color: Canvas adapt to the user's appearance and platform color settings where React Native exposes them, with readable fallbacks for unsupported native semantics. On the web the browser handles these keywords directly. (native-system-colors.md)

    Keywords match regardless of casing.

  • CSS text-overflow: ellipsis | clip is supported on every target. Pair it with line-clamp or text-wrap: nowrap so the content can actually overflow. (native-text-overflow-and-direction-mirror.md)

    direction: ltr | rtl | inherit follows the cascade through bidi-aware text on every target without having to set a second prop.

    outline declarations that include the hidden keyword, like outline: 2px hidden red, are not supported and drop with a development warning, since hidden is not a legal outline style per the CSS UI spec. Use outline: none to remove an outline.

  • Multi-shadow text-shadow lists are supported. React Native renders a single shadow per Text element, so on iOS and Android the first (topmost) shadow in the list is applied and a development warning suggests stacking duplicate Text elements for more layers. On the web the browser renders the full list as written. (native-text-shadow-multiple.md)
  • React Native: the CSS tree-counting functions sibling-index() and sibling-count() are supported. Styles can size, tint, or position each child by where it sits among its siblings, with one shared ruleset: width: calc(sibling-index() * 10px) renders a staircase, width: calc(100% / sibling-count()) divides a row evenly. Values update automatically when siblings mount, unmount, or reorder. (native-tree-counting-functions.md)
  • React Native: animation-timeline: view() is supported. Keyframe progress follows the element's own visibility within the nearest styled scroll container: the animation starts as the element scrolls into view and finishes as it scrolls out, with animation-range accepting the named view ranges (cover, contain, entry, exit, entry-crossing, exit-crossing) to scope the effect to entering or leaving. Elements using view() must be direct children of the scroll container; view-timeline-inset is not applied and emits a development warning. (native-view-timeline.md)
  • styled-components/native ships a smaller, browser-native build for react-native-web consumers. Webpack, Vite, and Metro (when targeting web) pick it up automatically; existing imports and props are unchanged. (native-web-bundle.md)

    On the web, the browser handles CSS directly, so these features resolve through native browser support:

    • var(), @media, @container, and pseudo-classes (:hover, :focus, :nth-child(...), :has(...)) resolve without React re-renders.
    • light-dark() and prefers-color-scheme repaint without a React re-render. The document opts into color-scheme: light dark automatically so useColorScheme() reflects the OS preference.
    • dvh / svh / lvh and the inline / block-axis viewport units (vi, vb) resolve distinctly per CSS Values 4.
    • oklch, oklab, lch, lab, and color-mix() render in the browser's full wide gamut (Display P3 / Rec. 2020 where the monitor supports it).
    • Static-mixed-unit calc() / clamp() / min() / max() resolve against the real containing block at paint time.
    • ThemeProvider and createTheme tokens publish as scoped CSS custom properties, so theme changes restyle without re-rendering the subtree.

    The bundle is smaller because the CSS polyfills for iOS / Android are excluded. iOS and Android consumers are unaffected and continue to use the native CSS engine.

    Consumers who want the same bundle without relying on bundler resolution can import it directly: styled-components/native/web-bridge.

Patch Changes

  • The arity-2 .attrs((props, ast) => ...) callback receives ast as a non-optional CompiledAst, so authors can read it directly without optional-chaining under TypeScript strict: true. The arity-1 form (.attrs((props) => ...)) takes only props. (attrs-ast-required-in-arity-2.md)
  • React Native: lab() and lch() accept percentage channels and resolve to the correct color. lab(50% 0 0) is mid-gray. Per CSS Color L4, each space has its own range: (color-percent-channels.md)

    • lab L: 0%-100% maps to 0-100. a/b: 100% maps to ±125.
    • lch L: 0%-100% maps to 0-100. C: 100% maps to 0-150.
    • oklab L: 0%-100% maps to 0-1. a/b: 100% maps to ±0.4.
    • oklch L: 0%-100% maps to 0-1. C: 100% maps to 0-0.4.

    The web is unaffected (the browser parses these notations natively).

  • Empty CSS custom property values are preserved. (empty-custom-property-values.md)

    --my-prop: ; is a legitimate CSS declaration; the empty value is part of the Custom Properties spec and is used by patterns like scroll-driven animations as a "guaranteed-invalid" sentinel. It renders as authored:

    @keyframes shadow-toggle {
      from,
      to {
        --shadow: ;
      }
    }

    Empty values for non-custom properties (e.g. color: ;) are dropped, since those are invalid CSS.

    Note: components that author --prop: ; get a new class name on upgrade since the emitted CSS includes the declaration. Typical apps are unaffected.

  • A css\``fragment placed after a declaration that is missing its trailing;` is treated as a sibling block: (fragment-missing-semicolon-recovery.md)

    const Box = styled.View`
      margin: 0 ${10}px ${css`
          color: red;`};
    `;

    The fragment promotes to a sibling, so the declaration above behaves the same as if you had written margin: 0 10px; color: red;. Value-position fragments (border: ${frag};) interpolate into the value as usual.

  • The prop-filtering logic that decides which props reach the underlying DOM element ships inside styled-components, with no @emotion/is-prop-valid dependency. Consumers get a smaller dependency tree and a slightly smaller installed footprint, with identical filtering behavior. (inline-prop-validator.md)

    Importing isPropValid from @emotion/is-prop-valid directly elsewhere in your app still works; this only affects what styled-components itself depends on.

  • Nested rules resolve correctly when their parent selector contains a comma inside :is(), :where(), :has(), or an attribute selector: (is-where-cross-product-bug.md)

    const Card = styled.div`
      :is(&:hover, .parent:hover &) .child {
        color: red;
        .grandchild {
          color: blue;
        }
      }
    `;

    The grandchild rule compiles to :is(.card-class:hover, .parent:hover .card-class) .child .grandchild { color: blue; }, keeping the :is() arms intact. Commas inside [attr*="a,b"] and other paren- or bracket-protected contexts resolve the same way.

  • React Native: multi-argument transform shorthands (translate(x, y), translate3d(x, y, z), and scale(x, y)) animate correctly per axis inside @keyframes or a transition, alongside single-axis forms and uniform scale(n). This applies on both iOS and Android and on react-native-web. (native-animated-translate-shorthand.md)
  • Comma-separated animation-composition is supported on React Native: each value pairs with the matching animation-name entry when you run multiple animations. (native-animation-composition-longhand.md)
  • React Native: aspect-ratio accepts the same common forms as CSS: 16 / 9, auto, auto 16 / 9, and 16 / 9 auto. When auto is combined with a ratio on a component that does not have its own natural dimensions, styled-components uses the ratio and shows a development warning explaining that the auto part only applies to image-like elements. (native-aspect-ratio-auto.md)
  • background-size: cover and background-size: contain are supported on React Native for gradient backgrounds: the gradient paints across the full element area. On react-native-web the browser handles the keyword directly. (native-background-keyword-crash-fix.md)

    background-position values like 0 0, 50% 50%, and top left are supported on react-native-web without a warning.

  • The background shorthand is supported on React Native, including multiple layers, position / size, and a color on the final layer. Attachment, origin, and clipping are not supported on native: they warn in development, while web builds keep the full declaration. Invalid position, size, and repeat values are ignored, and invalid layered longhands warn in development. (native-background-shorthand.md)
  • Border line styles are supported on React Native: hidden acts like no border, repeated sides collapse quietly, and mixed sides keep the first drawable style with a development warning. Keywords React Native can't draw, such as double, are not supported on native and are ignored. Web builds keep CSS border styles as authored. (native-border-line-styles.md)
  • Slash-separated border-radius values that resolve to a circular radius (for example 10px / 10px) are supported on native. Truly elliptical combinations are not supported: they are ignored with a development warning. Web builds keep the authored value. (native-border-radius-elliptical.md)
  • React Native: CSS-wide keywords (initial, inherit, unset, revert, revert-layer) are not supported: it has no cascade to resolve them against and its style defaults differ from the CSS initial values, so the declaration is dropped with a development warning suggesting an explicit value. On the web the browser resolves the keywords as usual. direction: inherit and flex: initial are supported, since React Native and the flex shorthand implement those directly. (native-css-wide-keywords.md)
  • React Native: direction: ltr and direction: rtl are supported. Logical edges such as margin-inline-start and padding-inline-end follow that direction, so the same declaration can support left-to-right and right-to-left layouts on iOS, Android, and the web. (native-direction-passthrough.md)
  • React Native: fixes spec-compliance edge cases in the flex shorthand. flex: initial and a zero basis after grow and shrink factors match CSS behavior, and invalid negative grow, shrink, and basis values are ignored. (native-flex-shorthand.md)
  • React Native: font-style: oblique maps to italic; an angle triggers a development warning. Standalone line-height (percentages, em, rem) and relative letter-spacing that are not supported warn with suggested replacements; percentage line height inside the font shorthand resolves when font size is known. On the web, browser-handled values are kept. (native-font-style-oblique-lineheight-letterspacing.md)
  • React Native: generic font-family keywords such as serif, sans-serif, monospace, system-ui, ui-rounded, emoji, and math map to an appropriate platform font on iOS and Android. react-native-web passes the keyword to the browser. When a React Native font list contains multiple comma-separated families, styled-components uses the first one and shows a development warning because React Native accepts only one font family. (native-generic-font-families.md)
  • React Native: interactivity: inert is supported. The styled component and its subtree stop responding to touch, reject D-pad / keyboard focus, and are hidden from screen readers (VoiceOver on iOS, TalkBack on Android). Not supported: a focusable child rendered inside an inert subtree on Android can still receive focus, which a development warning flags. (native-interactivity-inert.md)

    react-native-web lets the browser honor the property natively via the HTML inert attribute.

  • React Native: letter-spacing accepts the full CSS length grammar. Absolute lengths (pt, pc, in, cm, mm, Q) fold to dp at compile time. Font-relative units (em, rem, lh, rlh plus the font-metric forms ex, cap, ch, ic and their r-variants), viewport units, and container-query units resolve at render time against the current environment. Numbers, px, and normal are supported. Unsupported units drop with a development warning. (native-letter-spacing-font-relative.md)
  • React Native: logical border shorthands expand to their longhands: (native-logical-border-shorthands.md)

    • Per-edge color, style, and width declarations such as border-inline-start-color and border-block-end-width.
    • Axis shorthands such as border-inline-color, border-block-width, border-inline, and border-block.
    • Single-edge shorthands such as border-inline-start and border-block-end.

    Width and color apply to the matching logical edge. Per-edge border styles show a development warning on React Native, because the platform supports one border-style for the whole element. On react-native-web the browser handles per-edge styles. outline-style: hidden gets a clearer warning.

  • React Native: several CSS constructs that platform primitives can't render emit a clear development warning with a suggested alternative. This covers conic gradients (conic-gradient() / repeating-conic-gradient()), the order property, text-decoration-thickness / text-underline-offset / text-underline-position, and the advanced text-overflow forms (string, fade, and two-value). Each warning names the construct, explains why it can't run on iOS or Android, and points at a workaround. The web renders all of these natively. (native-loud-warnings.md)
  • React Native: on Expo and other Metro projects, importing from styled-components/native selects the correct build automatically for each platform, so react-native-web stays out of your iOS and Android bundles and no custom Metro resolver workaround is needed. This keeps the device bundle small and styling intact on device. (native-metro-platform-resolution.md)
  • React Native: object-fit on a styled Image is supported and renders consistently on iOS, Android, and react-native-web. (native-object-fit-rnweb.md)
  • React Native: perspective is supported as a standalone property, so it can combine with child transforms like rotateY or rotateX to create depth. Very small values are clamped to 1px to match browser behavior. transform-style: preserve-3d is not supported on iOS or Android and drops with a development warning. On react-native-web the browser handles both properties. (native-perspective-transform-style.md)
  • React Native: the place-content shorthand is supported. start, end, and space-evenly match CSS Box Alignment behavior on iOS, Android, and react-native-web. (native-place-content.md)
  • React Native: the place-items and place-self shorthands are supported. As on the web, the second value defaults to the first when omitted. Keywords like start, end, self-start, and self-end produce the same layout on iOS, Android, and react-native-web. (native-place-items-self.md)
  • React Native: position-dependent styles (:nth-child, sibling combinators) re-evaluate when a sibling insertion, removal, or reorder shifts an element's position, even when its own props are unchanged. An :nth-child(2) highlight, for example, follows the element that actually sits in the second slot. (native-position-dependent-restyle.md)
  • React Native: pseudo-state selectors (&:active, &:hover, &:focus, &:disabled) behave correctly on non-pressable elements. React Native supports state-driven styles only on Pressable; on any other element (View, Text, ...) the base styles apply normally, the unreachable pseudo styles are skipped, and a development warning points to styled.Pressable. Rules fenced behind a media query that does not match (such as web-only @media (hover: hover) blocks) stay silent. Pressable and custom components keep the live state behavior. (native-pseudo-state-non-pressable.md)
  • React Native: the rem length unit is supported. It uses the app's root font size, 16 by default, so width: 1rem becomes 16 and width: 2rem becomes 32. rem is supported on its own and inside calc(). On react-native-web the browser handles it. (native-rem-unit.md)
  • React Native: scroll-driven animations keep pace with the finger. Opacity and transform keyframes bound to animation-timeline: scroll() / view() track scrolling exactly, so effects like reveals and parallax stay locked to the scroll position. Width, color, and other layout-bound keyframes are not driven this way, since React Native cannot animate those off the JavaScript thread. (native-scroll-timeline-ui-thread.md)
  • React Native: calc() carrying sibling-index() or sibling-count() is supported in two more places: a purely percent-scaled expression (for example width: calc(sibling-index() * 13%)) resolves as a percentage of the parent, and dynamic math inside a color channel (for example oklch(0.72 0.14 calc(sibling-index() * 55)), or a sibling-index() weight inside color-mix()) resolves to a displayable color. Mixed percent-plus-length math is not supported and resolves to absolute pixels. (native-sibling-math-percent-and-color.md)
  • React Native: text-wrap-mode and text-wrap-style are supported alongside the text-wrap shorthand. nowrap clips text to a single line, and on Android, balance and pretty use the platform's higher-quality line breaking. (native-text-wrap-longhands.md)
  • React Native: transform-box shows a development warning on iOS and Android explaining that React Native transforms use the view center as their reference box. Use transform-origin when you need to move the pivot point. On react-native-web the browser handles transform-box. (native-transform-box-warn.md)
  • React Native: a var() reference whose custom property holds a render-dependent value, such as light-dark(...), a viewport unit, or env(...), resolves against the live environment exactly as if the value had been written literally. This applies to inherited and self-declared custom properties, var() fallbacks, and var() inside @media and other conditional blocks, and the resolved value updates in place when the OS theme changes. (native-var-dynamic-values.md)
  • React Native: a development warning fires when vertical-align is set on a native <Text> or <TextInput> running on iOS. (native-vertical-align-ios-warning.md)

    React Native 0.85 has no platform API for vertically aligning text content inside a fixed-height <Text> or <TextInput> on iOS, so the declaration silently has no effect there. Android and react-native-web render the property as authored. For <Text>, the warning points to the workaround: wrap the Text in a View and use justify-content for the vertical alignment. <TextInput> has no Text-level workaround on iOS today.

  • vertical-align: top | middle | bottom on a styled <Text> positions text content within the Text's box on react-native-web, matching the visual semantic of React Native's verticalAlign on Android (textAlignVertical). Other vertical-align values pass through unchanged so the browser's native baseline-shifting semantics still apply. (native-web-vertical-align-content.md)
  • React Native: when you opt into the Reanimated animation adapter, authored CSS animations and keyframes run on the UI thread. Reduced motion collapses CSS-layer durations and delays to zero, and @starting-style entry transitions start from the declared starting snapshot. (reanimated-css-keyframes.md)
  • On react-native-web, parallel animations that use additive composition (add or accumulate) pass animation-composition through to the browser so layered effects compose per CSS Animations Level 2. When every effect uses the default replace composition, the cascade is unchanged. (rn-web-animation-composition-style.md)
  • Fixed a styling leak between sibling subtrees when a nested <StyleSheetManager> sits beside other children of an outer <StyleSheetManager> in a server component tree. (rsc-nested-stylesheetmanager.md)

    <StyleSheetManager plugins={[outerPlugin]}>
      <ChildA />
      <StyleSheetManager plugins={[innerPlugin]}>
        <ChildB />
      </StyleSheetManager>
      <ChildC />
    </StyleSheetManager>

    ChildC is styled with the outer manager's plugins, not the inner manager's. The inner subtree's configuration stays scoped to ChildB.

  • A plain object with a custom toString() interpolated into a template stringifies via that method rather than expanding its keys as a CSS-property block. Useful for design-token shapes where the token resolves to a default value but also carries alternate sub-values: (toString-design-tokens.md)

    const ink = {
      default: '#000',
      subtle: '#444',
      toString() {
        return this.default;
      },
    };
    
    const Heading = styled.h1`
      color: ${ink};
    `;

Full Changelog: https://github.com/styled-components/styled-components/compare/styled-components%407.0.0-prerelease-20260610071139...styled-components%407.0.0-prerelease-20260611043336

styled-components@7.0.0-prerelease-20260610071139

Patch Changes

  • Fixed a rules-of-hooks violation that could crash components triggering an immediate re-render with unchanged style props. (hooks-cache-hit-debug-value.md)

Full Changelog: https://github.com/styled-components/styled-components/compare/styled-components%407.0.0-prerelease-20260530064039...styled-components%407.0.0-prerelease-20260610071139

styled-components@6.4.3-prerelease-20260602021501

Patch Changes

  • f692ec2: Fix a TypeScript error when wrapping a component whose props can't be statically read, such as Mantine v7's polymorphic-factory components (Button, Card, Menu.Item, and similar). These styled components no longer reject every prop, including children; arbitrary props are accepted again at the JSX call site and via .attrs(), while components with readable prop types stay fully type-checked.
  • f692ec2: Keep TypeScript attribute autocomplete working while you type props on a polymorphic styled component. When a component renders a different element through as (for example as="video"), beginning to type a new prop name could make the whole suggestion list vanish; the rendered element's props now keep autocompleting as you go.

Full Changelog: https://github.com/styled-components/styled-components/compare/styled-components%406.4.2...styled-components%406.4.3-prerelease-20260602021501