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@7.0.0-prerelease-20260925191055

styled-components@6.6.0-prerelease-20260925231434

Patch Changes

  • 7afbd11: Fixed attrs no longer applying its value when a prop was explicitly passed as undefined (the 6.3.12 to 6.5.x behavior). styled.button.attrs(({ type = 'button', ...rest }) => ({ type, ...rest })) rendered without type="button" when the caller passed type={undefined}, and an object-form default such as .attrs({ type: 'button' }) was lost the same way, including through a wrapper component that spreads its own props over the styled component. attrs now always wins for the keys it returns, matching every other case where a prop is passed alongside attrs.

    Also fixed: a prop passed explicitly as undefined (and not overridden by attrs) is now forwarded to a wrapped component so that component can fall back to its own default, the pattern MUI's ButtonBase relies on (for example <Root role="button" {...props} />). Wrapped components have dropped this prop entirely since v6.0, so a component that checks 'role' in props or merges {...defaults, ...props} to detect an explicitly-passed prop may see and behave differently now that the key is present again. This only applies when wrapping another component; a DOM tag such as styled.div still drops the undefined prop entirely, since browsers have no notion of an "undefined" attribute.

    If you were relying on an explicit undefined to clear an attrs default, use the function form and check for the prop's presence instead:

    styled.a.attrs(props => ('rel' in props ? {} : { rel: 'noopener' }))``;

    Passing rel={undefined} now renders no rel attribute, and omitting the prop renders rel="noopener".

    React Native already forwarded an explicit undefined prop to a wrapped component; it now also matches web in never forwarding an undefined that attrs itself produced.

  • 7afbd11: Fixed a typo in the useTheme error message's example code (a misspelled component name in error 18), so the copy-pasted example compiles as written.
  • 7afbd11: Fixed global styles from createGlobalStyle disappearing in React Server Components: a global style rendered in a loading state (a React <Suspense> fallback) and again once the real content streamed in could vanish entirely once the fallback was replaced. The same loss could happen across a client-side navigation when a global style was rendered by both a layout and one of its pages, and the layout's copy never re-rendered.

    Each server-rendered instance of a global style now carries its own styles, so a global style shown in more than one place in a request always survives, whether the page reveals streamed content or the user navigates to a sibling route.

  • 7afbd11: Fixed // JavaScript-style line comments in React Native style declarations. Only /* */ block comments were recognized before; a // comment left in a template literal was parsed as part of the surrounding CSS, which could drop or corrupt the styles that followed it on the same line. Line comments are now stripped the same way block comments already were, while a URL used as a raw value (for example url(http://example.com/image.png) or an unquoted https:// value in a custom property) is left untouched.
  • 7afbd11: Fixed styles disappearing from a server-rendered component when it is revealed from behind a React <Suspense> boundary, such as a streaming Next.js route (including cacheComponents). A component shown first in a Suspense fallback and then in the resolved content kept its class name but lost its CSS, because the rule had been emitted only inside the fallback that React discards on reveal.

    Each server-rendered instance now carries its own inline <style>, so its styles always travel with it and survive the boundary. Nearby duplicates still compress away almost for free under gzip, but gzip can only look back about 32 KB, so once repeats are farther apart on the page each one costs roughly its own compressed size; brotli's much larger window keeps it cheap regardless of distance. Only a very large repeated list (thousands of instances of one component on a single page) is worth collapsing into a shared class, and a development-only warning points that out if it happens.

  • 7afbd11: styled-components now installs the stylis type declarations its own published types rely on.

    The shipped declarations reference types from stylis (the stylisPlugins option and stylisPluginRSC), and stylis ships no types of its own. With skipLibCheck turned off, a project that had not installed @types/stylis itself could fail to type-check with an error inside styled-components' declarations. Nothing changes at runtime.

  • 7afbd11: Fixed the shipped types failing to compile, with skipLibCheck turned off, against @types/react 16, 17, and 18.2.6 through 18.2.11. Those versions don't declare the <search> HTML element, and styled-components' types assumed they did. The published types now compile on every supported @types/react.

    styled.search is present in the types on every version, and accepts the same props it did before, so no existing code stops compiling.

  • 7afbd11: Fixed an error inside styled-components' own type declarations, with skipLibCheck turned off, for projects using React 16 or 17 type packages or without @types/react-dom installed. The ServerStyleSheet streaming API's types referenced a type that only @types/react-dom 18 and later provide. interleaveWithNodeStream still accepts the result of renderToPipeableStream and Node readable streams exactly as before.
  • 7afbd11: Added a development-only warning for when the server and the browser are running different versions of styled-components. Class names are derived in part from the library's own version, so a mismatch made every server-rendered class name silently fail to match on the client, with no hint as to why styles disappeared or hydration broke. The warning names both versions and points at npm ls styled-components to find the duplicate. A page that intentionally hosts more than one app, each on its own styled-components version (for example a micro-frontend setup), can ignore it. It is stripped from production builds.

Full Changelog: https://github.com/styled-components/styled-components/compare/styled-components%406.6.0-prerelease-20260908162735...styled-components%406.6.0-prerelease-20260925231434

styled-components@7.0.0-prerelease-20260908195050

styled-components@7.0.0-prerelease-20260908153432

styled-components@6.6.0-prerelease-20260908162735

Patch Changes

  • 1c0e309: Fixed styles disappearing from a server-rendered component when it is revealed from behind a React <Suspense> boundary, such as a streaming Next.js route (including cacheComponents). A component shown first in a Suspense fallback and then in the resolved content kept its class name but lost its CSS, because the rule had been emitted only inside the fallback that React discards on reveal.

    Each server-rendered instance now carries its own inline <style>, so its styles always travel with it and survive the boundary. Identical rules compress away under gzip, so the extra output is negligible; only a very large repeated list (thousands of instances of one component on a single page) is worth collapsing into a shared class, and a development-only warning points that out if it happens.

Full Changelog: https://github.com/styled-components/styled-components/compare/styled-components%406.6.0-prerelease-20260905051044...styled-components%406.6.0-prerelease-20260908162735

styled-components@6.6.0-prerelease-20260905051044

Patch Changes

  • 52c5f6e: Fixed a crash ("Rendered fewer hooks than expected") and a related stale-style bug for components that call a React hook, or read any value outside their props and theme, from inside a style interpolation. This affected @mui/styled-engine-sc with MUI X DataGrid, which calls hooks within an interpolation, and was a regression introduced in 6.4.0.

    Style interpolations now run on every render, so a hook called inside one runs consistently and a value read inside one always reflects its current state.

    If a component re-renders often with unchanged props and its interpolations are expensive, wrap it in React.memo to skip those re-renders. That is the right place to bail out, because only the calling code knows the full set of inputs its styles depend on.

Full Changelog: https://github.com/styled-components/styled-components/compare/styled-components%406.6.0-prerelease-20260817175248...styled-components%406.6.0-prerelease-20260905051044

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