NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
npm · #2881 most downloaded on npm
Fast, expressive styling for React.
Last release 9 days ago
25 Sep 2026
Ships fairly regularly
a new release about every 2 weeks
Some releases are documented
notes for 25 of the last 60 stable releases
Nothing withdrawn
no release was ever pulled
10 years old
459 releases · first in 2016
Fix a typo in errors. ( soft-ads-push.md )
Full Changelog: styled-components@7.0.0-prerelease-20260908195050...styled-components@7.0.0-prerelease-20260925191055
No new changes since the previous release.
No new changes since the previous release.
Full Changelog: styled-components@7.0.0-prerelease-20260908153432...styled-components@7.0.0-prerelease-20260908195050
One column per quarter.
No new changes since the previous release.
No new changes since the previous release.
Full Changelog: styled-components@7.0.0-prerelease-20260808041113...styled-components@7.0.0-prerelease-20260908153432
No new changes since the previous release.
No new changes since the previous release.
Full Changelog: styled-components@7.0.0-prerelease-20260807223715...styled-components@7.0.0-prerelease-20260808041113
createGlobalStyle rules land before any consumer layout effect. ( global-styles-before-layout-effects.md )
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.
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: styled-components@7.0.0-prerelease-20260806233720...styled-components@7.0.0-prerelease-20260807223715
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
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(
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: styled-components@6.6.0-prerelease-20260908162735...styled-components@6.6.0-prerelease-20260925231434
1c0e309 : Fixed styles disappearing from a server-rendered component when it is revealed from behind a React <Suspense> boundary, such as a streaming
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: styled-components@6.6.0-prerelease-20260905051044...styled-components@6.6.0-prerelease-20260908162735
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
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: styled-components@6.6.0-prerelease-20260817175248...styled-components@6.6.0-prerelease-20260905051044
styled-components@6.6.0-prerelease-20260817175248
styled-components@6.6.0-prerelease-20260817175248
7ce6aea : Added a StyledComponent<Target, Props> type for annotating explicitly-typed styled component exports.
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: styled-components@6.5.3...styled-components@6.6.0-prerelease-20260815222953
3470387 : Fix TypeScript errors in projects that augment React HTML props with a data-* template-literal index signature.
data-* template-literal index signature.3470387 : Fix TypeScript errors in projects that augment React HTML props with a data-* template-literal index signature.
data-* template-literal index signature.Full Changelog: styled-components@6.5.2...styled-components@6.5.3-prerelease-20260815150702
00b9ee2 : .attrs() is cheaper to type-check.
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's styleand 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.
00b9ee2 : .attrs() is cheaper to type-check.
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's styleand 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: styled-components@6.5.1...styled-components@6.5.2-prerelease-20260810214005
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
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.Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
49d09ae: Fix a performance regression in 6.4.0 where dynamic createGlobalStyle components caused significant re-render slowdowns. Also restores pre-6.
createGlobalStyle components caused significant re-render slowdowns. Also restores pre-6.4 cascade ordering when multiple instances of the same createGlobalStyle coexist.www.styled-components.com and described behavior from styled-components v3.Nothing published for this version
Nothing published for this version
b0f3d29: .attrs() improvements: props supplied via attrs are now automatically made optional on the resulting component (previously required even when
b0f3d29: .attrs() improvements: props supplied via attrs are now automatically made optional on the resulting component (previously required even when attrs provided a default). Also fixes a bug where the attrs callback received a mutable props object that could be changed by subsequent attrs processing; it now receives an immutable snapshot.
2a973d8: Dropped IE11 support: ES2015 build target, inlined unitless CSS properties (removing @emotion/unitless dependency), removed legacy React class statics from hoist and other unnecessary code.
9e07d95: Add createTheme(defaultTheme, options?) for CSS variable theming that works across RSC and client components.
Returns an object with the same shape where every leaf is var(--prefix-path, fallback). Pass it to ThemeProvider for stable class name hashes across themes (no hydration mismatch on light/dark switch).
const theme = createTheme({ colors: { primary: '#0070f3' } });
// theme.colors.primary → "var(--sc-colors-primary, #0070f3)"
// theme.raw → original object
// theme.vars.colors.primary → "--sc-colors-primary"
// theme.resolve(el?) → computed values from DOM (client-only)
// theme.GlobalStyle → component that emits CSS var declarations
vars exposes bare CSS custom property names (same shape as the theme) for use in createGlobalStyle dark mode overrides without hand-writing variable names:
const { vars } = createTheme({ colors: { bg: '#fff', text: '#000' } });
const DarkOverrides = createGlobalStyle`
@media (prefers-color-scheme: dark) {
:root {
${vars.colors.bg}: #111;
${vars.colors.text}: #eee;
}
}
`;
Options: prefix (default "sc"), selector (default ":root", use ":host" for Shadow DOM).
79cc7b4: Add first-class CSP nonce support. Nonces can now be configured via StyleSheetManager's nonce prop (recommended for Next.js, Remix), ServerStyleSheet's constructor, <meta property="csp-nonce"> (Vite convention), <meta name="sc-nonce">, or the legacy __webpack_nonce__ global.
b0f3d29: Rearchitect createGlobalStyle to use shared stylesheet groups.
All instances of a createGlobalStyle component now share a single stylesheet group, registered once at definition time. This fixes unmounting one instance removing styles needed by others (#5695), styles scattering after remount (#3146), and group ID leaks during SSR (#3022).
CSS injection order is now fully determined at definition time (lower group ID = earlier in stylesheet). Render order no longer affects CSS order. Keyframes defined before a component correctly appear before that component's rules.
Also fixes: O(n^2) performance regression in jsdom test environments from unbounded rule accumulation, and stale static global styles during client-side HMR (effect deps now include the globalStyle reference so module re-evaluation triggers re-injection).
b0f3d29: Significant render performance improvements via three-layer memoization and hot-path micro-optimizations. Client-only; server renders are unaffected.
Re-renders that don't change styling now skip style resolution entirely. Components sharing the same CSS (e.g., list items) benefit from cross-sibling caching. Hot-path changes include forEach → for/for...of, template literal → manual concat, and reduced allocations.
Benchmarks vs 6.3.12:
9ada92b: React Server Components support: inline style injection, deduplication, and a new stylisPluginRSC for child-index selector fixes.
Inline style injection: RSC-rendered styled components emit <style data-styled> tags alongside their elements. CSS is deduplicated per render via React.cache (React 19+). Extended components use :where() zero-specificity wrapping on base CSS so extensions always win the cascade regardless of injection order.
StyleSheetManager works in RSC: stylisPlugins and shouldForwardProp are now applied in server component environments where React context is unavailable.
stylisPluginRSC — opt-in stylis plugin that fixes :first-child, :last-child, :nth-child(), and :nth-last-child() selectors broken by inline <style> tags shifting child indices. Rewrites them using CSS Selectors Level 4 of S syntax to exclude styled-components style tags from the count.
import { StyleSheetManager, stylisPluginRSC } from 'styled-components';
<StyleSheetManager stylisPlugins={[stylisPluginRSC]}>{children}</StyleSheetManager>;
The plugin rewrites :first-child, :last-child, :nth-child(), and :nth-last-child() using CSS Selectors Level 4 of S syntax to exclude injected style tags from the child count.
Browser support: Chrome 111+, Firefox 113+, Safari 9+ (~93% global). In unsupported browsers, the entire CSS rule is dropped — only opt in if your audience supports it. Use :first-of-type / :nth-of-type() as a universally compatible alternative.
HMR: Stale styles during client-side HMR are detected and invalidated when module re-evaluation creates new component instances while IDs remain stable (SWC plugin assigns IDs by file location). createGlobalStyle additionally clears stale sheet entries when the instance changes between renders.
The plugin is fully tree-shakeable — zero bytes in bundles that don't import it.
as and forwardedAs props in React.ComponentProps extraction for styled componentscolor: ${p => p.$dynamicValue} where the value comes from unbounded user input).nanoid crashes in Expo/Metro (#5705) and improving parse speed 4-6x. Parent re-renders with unchanged children are 2.6-3.2x faster via cache-first render. Updated native component alias list (removed 5 dead components, added 4 missing). Added react-native as an optional peer dependency.Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Your coding agent can read these notes before it upgrades. Set up the MCP server →