Releases

RSS feed

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

styled-components@6.4.2-prerelease-20260514185513

styled-components@6.4.2-prerelease-20260514184932

styled-components@6.4.2-prerelease-20260514182414

Patch Changes

  • 9945904e: Restore TypeScript prop autocomplete inside the JSX of a styled component once the first attribute is typed.

  • 9945904e: Apply all chain levels' styles when an extended styled component renders with the as prop under Preact's react-compat.

  • 9945904e: Respect a custom toString on plain value objects (e.g. design tokens) when interpolated into a styled component, rather than walking the object's keys as CSS declarations.

  • 9945904e: Fix a TypeScript error when wrapping a component whose props include an as prop with a non-string type (such as Next.js Link's as?: Url). The styled-components as and forwardedAs props now consistently override the wrapped component's same-named props instead of colliding with them.

  • 9945904e: Restore reliable styling in production browser bundles built without a runtime process global.

Full Changelog: https://github.com/styled-components/styled-components/compare/styled-components%406.4.1...styled-components%406.4.2-prerelease-[`20260514182414`](https://github.com/styled-components/styled-components/commit/20260514182414)

styled-components@7.0.0-prerelease-20260513173704

styled-components@7.0.0-prerelease-20260513034901

Minor Changes

  • feacf77: React Native: :not(...) now works for simple selectors. Rules such as :not(:hover), :not(:focus), :not([disabled]), and :not([data-state='loading']) apply when the condition inside :not() is not true. More complex forms, including multiple selectors or nested descendant selectors, still show a development warning and are ignored on native.

  • feacf77: em, lh, and rlh length units now work on React Native. 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 web and native without rewriting everything to pixels.

    text-align: start, text-align: end, and text-align: match-parent now resolve correctly under both left-to-right and right-to-left writing directions on React Native. Authors get the same direction-aware behavior they get on the web; the previous fall-back-to-auto warning is removed.

    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.

  • feacf77: React Native: descendant and child combinator selectors now work across styled components.

    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 also work on web. This also fixes a web bug where ${Component} { ... } rules placed after another declaration could lose the component selector and target too broadly.

  • feacf77: React Native: field-sizing: content makes a TextInput autosize to its content.

    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 dev-time message 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.

  • feacf77: React Native: :has(<simple>) selector now works.

    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 yet.

  • feacf77: Relative color syntax now works in React Native styles. 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 converts the result to a color React Native can render consistently on iOS, Android, and the web. This works with oklch, oklab, lch, and lab.

    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.

  • feacf77: React Native: sibling combinator selectors and the :nth-child family now work.

    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.

  • feacf77: System color keywords such as Canvas, CanvasText, Field, FieldText, GrayText, Highlight, and LinkText now work on React Native. 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. The browser still handles these keywords directly on the web build.

    Keywords match regardless of casing. Values inside larger shorthands, such as border: 1px solid Canvas, are not covered in this release; use the matching standalone color property for the same result.

Patch Changes

  • feacf77: aspect-ratio on React Native now 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 one-time development warning explaining that the auto part only applies to image-like elements.

  • feacf77: background-size: cover and background-size: contain on React Native no longer crash the app when applied to gradient backgrounds. Gradients now paint across the full element area as expected. react-native-web still receives the original keyword so the browser can handle it directly.

    background-position values like 0 0, 50% 50%, and top left also no longer trigger a react-native-web warning.

  • feacf77: The background shorthand now works on React Native. A single declaration can set image, position, size, repeat behavior, attachment, origin, clipping, and color. Multiple background layers, position / size, and a final background color are supported.

    When React Native does not expose a matching behavior, such as fixed background attachment or non-default background origin and clipping, styled-components shows a development warning instead of silently dropping the unsupported part. react-native-web continues to let the browser handle the full shorthand.

  • feacf77: direction: ltr and direction: rtl now work in React Native styles. 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.

  • feacf77: font-style: oblique now maps to italic on React Native. If an angle is provided, such as oblique 14deg, styled-components shows a one-time development warning because React Native cannot control the exact slant. react-native-web still passes the declaration to the browser.

    line-height values React Native cannot apply, such as percentages, em, and rem, now show a one-time development warning with the specific value and a suggested replacement.

    letter-spacing values written with em, rem, or percentages also now warn on React Native and point to pixel or unitless values instead.

  • feacf77: Generic font-family keywords such as serif, sans-serif, monospace, system-ui, ui-rounded, emoji, and math now map to an appropriate platform font on iOS and Android. react-native-web still 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 one-time development warning because React Native accepts only one font family.

  • feacf77: interactivity: inert now applies on React Native: the styled component and its subtree stop responding to touch, no longer accept D-pad / keyboard focus, and are hidden from screen readers (VoiceOver on iOS, TalkBack on Android). One known gap surfaces via a one-time dev warning on Android: a focusable child rendered inside an inert subtree may still receive focus, because React Native does not propagate that flag down the tree.

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

  • feacf77: Logical border shorthands now expand on React Native:

    • 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 now show a one-time development warning on React Native, because the platform only supports one border-style for the whole element. react-native-web continues to let the browser handle per-edge styles. outline-style: hidden also now gets a clearer warning.

  • feacf77: perspective now works as a standalone property on React Native, so it can be combined 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 shows a one-time development warning on iOS and Android because React Native does not expose that behavior yet; react-native-web continues to let the browser handle both properties.

  • feacf77: place-items and place-self shorthands now work on React Native. They expand to the matching align-* and justify-* properties, with the second value copied from the first when it is omitted. Keywords like start, end, self-start, and self-end are translated to the React Native values needed for the same layout on iOS, Android, and react-native-web.

  • feacf77: rem length values now work on React Native. They use the app's root font size, 16 by default, so width: 1rem becomes 16 and width: 2rem becomes 32. rem works on its own and inside calc(). react-native-web continues to let the browser handle it.

  • feacf77: text-wrap-mode and text-wrap-style can now be set directly on React Native. Previously only the text-wrap shorthand was supported. nowrap clips text to a single line, and on Android, balance and pretty use the platform's higher-quality line breaking.

  • feacf77: transform-box now shows a one-time 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. react-native-web continues to let the browser handle transform-box.

Full Changelog: https://github.com/styled-components/styled-components/compare/styled-components%407.0.0-prerelease-[`20260511203830`](https://github.com/styled-components/styled-components/commit/20260511203830)...styled-components%407.0.0-prerelease-[`20260513034901`](https://github.com/styled-components/styled-components/commit/20260513034901)

styled-components@7.0.0-prerelease-20260511203830

Patch Changes

  • a53bad8: vertical-align: top | middle | bottom on a styled <Text> now 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.

Full Changelog: https://github.com/styled-components/styled-components/compare/styled-components%407.0.0-prerelease-[`20260511181437`](https://github.com/styled-components/styled-components/commit/20260511181437)...styled-components%407.0.0-prerelease-[`20260511203830`](https://github.com/styled-components/styled-components/commit/20260511203830)

styled-components@7.0.0-prerelease-20260511181437

Major Changes

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

    import styled, { createTheme, ThemeProvider } from 'styled-components/native';
    
    
    const theme = createTheme({
      colors: { bg: '#ffffff', text: '[#111111](https://github.com/styled-components/styled-components/issues/111111)' },
    });
    
    
    const Card = styled.View`
      background-color: ${theme.colors.bg};
      border-color: ${theme.colors.text};
    `;
    
    
    <ThemeProvider theme={{ colors: { bg: '[#111](https://github.com/styled-components/styled-components/issues/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. Web behavior is unchanged.

  • c5e1c54: Styled components no longer honor defaultProps. React 19 removed defaultProps support from function components, so styled components can no longer inherit a parent's defaultProps either.

    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.

  • c5e1c54: Removed the disableCSSOMInjection prop on <StyleSheetManager> and the SC_DISABLE_SPEEDY / REACT_APP_SC_DISABLE_SPEEDY environment variables. Added a new extractCSS export.

    Browser builds now always use the same fast injection path that production has used by default for years. There's no longer a knob to switch into a slower text-based mode at runtime, and dev and production now behave identically.

    If you were using the toggle to make CSS visible as text (for static-render pipelines, micro-frontend cloning, embedding into iframes or Shadow DOM, or extraction tooling), call the new extractCSS() function 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.

  • c5e1c54: Mounting the same createGlobalStyle component multiple times now emits its CSS only once. Previously each mount produced its own copy of the stylesheet rules. Rendering output stays byte-stable across SSR, client, and Server Components.

  • c5e1c54: React Native: the CSS-to-style-object translation layer is now built in. Several long-standing limitations go away on the native path.

    • transform: matrix(...) / matrix3d(...) work.
    • transform: translateX(10) (bare number, no unit) works.
    • background-image: linear-gradient(...) / radial-gradient(...) work.
    • filter: blur(4px) saturate(1.5) and the full filter-function chain work.
    • Modern color notations pass through to React Native's color parser unchanged: rgb(r g b / a) slash-alpha, hwb(), hsl() all work.
    • box-shadow with spread and inset pass through as CSS strings.
    • mix-blend-mode, isolation, cursor flow through.
    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);
    `;
    

    The transform layer also fixes border: none emitting border-style: solid on native; it now emits border-style: none to match the rest of the ecosystem.

    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 work without this flag.

  • c5e1c54: Raised peer dependency floors:

    • 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.
    • The enableVendorPrefixes prop on <StyleSheetManager> and the runtime vendor prefixer have been removed. Modern browser targets handle prefixing natively; for the few properties that still need them (e.g. -webkit-backdrop-filter on Safari), declare both the prefixed and unprefixed forms in your CSS, or run a build-time PostCSS transform.

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

  • c5e1c54: Plugins moved to a dedicated styled-components/plugins subpath, and a first-party RTL plugin ships with the library.

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

    rtlPlugin replaces stylis-plugin-rtl for users coming from v6: it swaps physical side properties (padding-leftpadding-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.

    The stylisPlugins prop on <StyleSheetManager> is now plugins, and the top-level stylisPluginRSC export has moved into the new subpath as rscPlugin.

    Migration:

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

    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. Plugins are tree-shaken out of any app that doesn't import them.

    import type { SCPlugin } from 'styled-components';
    
    
    // `rw` runs on every fully-resolved selector after `&` substitution and
    // namespace prepending. Return a new selector string.
    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, 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;
      },
    };
    

    The name field is required and identifies the plugin so different plugin sets across nested <StyleSheetManager> trees stay isolated.

Minor Changes

  • c5e1c54: 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.

    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. Works on web and native. When the callback's behavior is fully determined by static declarations the work folds into a one-time computation at construction so renders pay nothing extra.

  • c5e1c54: Modern CSS functions now work in React Native styles. Static expressions resolve up front; values that depend on the device environment (viewport, container, safe area, color scheme) re-resolve as the environment changes.

    import styled from 'styled-components/native';
    
    
    const Card = styled.View`
      width: clamp(240px, 80vw, 480px);
      background-color: light-dark(white, [#111](https://github.com/styled-components/styled-components/issues/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) / calc(100vw - 40px) with any mix of static and runtime-resolvable arms.
    • 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 work 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 as <n>/1 per spec.
    • @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.

    Features React Native does not yet support (position: fixed, position: sticky, backdrop-filter, 3D transforms, text-shadow, scroll-snap, view-transitions, form-state selectors, and more) are listed in the "React Native CSS Features" compatibility tracker maintained alongside the library.

  • c5e1c54: React Native: CSS transition, @keyframes, and @starting-style now animate.

    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.

  • c5e1c54: React Native: attribute selectors now apply styles based on the rendered element's props.

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

    The same CSS works on web and native. This is most useful for aria-* selectors since React Native forwards those to platform accessibility services. The presence-only form &[attr] matches whenever the prop is defined. The exact-match forms &[attr=value], &[attr='value'], and &[attr="value"] compare as strings, with boolean coercion so aria-pressed={true} and aria-pressed="true" both apply the rule. Other operators (~=, ^=, $=, *=, |=) are not supported on native.

  • c5e1c54: Added box-sizing and hyphens support to React Native styles.

    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 now flows through unchanged on iOS, Android, and rn-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 rn-web the browser handles it natively.

  • c5e1c54: Added cross-platform support for several CSS properties on React Native: caret-color, object-fit, vertical-align, backface-visibility, and outline-offset.

    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 rn-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 now flow through unchanged on iOS, Android, and rn-web.

  • c5e1c54: styled.ScrollView now defaults to flex-shrink: 0, matching the behavior of styled.View. Previously, an explicit width: or height: declaration on a ScrollView could be silently overridden by the layout engine when the component sat in a flex parent — the rendered width would come out smaller (or larger) than declared. The fix makes explicit dimensions pin reliably; you can still opt back into the old behavior by declaring flex-shrink: 1 in your own template.

  • c5e1c54: styled-components/native now ships a dedicated build for react-native-web consumers. Webpack, Vite, and Metro (when targeting web) pick it up automatically; no opt-in or import-path change is needed.

    The browser handles a handful of CSS features more accurately than a render-time polyfill ever could, so the new build defers to it:

    • light-dark() and prefers-color-scheme repaint without a React re-render
    • dvh / svh / lvh and the inline / block-axis viewport units (vi, vb) resolve distinctly per CSS Values 4 instead of collapsing
    • oklch, oklab, lch, lab, and color-mix() render in the browser's full wide gamut (Display P3 / Rec. 2020 where the monitor supports it) instead of rounding through sRGB
    • Static-mixed-unit calc() / clamp() / min() / max() resolve against the real containing block at paint time instead of the closest container ancestor

    The bundle is also ~10 kB smaller (gzipped: ~4 kB) than the iOS / Android bundle because the matching polyfills tree-shake out.

  • c5e1c54: Performance improvements across the board in v7. Component creation, SSR renderToString, and React Server Components rendering are all faster than v6, with SSR seeing the largest gains at scale. The eager-parse strategy folds template-literal work into construction time so renders pay less.

    To measure on your hardware:

    pnpm --filter @styled-components/benchmarks bench:headless
    

Patch Changes

  • c5e1c54: Fixed a TypeScript regression where styled(SomeComponent).attrs({...}) could trigger TS2590: Expression produces a union type that is too complex to represent on components with deeply-discriminated prop unions, notably antd's Button. Affected projects also see modestly faster type-checks; projects without complex unions see no measurable difference.

  • c5e1c54: React Native: lab() and lch() now produce correct colors when channels are written as percentages. lab(50% 0 0) resolves to mid-gray as expected, where it previously produced near-black. Per CSS Color L4, each space has its own range:

    • 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.

    Web is unaffected (browsers parse these notations natively).

  • c5e1c54: Empty CSS custom property values are now preserved.

    --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. Previously these declarations were silently dropped from the rendered output, which broke setups like:

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

    They now render as authored. Empty values for non-custom properties (e.g. color: ;) continue to be dropped, since those are still invalid CSS.

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

  • c5e1c54: Inlined the prop validator that decides which props reach the underlying DOM element. styled-components no longer pulls @emotion/is-prop-valid from npm; the same validation logic ships inside the library itself. Consumers see a smaller dependency tree and a slightly smaller installed footprint, with identical behavior.

    If you were already importing isPropValid from @emotion/is-prop-valid directly elsewhere in your app, that continues to work; this change only affects what styled-components itself depends on.

  • c5e1c54: Fixed selector resolution for nested rules whose parent contains a comma inside :is(), :where(), :has(), or an attribute selector.

    Previously a parent like :is(&:hover, .parent:hover &) .child containing a nested rule would produce nonsense output where the nested selector got injected into the first arm of the :is(...) call. For example:

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

    The grandchild rule used to compile to :is(.card-class:hover .grandchild, .parent:hover .card-class) .child .grandchild { color: blue; }, where the .grandchild token leaked into the :is() parens. It now compiles correctly to :is(.card-class:hover, .parent:hover .card-class) .child .grandchild { color: blue; }. The same fix applies to commas inside [attr*="a,b"] and other paren/bracket-protected contexts.

  • c5e1c54: Fixed background-position, background-size, and background-repeat declarations rejected by react-native-web when authored as a comma-separated list with the same value on every layer (e.g. background-position: 0% 0%, 0% 0%). The CSS shorthand already cycles a single value to all layers, so the redundant comma form now collapses at the boundary and reaches react-native-web as a single value while keeping multi-layer intent intact when the values actually differ.

  • c5e1c54: React Native: passing prop={undefined} to a styled component opts out of an attrs()-provided default, matching web behavior. <Comp accessible={undefined} /> renders with no accessible prop even when the component has .attrs({ accessible: true }).

  • 9894183: Development builds now warn when vertical-align is set on a native <Text> running on iOS.

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

  • c5e1c54: Fixed a styling leak when a nested <StyleSheetManager> sits beside other children of an outer <StyleSheetManager> in a server component tree.

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

    Previously ChildC was being styled with the inner manager's plugins because the inner subtree's configuration leaked back out. ChildC now correctly uses the outer manager's plugins.

  • c5e1c54: Server-side output escapes </style> substrings (rewritten as the CSS hex escape \3C/style, which the CSS engine still parses identically) and HTML-escapes nonce values before they reach the rendered <style ...> tag, so user-supplied content interpolated into styles can't break out and inject markup. In-browser style injection is unaffected.

  • c5e1c54: Fixed plain objects with a custom toString() being expanded as CSS-property blocks instead of stringified. Useful for design-token shapes where the token resolves to a default value but also carries alternate sub-values:

    const ink = {
      default: '[#000](https://github.com/styled-components/styled-components/issues/000)',
      subtle: '[#444](https://github.com/styled-components/styled-components/issues/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-[`20260511181111`](https://github.com/styled-components/styled-components/commit/20260511181111)...styled-components%407.0.0-prerelease-[`20260511181437`](https://github.com/styled-components/styled-components/commit/20260511181437)

styled-components@7.0.0-prerelease-20260511181111

Major Changes

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

    import styled, { createTheme, ThemeProvider } from 'styled-components/native';
    
    
    const theme = createTheme({
      colors: { bg: '#ffffff', text: '[#111111](https://github.com/styled-components/styled-components/issues/111111)' },
    });
    
    
    const Card = styled.View`
      background-color: ${theme.colors.bg};
      border-color: ${theme.colors.text};
    `;
    
    
    <ThemeProvider theme={{ colors: { bg: '[#111](https://github.com/styled-components/styled-components/issues/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. Web behavior is unchanged.

  • c5e1c54: Styled components no longer honor defaultProps. React 19 removed defaultProps support from function components, so styled components can no longer inherit a parent's defaultProps either.

    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.

  • c5e1c54: Removed the disableCSSOMInjection prop on <StyleSheetManager> and the SC_DISABLE_SPEEDY / REACT_APP_SC_DISABLE_SPEEDY environment variables. Added a new extractCSS export.

    Browser builds now always use the same fast injection path that production has used by default for years. There's no longer a knob to switch into a slower text-based mode at runtime, and dev and production now behave identically.

    If you were using the toggle to make CSS visible as text (for static-render pipelines, micro-frontend cloning, embedding into iframes or Shadow DOM, or extraction tooling), call the new extractCSS() function 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.

  • c5e1c54: Mounting the same createGlobalStyle component multiple times now emits its CSS only once. Previously each mount produced its own copy of the stylesheet rules. Rendering output stays byte-stable across SSR, client, and Server Components.

  • c5e1c54: React Native: the CSS-to-style-object translation layer is now built in. Several long-standing limitations go away on the native path.

    • transform: matrix(...) / matrix3d(...) work.
    • transform: translateX(10) (bare number, no unit) works.
    • background-image: linear-gradient(...) / radial-gradient(...) work.
    • filter: blur(4px) saturate(1.5) and the full filter-function chain work.
    • Modern color notations pass through to React Native's color parser unchanged: rgb(r g b / a) slash-alpha, hwb(), hsl() all work.
    • box-shadow with spread and inset pass through as CSS strings.
    • mix-blend-mode, isolation, cursor flow through.
    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);
    `;
    

    The transform layer also fixes border: none emitting border-style: solid on native; it now emits border-style: none to match the rest of the ecosystem.

    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 work without this flag.

  • c5e1c54: Raised peer dependency floors:

    • 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.
    • The enableVendorPrefixes prop on <StyleSheetManager> and the runtime vendor prefixer have been removed. Modern browser targets handle prefixing natively; for the few properties that still need them (e.g. -webkit-backdrop-filter on Safari), declare both the prefixed and unprefixed forms in your CSS, or run a build-time PostCSS transform.

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

  • c5e1c54: Plugins moved to a dedicated styled-components/plugins subpath, and a first-party RTL plugin ships with the library.

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

    rtlPlugin replaces stylis-plugin-rtl for users coming from v6: it swaps physical side properties (padding-leftpadding-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.

    The stylisPlugins prop on <StyleSheetManager> is now plugins, and the top-level stylisPluginRSC export has moved into the new subpath as rscPlugin.

    Migration:

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

    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. Plugins are tree-shaken out of any app that doesn't import them.

    import type { SCPlugin } from 'styled-components';
    
    
    // `rw` runs on every fully-resolved selector after `&` substitution and
    // namespace prepending. Return a new selector string.
    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, 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;
      },
    };
    

    The name field is required and identifies the plugin so different plugin sets across nested <StyleSheetManager> trees stay isolated.

Minor Changes

  • c5e1c54: 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.

    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. Works on web and native. When the callback's behavior is fully determined by static declarations the work folds into a one-time computation at construction so renders pay nothing extra.

  • c5e1c54: Modern CSS functions now work in React Native styles. Static expressions resolve up front; values that depend on the device environment (viewport, container, safe area, color scheme) re-resolve as the environment changes.

    import styled from 'styled-components/native';
    
    
    const Card = styled.View`
      width: clamp(240px, 80vw, 480px);
      background-color: light-dark(white, [#111](https://github.com/styled-components/styled-components/issues/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) / calc(100vw - 40px) with any mix of static and runtime-resolvable arms.
    • 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 work 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 as <n>/1 per spec.
    • @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.

    Features React Native does not yet support (position: fixed, position: sticky, backdrop-filter, 3D transforms, text-shadow, scroll-snap, view-transitions, form-state selectors, and more) are listed in the "React Native CSS Features" compatibility tracker maintained alongside the library.

  • c5e1c54: React Native: CSS transition, @keyframes, and @starting-style now animate.

    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.

  • c5e1c54: React Native: attribute selectors now apply styles based on the rendered element's props.

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

    The same CSS works on web and native. This is most useful for aria-* selectors since React Native forwards those to platform accessibility services. The presence-only form &[attr] matches whenever the prop is defined. The exact-match forms &[attr=value], &[attr='value'], and &[attr="value"] compare as strings, with boolean coercion so aria-pressed={true} and aria-pressed="true" both apply the rule. Other operators (~=, ^=, $=, *=, |=) are not supported on native.

  • c5e1c54: Added box-sizing and hyphens support to React Native styles.

    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 now flows through unchanged on iOS, Android, and rn-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 rn-web the browser handles it natively.

  • c5e1c54: Added cross-platform support for several CSS properties on React Native: caret-color, object-fit, vertical-align, backface-visibility, and outline-offset.

    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 rn-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 now flow through unchanged on iOS, Android, and rn-web.

  • c5e1c54: styled.ScrollView now defaults to flex-shrink: 0, matching the behavior of styled.View. Previously, an explicit width: or height: declaration on a ScrollView could be silently overridden by the layout engine when the component sat in a flex parent — the rendered width would come out smaller (or larger) than declared. The fix makes explicit dimensions pin reliably; you can still opt back into the old behavior by declaring flex-shrink: 1 in your own template.

  • c5e1c54: styled-components/native now ships a dedicated build for react-native-web consumers. Webpack, Vite, and Metro (when targeting web) pick it up automatically; no opt-in or import-path change is needed.

    The browser handles a handful of CSS features more accurately than a render-time polyfill ever could, so the new build defers to it:

    • light-dark() and prefers-color-scheme repaint without a React re-render
    • dvh / svh / lvh and the inline / block-axis viewport units (vi, vb) resolve distinctly per CSS Values 4 instead of collapsing
    • oklch, oklab, lch, lab, and color-mix() render in the browser's full wide gamut (Display P3 / Rec. 2020 where the monitor supports it) instead of rounding through sRGB
    • Static-mixed-unit calc() / clamp() / min() / max() resolve against the real containing block at paint time instead of the closest container ancestor

    The bundle is also ~10 kB smaller (gzipped: ~4 kB) than the iOS / Android bundle because the matching polyfills tree-shake out.

  • c5e1c54: Performance improvements across the board in v7. Component creation, SSR renderToString, and React Server Components rendering are all faster than v6, with SSR seeing the largest gains at scale. The eager-parse strategy folds template-literal work into construction time so renders pay less.

    To measure on your hardware:

    pnpm --filter @styled-components/benchmarks bench:headless
    

Patch Changes

  • c5e1c54: Fixed a TypeScript regression where styled(SomeComponent).attrs({...}) could trigger TS2590: Expression produces a union type that is too complex to represent on components with deeply-discriminated prop unions, notably antd's Button. Affected projects also see modestly faster type-checks; projects without complex unions see no measurable difference.

  • c5e1c54: React Native: lab() and lch() now produce correct colors when channels are written as percentages. lab(50% 0 0) resolves to mid-gray as expected, where it previously produced near-black. Per CSS Color L4, each space has its own range:

    • 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.

    Web is unaffected (browsers parse these notations natively).

  • c5e1c54: Empty CSS custom property values are now preserved.

    --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. Previously these declarations were silently dropped from the rendered output, which broke setups like:

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

    They now render as authored. Empty values for non-custom properties (e.g. color: ;) continue to be dropped, since those are still invalid CSS.

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

  • c5e1c54: Inlined the prop validator that decides which props reach the underlying DOM element. styled-components no longer pulls @emotion/is-prop-valid from npm; the same validation logic ships inside the library itself. Consumers see a smaller dependency tree and a slightly smaller installed footprint, with identical behavior.

    If you were already importing isPropValid from @emotion/is-prop-valid directly elsewhere in your app, that continues to work; this change only affects what styled-components itself depends on.

  • c5e1c54: Fixed selector resolution for nested rules whose parent contains a comma inside :is(), :where(), :has(), or an attribute selector.

    Previously a parent like :is(&:hover, .parent:hover &) .child containing a nested rule would produce nonsense output where the nested selector got injected into the first arm of the :is(...) call. For example:

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

    The grandchild rule used to compile to :is(.card-class:hover .grandchild, .parent:hover .card-class) .child .grandchild { color: blue; }, where the .grandchild token leaked into the :is() parens. It now compiles correctly to :is(.card-class:hover, .parent:hover .card-class) .child .grandchild { color: blue; }. The same fix applies to commas inside [attr*="a,b"] and other paren/bracket-protected contexts.

  • c5e1c54: Fixed background-position, background-size, and background-repeat declarations rejected by react-native-web when authored as a comma-separated list with the same value on every layer (e.g. background-position: 0% 0%, 0% 0%). The CSS shorthand already cycles a single value to all layers, so the redundant comma form now collapses at the boundary and reaches react-native-web as a single value while keeping multi-layer intent intact when the values actually differ.

  • c5e1c54: React Native: passing prop={undefined} to a styled component opts out of an attrs()-provided default, matching web behavior. <Comp accessible={undefined} /> renders with no accessible prop even when the component has .attrs({ accessible: true }).

  • 9894183: Development builds now warn when vertical-align is set on a native <Text> running on iOS.

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

  • c5e1c54: Fixed a styling leak when a nested <StyleSheetManager> sits beside other children of an outer <StyleSheetManager> in a server component tree.

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

    Previously ChildC was being styled with the inner manager's plugins because the inner subtree's configuration leaked back out. ChildC now correctly uses the outer manager's plugins.

  • c5e1c54: Server-side output escapes </style> substrings (rewritten as the CSS hex escape \3C/style, which the CSS engine still parses identically) and HTML-escapes nonce values before they reach the rendered <style ...> tag, so user-supplied content interpolated into styles can't break out and inject markup. In-browser style injection is unaffected.

  • c5e1c54: Fixed plain objects with a custom toString() being expanded as CSS-property blocks instead of stringified. Useful for design-token shapes where the token resolves to a default value but also carries alternate sub-values:

    const ink = {
      default: '[#000](https://github.com/styled-components/styled-components/issues/000)',
      subtle: '[#444](https://github.com/styled-components/styled-components/issues/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-[`20260511073743`](https://github.com/styled-components/styled-components/commit/20260511073743)...styled-components%407.0.0-prerelease-[`20260511181111`](https://github.com/styled-components/styled-components/commit/20260511181111)

styled-components@7.0.0-prerelease-20260511073743

Major Changes

  • 26a3151: React Native: createTheme() now works exactly the way it does on web. Pass the returned object to ThemeProvider, reference leaves in your styled components, and the current theme resolves automatically.

    import styled, { createTheme, ThemeProvider } from 'styled-components/native';
    
    
    const theme = createTheme({
      colors: { bg: '#ffffff', text: '[#111111](https://github.com/styled-components/styled-components/issues/111111)' },
    });
    
    
    const Card = styled.View`
      background-color: ${theme.colors.bg};
      border-color: ${theme.colors.text};
    `;
    
    
    <ThemeProvider theme={{ colors: { bg: '[#111](https://github.com/styled-components/styled-components/issues/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. Web behavior is unchanged.

  • 26a3151: Styled components no longer honor defaultProps. React 19 removed defaultProps support from function components, so styled components can no longer inherit a parent's defaultProps either.

    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.

  • 26a3151: Removed the disableCSSOMInjection prop on <StyleSheetManager> and the SC_DISABLE_SPEEDY / REACT_APP_SC_DISABLE_SPEEDY environment variables. Added a new extractCSS export.

    Browser builds now always use the same fast injection path that production has used by default for years. There's no longer a knob to switch into a slower text-based mode at runtime, and dev and production now behave identically.

    If you were using the toggle to make CSS visible as text (for static-render pipelines, micro-frontend cloning, embedding into iframes or Shadow DOM, or extraction tooling), call the new extractCSS() function 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.

  • 26a3151: Mounting the same createGlobalStyle component multiple times now emits its CSS only once. Previously each mount produced its own copy of the stylesheet rules. Rendering output stays byte-stable across SSR, client, and Server Components.

  • 26a3151: React Native: the CSS-to-style-object translation layer is now built in. Several long-standing limitations go away on the native path.

    • transform: matrix(...) / matrix3d(...) work.
    • transform: translateX(10) (bare number, no unit) works.
    • background-image: linear-gradient(...) / radial-gradient(...) work.
    • filter: blur(4px) saturate(1.5) and the full filter-function chain work.
    • Modern color notations pass through to React Native's color parser unchanged: rgb(r g b / a) slash-alpha, hwb(), hsl() all work.
    • box-shadow with spread and inset pass through as CSS strings.
    • mix-blend-mode, isolation, cursor flow through.
    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);
    `;
    

    The transform layer also fixes border: none emitting border-style: solid on native; it now emits border-style: none to match the rest of the ecosystem.

    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 work without this flag.

  • 26a3151: Raised peer dependency floors:

    • 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.
    • The enableVendorPrefixes prop on <StyleSheetManager> and the runtime vendor prefixer have been removed. Modern browser targets handle prefixing natively; for the few properties that still need them (e.g. -webkit-backdrop-filter on Safari), declare both the prefixed and unprefixed forms in your CSS, or run a build-time PostCSS transform.

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

  • 26a3151: Plugins moved to a dedicated styled-components/plugins subpath, and a first-party RTL plugin ships with the library.

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

    rtlPlugin replaces stylis-plugin-rtl for users coming from v6: it swaps physical side properties (padding-leftpadding-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.

    The stylisPlugins prop on <StyleSheetManager> is now plugins, and the top-level stylisPluginRSC export has moved into the new subpath as rscPlugin.

    Migration:

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

    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. Plugins are tree-shaken out of any app that doesn't import them.

    import type { SCPlugin } from 'styled-components';
    
    
    // `rw` runs on every fully-resolved selector after `&` substitution and
    // namespace prepending. Return a new selector string.
    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, 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;
      },
    };
    

    The name field is required and identifies the plugin so different plugin sets across nested <StyleSheetManager> trees stay isolated.

Minor Changes

  • 26a3151: 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.

    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. Works on web and native. When the callback's behavior is fully determined by static declarations the work folds into a one-time computation at construction so renders pay nothing extra.

  • 26a3151: Modern CSS functions now work in React Native styles. Static expressions resolve up front; values that depend on the device environment (viewport, container, safe area, color scheme) re-resolve as the environment changes.

    import styled from 'styled-components/native';
    
    
    const Card = styled.View`
      width: clamp(240px, 80vw, 480px);
      background-color: light-dark(white, [#111](https://github.com/styled-components/styled-components/issues/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) / calc(100vw - 40px) with any mix of static and runtime-resolvable arms.
    • 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 work 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 as <n>/1 per spec.
    • @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.

    Features React Native does not yet support (position: fixed, position: sticky, backdrop-filter, 3D transforms, text-shadow, scroll-snap, view-transitions, form-state selectors, and more) are listed in the "React Native CSS Features" compatibility tracker maintained alongside the library.

  • 26a3151: React Native: CSS transition, @keyframes, and @starting-style now animate.

    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.

  • 26a3151: React Native: attribute selectors now apply styles based on the rendered element's props.

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

    The same CSS works on web and native. This is most useful for aria-* selectors since React Native forwards those to platform accessibility services. The presence-only form &[attr] matches whenever the prop is defined. The exact-match forms &[attr=value], &[attr='value'], and &[attr="value"] compare as strings, with boolean coercion so aria-pressed={true} and aria-pressed="true" both apply the rule. Other operators (~=, ^=, $=, *=, |=) are not supported on native.

  • 26a3151: Added box-sizing and hyphens support to React Native styles.

    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 now flows through unchanged on iOS, Android, and rn-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 rn-web the browser handles it natively.

  • 26a3151: Added cross-platform support for several CSS properties on React Native: caret-color, object-fit, vertical-align, backface-visibility, and outline-offset.

    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 rn-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 now flow through unchanged on iOS, Android, and rn-web.

  • 26a3151: styled.ScrollView now defaults to flex-shrink: 0, matching the behavior of styled.View. Previously, an explicit width: or height: declaration on a ScrollView could be silently overridden by the layout engine when the component sat in a flex parent — the rendered width would come out smaller (or larger) than declared. The fix makes explicit dimensions pin reliably; you can still opt back into the old behavior by declaring flex-shrink: 1 in your own template.

  • 26a3151: styled-components/native now ships a dedicated build for react-native-web consumers. Webpack, Vite, and Metro (when targeting web) pick it up automatically; no opt-in or import-path change is needed.

    The browser handles a handful of CSS features more accurately than a render-time polyfill ever could, so the new build defers to it:

    • light-dark() and prefers-color-scheme repaint without a React re-render
    • dvh / svh / lvh and the inline / block-axis viewport units (vi, vb) resolve distinctly per CSS Values 4 instead of collapsing
    • oklch, oklab, lch, lab, and color-mix() render in the browser's full wide gamut (Display P3 / Rec. 2020 where the monitor supports it) instead of rounding through sRGB
    • Static-mixed-unit calc() / clamp() / min() / max() resolve against the real containing block at paint time instead of the closest container ancestor

    The bundle is also ~10 kB smaller (gzipped: ~4 kB) than the iOS / Android bundle because the matching polyfills tree-shake out.

  • 26a3151: Performance improvements across the board in v7. Component creation, SSR renderToString, and React Server Components rendering are all faster than v6, with SSR seeing the largest gains at scale. The eager-parse strategy folds template-literal work into construction time so renders pay less.

    To measure on your hardware:

    pnpm --filter @styled-components/benchmarks bench:headless
    

Patch Changes

  • 26a3151: Fixed a TypeScript regression where styled(SomeComponent).attrs({...}) could trigger TS2590: Expression produces a union type that is too complex to represent on components with deeply-discriminated prop unions, notably antd's Button. Affected projects also see modestly faster type-checks; projects without complex unions see no measurable difference.

  • 26a3151: React Native: lab() and lch() now produce correct colors when channels are written as percentages. lab(50% 0 0) resolves to mid-gray as expected, where it previously produced near-black. Per CSS Color L4, each space has its own range:

    • 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.

    Web is unaffected (browsers parse these notations natively).

  • 26a3151: Empty CSS custom property values are now preserved.

    --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. Previously these declarations were silently dropped from the rendered output, which broke setups like:

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

    They now render as authored. Empty values for non-custom properties (e.g. color: ;) continue to be dropped, since those are still invalid CSS.

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

  • 26a3151: Inlined the prop validator that decides which props reach the underlying DOM element. styled-components no longer pulls @emotion/is-prop-valid from npm; the same validation logic ships inside the library itself. Consumers see a smaller dependency tree and a slightly smaller installed footprint, with identical behavior.

    If you were already importing isPropValid from @emotion/is-prop-valid directly elsewhere in your app, that continues to work; this change only affects what styled-components itself depends on.

  • 26a3151: Fixed selector resolution for nested rules whose parent contains a comma inside :is(), :where(), :has(), or an attribute selector.

    Previously a parent like :is(&:hover, .parent:hover &) .child containing a nested rule would produce nonsense output where the nested selector got injected into the first arm of the :is(...) call. For example:

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

    The grandchild rule used to compile to :is(.card-class:hover .grandchild, .parent:hover .card-class) .child .grandchild { color: blue; }, where the .grandchild token leaked into the :is() parens. It now compiles correctly to :is(.card-class:hover, .parent:hover .card-class) .child .grandchild { color: blue; }. The same fix applies to commas inside [attr*="a,b"] and other paren/bracket-protected contexts.

  • 26a3151: Fixed background-position, background-size, and background-repeat declarations rejected by react-native-web when authored as a comma-separated list with the same value on every layer (e.g. background-position: 0% 0%, 0% 0%). The CSS shorthand already cycles a single value to all layers, so the redundant comma form now collapses at the boundary and reaches react-native-web as a single value while keeping multi-layer intent intact when the values actually differ.

  • 26a3151: React Native: passing prop={undefined} to a styled component opts out of an attrs()-provided default, matching web behavior. <Comp accessible={undefined} /> renders with no accessible prop even when the component has .attrs({ accessible: true }).

  • 26a3151: Fixed a styling leak when a nested <StyleSheetManager> sits beside other children of an outer <StyleSheetManager> in a server component tree.

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

    Previously ChildC was being styled with the inner manager's plugins because the inner subtree's configuration leaked back out. ChildC now correctly uses the outer manager's plugins.

  • 26a3151: Server-side output escapes </style> substrings (rewritten as the CSS hex escape \3C/style, which the CSS engine still parses identically) and HTML-escapes nonce values before they reach the rendered <style ...> tag, so user-supplied content interpolated into styles can't break out and inject markup. In-browser style injection is unaffected.

  • 26a3151: Fixed plain objects with a custom toString() being expanded as CSS-property blocks instead of stringified. Useful for design-token shapes where the token resolves to a default value but also carries alternate sub-values:

    const ink = {
      default: '[#000](https://github.com/styled-components/styled-components/issues/000)',
      subtle: '[#444](https://github.com/styled-components/styled-components/issues/444)',
      toString() {
        return this.default;
      },
    };
    
    
    const Heading = styled.h1`
      color: ${ink};
    `;
    

Full Changelog: https://github.com/styled-components/styled-components/compare/styled-components%406.4.1-prerelease-[`20260417184545`](https://github.com/styled-components/styled-components/commit/20260417184545)...styled-components%407.0.0-prerelease-[`20260511073743`](https://github.com/styled-components/styled-components/commit/20260511073743)

styled-components@6.4.1

Patch Changes

  • 49d09ae: Fix a performance regression in 6.4.0 where dynamic createGlobalStyle components caused significant re-render slowdowns. Also restores pre-6.4 cascade ordering when multiple instances of the same createGlobalStyle coexist.
  • eca95b2: Fix outdated dev-mode error messages for keyframes-in-untagged-strings and component-selector references that still pointed at www.styled-components.com and described behavior from styled-components v3.

styled-components@6.4.1-prerelease-20260417184545

Full Changelog: https://github.com/styled-components/styled-components/compare/styled-components@6.4.1-prerelease-[`20260417184031`](https://github.com/styled-components/styled-components/commit/20260417184031)...styled-components@6.4.1-prerelease-[`20260417184545`](https://github.com/styled-components/styled-components/commit/20260417184545)

styled-components@6.4.1-prerelease-20260417184031

styled-components@6.4.0

Minor Changes

  • 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](https://github.com/styled-components/styled-components/issues/000)' } });
    
    
    const DarkOverrides = createGlobalStyle`
      @media (prefers-color-scheme: dark) {
        :root {
          ${vars.colors.bg}: [#111](https://github.com/styled-components/styled-components/issues/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 forEachfor/for...of, template literal → manual concat, and reduced allocations.

    Benchmarks vs 6.3.12:

    • Parent re-render (most common): 3.3x faster
    • First mount: 1.7-2.5x faster
    • Prop cycling: 2.3-2.4x faster
    • 10K heavy layouts: 1.9x faster
    • No regressions on any benchmark
  • 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.

Patch Changes

  • b0f3d29: Expose as and forwardedAs props in React.ComponentProps extraction for styled components
  • 553cbb4: Fix memory leak in long-running apps using components with free-form string interpolations (e.g. color: ${p => p.$dynamicValue} where the value comes from unbounded user input).
  • b0f3d29: React Native improvements: replaced postcss with a lightweight CSS declaration parser, fixing 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.
  • 74e8b76: Smaller install footprint via unused dependency cleanup.

styled-components@6.3.12

Patch Changes

  • db4f940: Fix test performance regression in 6.3.x by eliminating double style rendering in createGlobalStyle and removing unnecessary DOM queries during cleanup in client/test environments.
  • 1203f80: Fix React Native crash caused by document references in the native build. The native bundle no longer includes DOM code, resolving compatibility with RN 0.79+ and Hermes.
  • 5ef3804: Gracefully handle CSS syntax errors in React Native instead of crashing. Missing semicolons and other syntax issues now log a warning in development and produce an empty style object instead of throwing a fatal error.
  • a777f5a: Preserve explicitly passed undefined props instead of stripping them. This fixes compatibility with libraries like MUI and Radix UI that pass undefined to reset inherited defaults (e.g., role={undefined}). Props set to undefined via .attrs() are still stripped as before.

styled-components@6.3.11

Patch Changes

  • 752f5ec: fix: resolve "React is not defined" ReferenceError introduced in 6.3.10 when loading the CJS build in Node.js

styled-components@6.3.10

Patch Changes

  • f674224: fix: RSC style tags for extended components have correct href and include base CSS (#5663)

    • Fix spaces in <style href> attribute that caused React 19 hydration failures when using styled() inheritance
    • Fix missing base component CSS in RSC output when only the extended component renders
    • Emit a separate <style> tag per inheritance level with content-aware hrefs, enabling React 19 deduplication of shared base styles
    • Preserve correct CSS ordering (base before extended) for proper specificity override behavior
  • f674224: Reduce standalone/browser bundle size by making IS_RSC a build-time constant, enabling dead code elimination of RSC-specific branches

styled-components@6.3.9

Patch Changes

  • ca61aca: Fix CSS block comments containing // (e.g. URLs) causing subsequent styles to not be applied.
  • a2cd792: Fix createGlobalStyle styles not being removed when unmounted in RSC environments. React 19's precedence attribute on style tags makes them persist as permanent resources; global styles now render without precedence so they follow normal component lifecycle.
  • dbe0aae: In RSC environments, theme is now undefined instead of {} for styled components, matching the existing behavior of withTheme and createGlobalStyle. This ensures accessing theme properties without a ThemeProvider correctly throws rather than silently returning undefined.
  • 1888c73: Fix withTheme HOC types: ref now correctly resolves to the component instance type instead of the constructor, and theme is properly optional in the wrapped component's props.
  • f84f3fa: Fix SSR styles hydration and global style cleanup in Shadow DOM
  • 43a5b4b: Optimize internal style processing hot paths: cached GroupedTag index lookups, string fast path in flatten, direct string concatenation in dynamic style generation, pre-built stylis middleware chain with lazy RegExp creation, single-lookup Map operations, VirtualTag append fast-path, and manual string concat in SSR output.
  • 788e8c0: Revert exports field and restore browser/server build split with browser field in package.json. Fixes require('stream') resolution errors in browser bundlers like webpack 5.

styled-components@6.3.8

Patch Changes

  • 55d05c1: Make react-dom an optional peer dependency, clean up some unnecessary type peers.

styled-components@6.3.7

Patch Changes

  • 51ffa9c: Fix createGlobalStyle compatibility with React StrictMode and RSC

    This fix addresses issues where global styles would disappear or behave incorrectly in React StrictMode and RSC:

    1. Static styles optimization: Static global styles (without props/interpolations) are now only injected once and won't be removed/re-added on every render. This prevents the style flickering that could occur during concurrent rendering.

    2. StrictMode-aware cleanup: Style cleanup now uses queueMicrotask to coordinate with React's effect lifecycle. In StrictMode's simulated unmount/remount cycle, styles are preserved. On real unmount, styles are properly removed.

    3. RSC compatibility: Move useRef inside RSC guard in createGlobalStyle and unify all useContext calls to use consistent !IS_RSC ? pattern.

    4. RSC inline style tag cleanup: Fix bug where server-defined createGlobalStyle rendered in client components would leave behind accumulated SSR-rendered inline <style data-styled-global> tags. The cleanup effect now removes these hoisted style tags when the component unmounts or re-renders with different CSS.

    These changes ensure createGlobalStyle works correctly with:

    • React StrictMode's double-render behavior
    • React 18/19's concurrent rendering features
    • React 19's style hoisting with the precedence attribute
    • React Server Components (server-defined GlobalStyles in client components)
  • 51ffa9c: Restore styled.br.

  • 1f794b7: Add package.json "exports" field for better native ESM integration.

styled-components@6.3.6

Patch Changes

  • 189bc17: Fix url() CSS function values being incorrectly stripped when using unquoted URLs containing // (e.g., url(https://example.com)). The // in protocol URLs like https://, http://, file://, and protocol-relative URLs was incorrectly being treated as a JavaScript-style line comment.

styled-components@6.3.5

Patch Changes

  • 7ff7002: Fix: Line comments (//) in multiline CSS declarations no longer cause parsing errors (fixes #5613)

    JS-style line comments (//) placed after multiline declarations like calc() were not being properly stripped, causing CSS parsing issues. Comments are now correctly removed anywhere in the CSS while preserving valid syntax.

    Example that now works:

    const Box = styled.div`
      max-height: calc(100px + 200px + 300px); // This comment no longer breaks parsing
      background-color: green;
    `;
    
  • 7ff7002: Fix: Contain invalid CSS syntax to just the affected line

    In styled-components v6, invalid CSS syntax (like unbalanced braces) could cause all subsequent styles to be ignored. This fix ensures that malformed CSS only affects the specific declaration, not subsequent valid styles.

    Example that now works:

    const Circle = styled.div`
      width: 100px;
      line-height: ${() => '14px}'}; // ⛔️ This malformed line is dropped
      background-color: green; // ✅ Now preserved (was ignored in v6)
    `;
    

styled-components@6.3.4

Patch Changes

  • 8e8c282: Fixed createGlobalStyle to not use useLayoutEffect on the server, which was causing a warning and broken styles in v6.3.x. The check typeof React.useLayoutEffect === 'function' is not reliable for detecting server vs client environments in React 18+, so we now use the __SERVER__ build constant instead.

styled-components@6.3.3

Patch Changes

  • 6e4d1e7: fix: suppress false "created dynamically" warnings in React Server Components

    The dynamic creation warning check now properly detects RSC environments and skips validation when IS_RSC is true. This eliminates false warnings for module-level styled components in server components, which were incorrectly flagged due to RSC's different module evaluation context. Module-level styled components in RSC files no longer trigger warnings since they cannot be created inside render functions by definition.

styled-components@6.3.2

Patch Changes

  • a4b4a6b: fix: include TypeScript declaration files in npm package

    Fixed Rollup TypeScript plugin configuration to override tsconfig.json's noEmit setting, ensuring TypeScript declaration files are generated during build.

  • a4b4a6b: fix: resolve TypeScript error blocking type declaration emission

    Fixed TypeScript error in StyledComponent when merging style attributes from attrs. Added explicit type cast to React.CSSProperties to safely merge CSS property objects. This error was preventing TypeScript declaration files from being generated during build.

styled-components@6.3.1

Patch Changes

  • 046e880: Ensure TypeScript declaration files are included in npm package, needed to tweak a Rollup setting.

styled-components@6.3.0

Minor Changes

  • 28fd502: Add React Server Components (RSC) support

    styled-components now automatically detects RSC environments and handles CSS delivery appropriately:

    • No 'use client' directive required: Components work in RSC without any wrapper or directive
    • Automatic CSS injection: In RSC mode, styled components emit inline <style> tags that React 19 automatically hoists and deduplicates
    • Zero configuration: Works out of the box with Next.js App Router and other RSC-enabled frameworks
    • Backward compatible: Existing SSR patterns with ServerStyleSheet continue to work unchanged

    RSC best practices:

    • Prefer static styles over dynamic interpolations to avoid serialization overhead
    • Use data attributes for discrete variants (e.g., &[data-size='lg'])
    • CSS custom properties work perfectly in styled-components, can be set via inline style, and cascade to children:
    const Container = styled.div``;
    const Button = styled.button`
      background: var(--color-primary, blue);
    `;
    
    
    // Variables set on parent cascade to all DOM children
    <Container style={{ '--color-primary': 'orchid' }}>
      <Button>Inherits orchid background</Button>
    </Container>;
    
    • Use build-time CSS variable generation for theming since ThemeProvider is a no-op in RSC

    Technical details:

    • RSC detection via typeof React.createContext === 'undefined'
    • ThemeProvider and StyleSheetManager become no-ops in RSC (children pass-through)
    • React hooks are conditionally accessed via runtime guards
    • CSS is retrieved from the StyleSheet Tag for inline delivery in RSC mode
  • 856cf06: feat: update built-in element aliases to include modern HTML and SVG elements

    Added support for modern HTML and SVG elements that were previously missing:

    HTML elements:

    • search - HTML5 search element
    • slot - Web Components slot element
    • template - HTML template element

    SVG filter elements:

    • All fe* filter primitive elements (feBlend, feColorMatrix, feComponentTransfer, etc.)
    • clipPath, linearGradient, radialGradient - gradient and clipping elements
    • textPath - SVG text path element
    • switch, symbol, use - SVG structural elements

    This ensures styled-components has comprehensive coverage of all styleable HTML and SVG elements supported by modern browsers and React.

Patch Changes

  • 418adbe: fix(types): add CSS custom properties (variables) support to style prop

    CSS custom properties (CSS variables like --primary-color) are now fully supported in TypeScript without errors:

    • .attrs({ style: { '--var': 'value' } }) - CSS variables in attrs
    • <Component style={{ '--var': 'value' }} /> - CSS variables in component props
    • Mixed usage with regular CSS properties works seamlessly
  • aef2ad6: Update shared css property handling tools to latest versions.

styled-components@6.2.0

Minor Changes

  • e7c8055: Experimental support for React 18+ renderToPipeableStream.

Patch Changes

  • d0b73ac: Fix no longer existing link in console debug message

  • 8a9c21b: Upgrade stylis to 4.3.6. Related commits

  • a21089e: Update internal React types to ^18

  • c3a5990: Update csstype dependency from 3.1.3 to 3.2.3

    This updates the pinned csstype dependency from 3.1.3 to 3.2.3 to fix a type incompatibility with @types/react.

styled-components@6.1.19

Patch Changes

  • aa997d8: fix for React Native >=0.79 crashes when using unsupported web-only CSS values (e.g., fit-content, min-content, max-content). The fix emits a warning and ignores the property using those values, instead of causing crashes.

styled-components@6.1.18

Patch Changes

  • 76b18a4: fix react 19 compatibility
  • bdac7af: Quickfix to support expo sdk >= 53 and react-native >=0.79.

styled-components@6.1.17

Patch Changes

  • 47a4dcb: Fix for loose DefaultTheme type definition
  • a8c0f5b: fix: add info link to console

styled-components@6.1.16

Patch Changes

  • 246c77b: Resolve TS error related to ExoticComponentWithDisplayName API from React.
  • 4757191: Native typings weren't on the correct folder, which caused issues on React Native projects using this library

styled-components@6.1.15

Patch Changes

  • b9688ae: chore: update postcss to version 8.4.49 and nanoid to version 3.3.8

styled-components@6.1.14

Patch Changes

  • 6908326: Add changesets for release management
  • 18ebf6d: Prevent styled() from injecting an undefined ref prop in React 19

v6.1.13

What's Changed

New Contributors

Full Changelog: https://github.com/styled-components/styled-components/compare/v6.1.12...v6.1.13

v6.1.12

What's Changed

New Contributors

Full Changelog: https://github.com/styled-components/styled-components/compare/v6.1.11...v6.1.12

v6.1.11

What's Changed

Full Changelog: https://github.com/styled-components/styled-components/compare/v6.1.10...v6.1.11

v6.1.10

What's Changed

New Contributors

Full Changelog: https://github.com/styled-components/styled-components/compare/v6.1.9...v6.1.10

v6.1.9

What's Changed

New Contributors

Full Changelog: https://github.com/styled-components/styled-components/compare/v6.1.8...v6.1.9

v6.1.8

Revert adding peerDependencies from v6.1.7; apparently some package managers have differing behaviors around peerDependenciesMeta[package].optional which is causing issues. Will revisit at a later date if possible.

Full Changelog: https://github.com/styled-components/styled-components/compare/v6.1.7...v6.1.8

v6.1.7

What's Changed

  • chore: add all missing peer dependency statements by @quantizor in https://github.com/styled-components/styled-components/pull/4243

    NOTE: this change may cause some installed dependency duplication until this NPM bug is addressed but yarn and pnpm have correct behavior. Bun also has a similar bug.

    Overall these changes ensure that styled-components is specifying a known working version of all utilized libraries, while instructing the client package manager that higher semver-compliant versions are permissible and should work, assuming the relevant libraries are compliant in practice.

Full Changelog: https://github.com/styled-components/styled-components/compare/v6.1.6...v6.1.7

v6.1.6

What's Changed

Full Changelog: https://github.com/styled-components/styled-components/compare/v6.1.5...v6.1.6

v6.1.5

What's Changed

Full Changelog: https://github.com/styled-components/styled-components/compare/v6.1.4...v6.1.5

v6.1.4

What's Changed

Full Changelog: https://github.com/styled-components/styled-components/compare/v6.1.3...v6.1.4

v6.1.3

What's Changed

New Contributors

Full Changelog: https://github.com/styled-components/styled-components/compare/v6.1.2...v6.1.3

v6.1.2

What's Changed

New Contributors

Full Changelog: https://github.com/styled-components/styled-components/compare/v6.1.1...v6.1.2

v6.1.1

What's Changed

New Contributors

Full Changelog: https://github.com/styled-components/styled-components/compare/v6.1.0...v6.1.1

v6.1.0

What's Changed

New Contributors

Full Changelog: https://github.com/styled-components/styled-components/compare/v6.0.9...v6.1.0

v6.0.9

fix bundling to not hardcode window (should fix some testing use cases that were incorrectly assuming a server environment when JSDOM and similar are in use)

Full Changelog: https://github.com/styled-components/styled-components/compare/v6.0.8...v6.0.9

v6.0.8

What's Changed

New Contributors

Full Changelog: https://github.com/styled-components/styled-components/compare/v6.0.7...v6.0.8

v6.0.7

What's Changed

New Contributors

Full Changelog: https://github.com/styled-components/styled-components/compare/v6.0.6...v6.0.7

v6.0.6

What's Changed

New Contributors

Full Changelog: https://github.com/styled-components/styled-components/compare/v6.0.5...v6.0.6

v6.0.5

What's Changed

New Contributors

Full Changelog: https://github.com/styled-components/styled-components/compare/v6.0.4...v6.0.5

v6.0.4

What's Changed

New Contributors

Full Changelog: https://github.com/styled-components/styled-components/compare/v6.0.3...v6.0.4

v6.0.3

What's Changed

New Contributors

Full Changelog: https://github.com/styled-components/styled-components/compare/v6.0.2...v6.0.3

v6.0.2

What's Changed

New Contributors

Full Changelog: https://github.com/styled-components/styled-components/compare/v6.0.1...v6.0.2

v6.0.1

Fixed an issue where a dev-time warning was being triggered too eagerly.

Full Changelog: https://github.com/styled-components/styled-components/compare/v6.0.0...v6.0.1

v6.0.0

yarn add styled-components

Changed in this version

Breaking changes in v6

Migration guide → https://styled-components.com/docs/faqs#what-do-i-need-to-do-to-migrate-to-v6

  • now using stylis v4 (if using stylis-plugin-rtl you'll need to upgrade to the newer version)
  • styled-components now provides its own types; if you installed @types/styled-components in the past, you'll want to remove it
  • dropped $as and $forwardedAs props (use as or forwardedAs)
  • dropped automatic prop filtering; use transient props ($ prefix) for stuff you don't want to be passed to child component / HTML
  • StyleSheetManager
    • replaced disableVendorPrefixes with enableVendorPrefixes prop
    • dropped automatic vendor prefixing; if you need to support older browsers, you can re-enable it easily with the above prop
      <StyleSheetManager enableVendorPrefixes>
        {/* your React tree and ThemeProvider goes here */}
      </StyleSheetManager>
      
  • dropped deprecated withComponent API (87f511a228e5b13b1ff70a416409e0705e5bf456); use "as" prop instead
  • node >= 14 needed

Full Changelog: https://github.com/styled-components/styled-components/compare/v5.3.7...v6.0.0

v6.0.0-rc.6

yarn add styled-components

Changed in this version

Breaking changes in v6

Migration guide → https://styled-components.com/docs/faqs#what-do-i-need-to-do-to-migrate-to-v6

  • now using stylis v4 (if using stylis-plugin-rtl you'll need to upgrade to the newer version)
  • styled-components now provides its own types; if you installed @types/styled-components in the past, you'll want to remove it
  • dropped $as and $forwardedAs props (use as or forwardedAs)
  • dropped automatic prop filtering; use transient props ($ prefix) for stuff you don't want to be passed to child component / HTML
  • StyleSheetManager
    • replaced disableVendorPrefixes with enableVendorPrefixes prop
    • dropped automatic vendor prefixing; if you need to support older browsers, you can re-enable it easily with the above prop
      <StyleSheetManager enableVendorPrefixes>
        {/* your React tree and ThemeProvider goes here */}
      </StyleSheetManager>
      
  • dropped deprecated withComponent API (87f511a228e5b13b1ff70a416409e0705e5bf456); use "as" prop instead
  • node >= 14 needed

Full Changelog: https://github.com/styled-components/styled-components/compare/v6.0.0-rc.5..v6.0.0-rc.6

v6.0.0-rc.5

yarn add styled-components

Changed in this version

New Contributors

Breaking changes in v6

Migration guide → https://styled-components.com/docs/faqs#what-do-i-need-to-do-to-migrate-to-v6

  • now using stylis v4 (if using stylis-plugin-rtl you'll need to upgrade to the newer version)
  • styled-components now provides its own types; if you installed @types/styled-components in the past, you'll want to remove it
  • dropped $as and $forwardedAs props (use as or forwardedAs)
  • dropped automatic prop filtering; use transient props ($ prefix) for stuff you don't want to be passed to child component / HTML
  • StyleSheetManager
    • replaced disableVendorPrefixes with enableVendorPrefixes prop
    • dropped automatic vendor prefixing; if you need to support older browsers, you can re-enable it easily with the above prop
      <StyleSheetManager enableVendorPrefixes>
        {/* your React tree and ThemeProvider goes here */}
      </StyleSheetManager>
      
  • dropped deprecated withComponent API (87f511a228e5b13b1ff70a416409e0705e5bf456); use "as" prop instead
  • node >= 14 needed

Full Changelog: https://github.com/styled-components/styled-components/compare/v6.0.0-rc.3..v6.0.0-rc.5

v6.0.0-rc.3

Full Changelog: https://github.com/styled-components/styled-components/compare/v6.0.0-rc.2...v6.0.0-rc.3

v5.3.11

Removed use of the useDebugValue hook to rectify older React support.

Full Changelog: https://github.com/styled-components/styled-components/compare/v5.3.10...v5.3.11

v6.0.0-rc.2

yarn add styled-components

Changed in this version

New Contributors

Upcoming

  • v6 migration documentation

Breaking changes in v6

  • now using stylis v4 (if using stylis-plugin-rtl you'll need to upgrade to the newer version)
  • styled-components now provides its own types; if you installed @types/styled-components in the past, you'll want to remove it
  • dropped $as and $forwardedAs props (use as or forwardedAs)
  • dropped automatic prop filtering; use transient props ($ prefix) for stuff you don't want to be passed to child component / HTML
  • StyleSheetManager
    • replaced disableVendorPrefixes with enableVendorPrefixes prop
    • dropped automatic vendor prefixing; if you need to support older browsers, you can re-enable it easily with the above prop
      <StyleSheetManager enableVendorPrefixes>
        {/* your React tree and ThemeProvider goes here */}
      </StyleSheetManager>
      
  • dropped deprecated withComponent API (87f511a228e5b13b1ff70a416409e0705e5bf456); use "as" prop instead
  • node >= 14 needed

Full Changelog: https://github.com/styled-components/styled-components/compare/v6.0.0-rc.1...v6.0.0-rc.2

v6.0.0-rc.1

yarn add styled-components

Changed in this version

  • bump stylis to 4.2.0 to enable @layer rule support

Upcoming

  • v6 migration documentation

Breaking changes in v6

  • now using stylis v4 (if using stylis-plugin-rtl you'll need to upgrade to the newer version)
  • styled-components now provides its own types; if you installed @types/styled-components in the past, you'll want to remove it
  • dropped $as and $forwardedAs props (use as or forwardedAs)
  • dropped automatic prop filtering; use transient props ($ prefix) for stuff you don't want to be passed to child component / HTML
  • StyleSheetManager
    • replaced disableVendorPrefixes with enableVendorPrefixes prop
    • dropped automatic vendor prefixing; if you need to support older browsers, you can re-enable it easily with the above prop
      <StyleSheetManager enableVendorPrefixes>
        {/* your React tree and ThemeProvider goes here */}
      </StyleSheetManager>
      
  • dropped deprecated withComponent API (87f511a228e5b13b1ff70a416409e0705e5bf456); use "as" prop instead
  • node >= 14 needed

Full Changelog: https://github.com/styled-components/styled-components/compare/v6.0.0-rc.0...v6.0.0-rc.1

v6.0.0-rc.0

yarn add styled-components@beta

Changed in this version

Upcoming

Breaking changes in v6

  • now using stylis v4 (if using stylis-plugin-rtl you'll need to upgrade to the newer version)
  • styled-components now provides its own types; if you installed @types/styled-components in the past, you'll want to remove it
  • dropped $as and $forwardedAs props (use as or forwardedAs)
  • dropped automatic prop filtering; use transient props ($ prefix) for stuff you don't want to be passed to child component / HTML
  • StyleSheetManager
    • replaced disableVendorPrefixes with enableVendorPrefixes prop
    • dropped automatic vendor prefixing; if you need to support older browsers, you can re-enable it easily with the above prop
      <StyleSheetManager enableVendorPrefixes>
        {/* your React tree and ThemeProvider goes here */}
      </StyleSheetManager>
      
  • dropped deprecated withComponent API (87f511a228e5b13b1ff70a416409e0705e5bf456); use "as" prop instead
  • node >= 14 needed

New Contributors (thank you!)

Full Changelog: https://github.com/styled-components/styled-components/compare/v6.0.0-beta.15...v6.0.0-rc.0

v6.0.0-beta.15

yarn add styled-components@beta

Changed in this version

Breaking changes in v6

  • now using stylis v4 (if using stylis-plugin-rtl you'll need to upgrade to the newer version)
  • styled-components now provides its own types; if you installed @types/styled-components in the past, you'll want to remove it
  • dropped $as and $forwardedAs props (use as or forwardedAs)
  • dropped automatic prop filtering; use transient props ($ prefix) for stuff you don't want to be passed to child component / HTML
  • StyleSheetManager
    • replaced disableVendorPrefixes with enableVendorPrefixes prop
    • dropped automatic vendor prefixing; if you need to support older browsers, you can re-enable it easily with the above prop
      <StyleSheetManager enableVendorPrefixes>
        {/* your React tree and ThemeProvider goes here */}
      </StyleSheetManager>
      
  • dropped deprecated withComponent API (87f511a228e5b13b1ff70a416409e0705e5bf456); use "as" prop instead
  • node >= 14 needed

New Contributors (thank you!)

Full Changelog: https://github.com/styled-components/styled-components/compare/v6.0.0-beta.14...v6.0.0-beta.15

v5.3.10

v6.0.0-beta.14

yarn add styled-components@beta

Changed in this version

Breaking changes in v6

  • now using stylis v4 (if using stylis-plugin-rtl you'll need to upgrade to the newer version)
  • styled-components now provides its own types; if you installed @types/styled-components in the past, you'll want to remove it
  • dropped $as and $forwardedAs props (use as or forwardedAs)
  • dropped automatic prop filtering; use transient props ($ prefix) for stuff you don't want to be passed to child component / HTML
  • StyleSheetManager
    • replaced disableVendorPrefixes with enableVendorPrefixes prop
    • dropped automatic vendor prefixing; if you need to support older browsers, you can re-enable it easily with the above prop
      <StyleSheetManager enableVendorPrefixes>
        {/* your React tree and ThemeProvider goes here */}
      </StyleSheetManager>
      
  • dropped deprecated withComponent API (87f511a228e5b13b1ff70a416409e0705e5bf456); use "as" prop instead
  • node >= 14 needed

New Contributors (thank you!)

Full Changelog: https://github.com/styled-components/styled-components/compare/v6.0.0-beta.13...v6.0.0-beta.14

v5.3.9

What's Changed

Full Changelog: https://github.com/styled-components/styled-components/compare/v5.3.8...v5.3.9

v6.0.0-beta.13

yarn add styled-components@beta

Changed in this version

Breaking changes in v6

  • now using stylis v4 (if using stylis-plugin-rtl you'll need to upgrade to the newer version)
  • styled-components now provides its own types; if you installed @types/styled-components in the past, you'll want to remove it
  • dropped $as and $forwardedAs props (use as or forwardedAs)
  • dropped automatic prop filtering; use transient props ($ prefix) for stuff you don't want to be passed to child component / HTML
  • dropped deprecated withComponent API (87f511a228e5b13b1ff70a416409e0705e5bf456); use "as" prop instead
  • node >= 14 needed

New Contributors (thank you!)

Full Changelog: https://github.com/styled-components/styled-components/compare/v6.0.0-beta.11...v6.0.0-beta.12

v6.0.0-beta.12

yarn add styled-components@beta

Changed in this version

  • fix(types): restore exotic component prop passing (f678107f420ecf5454aa6326bd6819d83a61c09d); this restores React.ComponentProps<typeof MyStyledComponent> support
  • add "exports" config in package.json
  • minor dependency updates
  • thank you @marmite22 for updating a test that was not getting properly run

Breaking changes in v6

  • now using stylis v4 (if using stylis-plugin-rtl you'll need to upgrade to the newer version)
  • styled-components now provides its own types; if you installed @types/styled-components in the past, you'll want to remove it
  • dropped $as and $forwardedAs props (use as or forwardedAs)
  • dropped automatic prop filtering; use transient props ($ prefix) for stuff you don't want to be passed to child component / HTML
  • dropped deprecated withComponent API (87f511a228e5b13b1ff70a416409e0705e5bf456); use "as" prop instead
  • node >= 14 needed

Full Changelog: https://github.com/styled-components/styled-components/compare/v6.0.0-beta.11...v6.0.0-beta.12

v5.3.8

What's Changed

fix(constants): rework process env guard

Full Changelog: https://github.com/styled-components/styled-components/compare/v5.3.7-fixed...v5.3.8

v5.3.7

  • fix: (React Native) passing testID as attrs property by @ku8ar (see #3857)

  • fix: prevent crash when process.env is not defined by Suhas R (see #3957)

  • Add support for the translate attribute as a valid prop by @ay4toh5i (see #3619)

  • remove Ukraine message; it's now out of date and the message has been received

v6.0.0-beta.11

yarn add styled-components@beta

Changed in this version

Breaking changes in v6

  • now using stylis v4 (if using stylis-plugin-rtl you'll need to upgrade to the newer version)
  • styled-components now provides its own types; if you installed @types/styled-components in the past, you'll want to remove it
  • dropped $as and $forwardedAs props (use as or forwardedAs)
  • dropped automatic prop filtering; use transient props ($ prefix) for stuff you don't want to be passed to child component / HTML
  • dropped deprecated withComponent API (87f511a228e5b13b1ff70a416409e0705e5bf456); use "as" prop instead
  • node >= 14 needed

Full Changelog: https://github.com/styled-components/styled-components/compare/v6.0.0-beta.10...v6.0.0-beta.11

v6.0.0-beta.10

yarn add styled-components@beta

Changed in this version

Breaking changes in v6

  • now using stylis v4 (if using stylis-plugin-rtl you'll need to upgrade to the newer version)
  • styled-components now provides its own types; if you installed @types/styled-components in the past, you'll want to remove it
  • dropped $as and $forwardedAs props (use as or forwardedAs)
  • dropped automatic prop filtering; use transient props ($ prefix) for stuff you don't want to be passed to child component / HTML
  • dropped deprecated withComponent API (87f511a228e5b13b1ff70a416409e0705e5bf456); use "as" prop instead
  • node >= 14 needed

New Contributors

Full Changelog: https://github.com/styled-components/styled-components/compare/v6.0.0-beta.9...v6.0.0-beta.10

v6.0.0-beta.9

yarn add styled-components@beta

What's Changed

New Contributors

Breaking changes in v6

  • now using stylis v4 (if using stylis-plugin-rtl you'll need to upgrade to the newer version)
  • styled-components now provides its own types; if you installed @types/styled-components in the past, you'll want to remove it
  • dropped $as and $forwardedAs props (use as or forwardedAs)
  • dropped automatic prop filtering; use transient props ($ prefix) for stuff you don't want to be passed to child component / HTML
  • dropped deprecated withComponent API (87f511a228e5b13b1ff70a416409e0705e5bf456); use "as" prop instead
  • node >= 14 needed

Full Changelog: https://github.com/styled-components/styled-components/compare/v6.0.0-beta.8...v6.0.0-beta.9

v6.0.0-beta.8

yarn add styled-components@beta

What's Changed

Breaking changes in v6

  • now using stylis v4 (if using stylis-plugin-rtl you'll need to upgrade to the newer version)
  • styled-components now provides its own types; if you installed @types/styled-components in the past, you'll want to remove it
  • dropped $as and $forwardedAs props (use as or forwardedAs)
  • dropped automatic prop filtering; use transient props ($ prefix) for stuff you don't want to be passed to child component / HTML
  • dropped deprecated withComponent API (87f511a228e5b13b1ff70a416409e0705e5bf456); use "as" prop instead
  • node >= 14 needed

Full Changelog: https://github.com/styled-components/styled-components/compare/v6.0.0-beta.7...v6.0.0-beta.8

v6.0.0-beta.7

yarn add styled-components@beta

What's Changed

  • feat(StyleSheetManager): add optional namespacing (#3881); replaces functionality in the babel plugin to be performed at runtime
  • breaking refactor: remove deprecated withComponent API (87f511a228e5b13b1ff70a416409e0705e5bf456); use "as" prop instead
  • feat: add styled as named export as well (5aed9e3f84cd52fa053693d5b66dc5a0f0c82ee9); note that this syntax will probably not work with the babel plugin until it is updated
  • chore: dependency maintenance, including rollup upgrades

Breaking changes in v6

  • now using stylis v4 (if using stylis-plugin-rtl you'll need to upgrade to the newer version)
  • styled-components now provides its own types; if you installed @types/styled-components in the past, you'll want to remove it
  • dropped $as and $forwardedAs props (use as or forwardedAs)
  • dropped automatic prop filtering; use transient props ($ prefix) for stuff you don't want to be passed to child component / HTML
  • dropped deprecated withComponent API (87f511a228e5b13b1ff70a416409e0705e5bf456); use "as" prop instead
  • node >= 14 needed

Full Changelog: https://github.com/styled-components/styled-components/compare/v6.0.0-beta.6...v6.0.0-beta.7

v6.0.0-beta.6

yarn add styled-components@beta

What's Changed

Breaking changes in v6 (as of this version)

  • now using stylis v4 (if using stylis-plugin-rtl you'll need to upgrade to the newer version)
  • styled-components now provides its own types; if you installed @types/styled-components in the past, you'll want to remove it
  • dropped $as and $forwardedAs props (use as or forwardedAs)
  • dropped automatic prop filtering; use transient props ($ prefix) for stuff you don't want to be passed to child component / HTML
  • dropped deprecated withComponent API (87f511a228e5b13b1ff70a416409e0705e5bf456); use "as" prop instead
  • node >= 14 needed

Full Changelog: https://github.com/styled-components/styled-components/compare/v6.0.0-beta.5...v6.0.0-beta.6

v6.0.0-beta.5

yarn add styled-components@beta

What's Changed

Breaking changes in v6

  • now using stylis v4 (if using stylis-plugin-rtl you'll need to upgrade to the newer version)
  • styled-components now provides its own types; if you installed @types/styled-components in the past, you'll want to remove it
  • dropped $as and $forwardedAs props (use as or forwardedAs)
  • dropped automatic prop filtering; use transient props ($ prefix) for stuff you don't want to be passed to child component / HTML
  • dropped deprecated withComponent API (87f511a228e5b13b1ff70a416409e0705e5bf456); use "as" prop instead
  • node >= 14 needed

Full Changelog: https://github.com/styled-components/styled-components/compare/v6.0.0-beta.4...v6.0.0-beta.5

v6.0.0-beta.4

yarn add styled-components@beta

What's Changed

Breaking changes in v6

  • now using stylis v4 (if using stylis-plugin-rtl you'll need to upgrade to the newer version)
  • styled-components now provides its own types; if you installed @types/styled-components in the past, you'll want to remove it
  • dropped $as and $forwardedAs props (use as or forwardedAs)
  • dropped automatic prop filtering; use transient props ($ prefix) for stuff you don't want to be passed to child component / HTML
  • dropped deprecated withComponent API (87f511a228e5b13b1ff70a416409e0705e5bf456); use "as" prop instead
  • node >= 14 needed

Full Changelog: https://github.com/styled-components/styled-components/compare/v6.0.0-beta.3...v6.0.0-beta.4

v6.0.0-beta.3

yarn add styled-components@beta

What's Changed

Breaking changes in v6

  • now using stylis v4 (if using stylis-plugin-rtl you'll need to upgrade to the newer version)
  • styled-components now provides its own types; if you installed @types/styled-components in the past, you'll want to remove it
  • dropped $as and $forwardedAs props (use as or forwardedAs)
  • dropped automatic prop filtering; use transient props ($ prefix) for stuff you don't want to be passed to child component / HTML
  • dropped deprecated withComponent API (87f511a228e5b13b1ff70a416409e0705e5bf456); use "as" prop instead
  • node >= 14 needed

Full Changelog: https://github.com/styled-components/styled-components/compare/v6.0.0-beta.2...v6.0.0-beta.3

v5.3.6

What's Changed

Deprecations

  • $as and $forwardedAs will be removed in the next major version, use the unprefixed props instead

New Contributors

Full Changelog: https://github.com/styled-components/styled-components/compare/v5.3.5...v5.3.6

v6.0.0 beta 2

yarn add styled-components@beta

What's Changed

Breaking changes in v6

  • now using stylis v4 (if using stylis-plugin-rtl you'll need to upgrade to the newer version)
  • styled-components now provides its own types; if you installed @types/styled-components in the past, you'll want to remove it
  • dropped $as and $forwardedAs props (use as or forwardedAs)
  • dropped automatic prop filtering; use transient props ($ prefix) for stuff you don't want to be passed to child component / HTML
  • dropped deprecated withComponent API (87f511a228e5b13b1ff70a416409e0705e5bf456); use "as" prop instead
  • node >= 14 needed

Full Changelog: https://github.com/styled-components/styled-components/compare/v6.0.0-beta.1...v6.0.0-beta.2

v6.0.0 beta 1

yarn add styled-components@beta

What's Changed

Breaking changes in v6

  • now using stylis v4 (if using stylis-plugin-rtl you'll need to upgrade to the newer version)
  • styled-components now provides its own types; if you installed @types/styled-components in the past, you'll want to remove it
  • dropped $as and $forwardedAs props (use as or forwardedAs)
  • dropped automatic prop filtering; use transient props ($ prefix) for stuff you don't want to be passed to child component / HTML
  • dropped deprecated withComponent API (87f511a228e5b13b1ff70a416409e0705e5bf456); use "as" prop instead
  • node >= 14 needed

Full Changelog: https://github.com/styled-components/styled-components/compare/v6.0.0-beta.0...v6.0.0-beta.1

v6.0.0 beta 0

yarn add styled-components@beta

What's Changed

Breaking changes in v6

  • now using stylis v4 (if using stylis-plugin-rtl you'll need to upgrade to the newer version)
  • styled-components now provides its own types; if you installed @types/styled-components in the past, you'll want to remove it
  • dropped $as and $forwardedAs props (use as or forwardedAs)
  • dropped automatic prop filtering; use transient props ($ prefix) for stuff you don't want to be passed to child component / HTML
  • dropped deprecated withComponent API (87f511a228e5b13b1ff70a416409e0705e5bf456); use "as" prop instead
  • node >= 14 needed

New Contributors

Full Changelog: https://github.com/styled-components/styled-components/compare/v6.0.0-alpha.5...v6.0.0-beta.0

v6.0.0-alpha.5

  • Fix types associated with styled-components/macros
  • Add optional peer dependency for babel-plugin-styled-components (required for macros)

Updated sandbox for alpha: https://codesandbox.io/s/styled-components-v6-alpha-sandbox-05bod1?file=/src/App.tsx

Full Changelog: https://github.com/styled-components/styled-components/compare/v6.0.0-alpha.4...v6.0.0-alpha.5

v6.0.0-alpha.4

  • Added type for CSSProp (this is in definitely typed but wasn't exposed by us)
  • Exposed more base types

Recommended styled-components.d.ts setup for your project:

// create styled-components.d.ts in your project source
// if it isn't being picked up, check tsconfig compilerOptions.types
import type { CSSProp } from 'styled-components';
import Theme from './theme';


type ThemeType = typeof Theme;


declare module 'styled-components' {
  export interface DefaultTheme extends ThemeType {}
}


declare module 'react' {
  interface DOMAttributes<T> {
    css?: CSSProp;
  }
}

Full Changelog: https://github.com/styled-components/styled-components/compare/v6.0.0-alpha.2...v6.0.0-alpha.4

v6.0.0-alpha.2

Added "types" package.json fields for TS type acquistion.

Full Changelog: https://github.com/styled-components/styled-components/compare/v6.0.0-alpha.1...v6.0.0-alpha.2

v5.3.5

Add statement of solidarity against the war on Ukraine 🇺🇦

v6.0.0-alpha.1

Fixed the TS declarations not getting emitted correctly by rollup.

Full Changelog: https://github.com/styled-components/styled-components/compare/.v6.0.0-alpha.0...v6.0.0-alpha.1

v6.0.0-alpha.0

After an epic amount of refactoring, I'm pleased to announce the first alpha of styled-components v6!

Highlights:

  1. styled-components is now written in TypeScript and ships its own types
  2. stylis v4
  3. tons of bug fixes
  4. node 14+ now required

Full Changelog: https://github.com/styled-components/styled-components/compare/v5.2.0...v6.0.0-alpha.0

v5.3.3

What's Changed

New Contributors

Full Changelog: https://github.com/styled-components/styled-components/compare/v5.3.1...v5.3.3

v5.3.1

  • Fix forced server-side mode not triggering global styles (See #3566)

  • Fix SSR collisions caused by insufficient hash inputs and reordering of groups on the client, which is a regression in v5.2.0 (See #3563)

  • Fix dynamic creation React warning for React v18, backported to v5 by @lynndylanhurley (See #3564)

  • Add missing typeof window check when checking for duplicate instances of styled-components (See #3553)

  • Prevent ServerStyleSheet from emitting empty style tags, which would cause issues in IE11 (See #3555)

  • Support css tagged templates inside style objects, by @roginfarrer and @dvingo (See #3469)

v5.3.0

  • Pass elementToBeCreated as a third parameter to shouldForwardProp so that the user-specified function can decide whether to pass through props based on whether the created element will be a tag or another component. (see #3436)

  • Fix React Native components accepts function as style prop. (see #3389)

v5.2.3

fix an issue with an unguarded window accessor in a SSR path ([see #3446](https://github.com/styled-components/styled-components/pull/3446))

v5.2.1

Tweak server-side build settings to resolve an issue with jest-dom not being able to pick up generated styles (see #3308) thanks @Lazyuki

v5.2.0

  • Make sure StyleSheetManager renders all styles in iframe / child windows (see #3159) thanks @eramdam!

  • Rework how components self-reference in extension scenarios (see #3236); should fix a bunch of subtle bugs around patterns like & + &

  • Fix keyframes not receiving a modified stylis instance when using something like stylis-plugin-rtl (see #3239)

  • Big performance gain for components using style objects (see #3239)

  • We no longer emit dynamic classNames for empty rulesets, so some className churn may occur in snapshots

  • Preallocate global style placement to ensure cGS is consistently inserted at the top of the stylesheet; note that this is done in runtime order so, if you have multiple cGS that have overlapping styles, ensure they're defined in code in the sequence you would want them injected (see #3239)

  • Add "engines" to package.json (currently set to Node 10, the oldest supported LTS distribution) (see #3201) thanks @MichaelDeBoey!

Finally, special thanks to @willheslam for testing and some last minute fixes on this release!

v5.2.0-test.10

We are planning to release 5.2 on September 2/3, please help us test!

yarn add styled-components@test
  • Preallocate global style placement to ensure cGS is consistently inserted at the top of the stylesheet; note that this is done in runtime order so, if you have multiple cGS that have overlapping styles, ensure they're defined in code in the sequence you would want them injected (see #3239)

    NOTE: This is a behavioral change and might require adjustment in your codebase if you have many createGlobalStyle components in use. We do not think it will affect the majority of projects other than fix existing bugs.

  • createGlobalStyle is now React.StrictMode compliant

  • Make sure StyleSheetManager renders all styles in iframe / child windows (see #3159) thanks @eramdam!

  • Rework how components self-reference in extension scenarios (see #3236); should fix a bunch of subtle bugs around patterns like & + &

  • Fix keyframes not receiving a modified stylis instance when using something like stylis-plugin-rtl (see #3239)

  • Big performance gain for components using style objects (see #3239)

  • We no longer emit dynamic classNames for empty rulesets, so some className churn may occur in snapshots

  • Add "engines" to package.json (currently set to Node 10, the oldest supported LTS distribution) (see #3201) thanks @MichaelDeBoey!