Skip to content

Releases: styled-components/styled-components

styled-components@7.0.0-prerelease-20260808041113

Choose a tag to compare

styled-components@6.5.1

Choose a tag to compare

@quantizor quantizor released this 07 Aug 14:07
ff15a53

Patch Changes

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

styled-components@7.0.0-prerelease-20260807223715

Choose a tag to compare

Minor Changes

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

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

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

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

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

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

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

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

Patch Changes

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

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

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

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

Full Changelog: styled-components@7.0.0-prerelease-20260806233720...styled-components@7.0.0-prerelease-20260807223715

styled-components@7.0.0-prerelease-20260806233720

Choose a tag to compare

@github-actions github-actions released this 06 Aug 23:39
ef8178b

Minor Changes

  • Cut the TypeScript cost of using styled components in an app. A render target's props are resolved once per target instead of once per JSX call site, which is where most of the work was going. Against a fixture of 100 styled components the type count drops to roughly a sixth and peak memory to roughly a quarter, putting v7 slightly under v6 on both. (consumer-type-check-cost.md)

  • A declared style type now constrains the fields it names and leaves the rest of CSS accepted, instead of replacing the target's style outright. Wrap the declaration in the new CustomStyle export to forbid everything it omits rather than writing never for every property by hand. The constraint holds through as and forwardedAs. (declared-style-merges.md)

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

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

Patch Changes

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

Full Changelog: styled-components@7.0.0-prerelease-20260731041038...styled-components@7.0.0-prerelease-20260806233720

styled-components@6.5.1-prerelease-20260806232123

Choose a tag to compare

@github-actions github-actions released this 06 Aug 23:22
a0a92cd

Patch Changes

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

Full Changelog: styled-components@6.5.0...styled-components@6.5.1-prerelease-20260806232123

styled-components@6.5.0

Choose a tag to compare

@quantizor quantizor released this 04 Aug 15:27
ef5142a

Minor Changes

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

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

    Web components are unaffected and still accept custom properties.

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

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

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

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

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

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

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

Patch Changes

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

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

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

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

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

styled-components@6.5.0-prerelease-20260804151232

Choose a tag to compare

@github-actions github-actions released this 04 Aug 15:13
dfe4baf

Minor Changes

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

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

    Web components are unaffected and still accept custom properties.

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

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

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

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

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

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

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

Patch Changes

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

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

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

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

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

Full Changelog: styled-components@6.4.4...styled-components@6.5.0-prerelease-20260804151232

styled-components@7.0.0-prerelease-20260731041038

Choose a tag to compare

styled-components@7.0.0-prerelease-20260731035917

Choose a tag to compare

@github-actions github-actions released this 31 Jul 04:02
5431a8b

Minor Changes

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

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

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

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

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

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

Full Changelog: styled-components@7.0.0-prerelease-20260731032118...styled-components@7.0.0-prerelease-20260731035917

styled-components@7.0.0-prerelease-20260731032118

Choose a tag to compare

@github-actions github-actions released this 31 Jul 03:24
5af42ec