github styled-components/styled-components styled-components@7.0.0-prerelease-20260519035351

latest release: styled-components@6.4.2
pre-release13 hours ago

Minor Changes

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

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

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

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

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

  • React Native now supports CSS custom properties through the component cascade. (native-css-var-warn.md)

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

    Spec compliance touches:

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

    The rn-web bundle leaves both the declarations and var() references in place so the browser's own cascade handles them. Development builds warn on a var() reference only when no ancestor declared the property and no fallback was provided.

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

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

    • Font-width / font-stretch keywords (condensed, expanded, etc.) drop because React Native does not control glyph width.
    • System font names (caption, icon, menu, message-box, small-caption, status-bar) drop because the per-platform meaning has no cross-platform mapping; pick a font-family explicitly.
  • Expanded the React Native CSS surface with four polyfills that previously dropped silently or warned: (native-font-line-height-caret-line-width.md)

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

    translate: x y z no longer drops the Z value on React Native; the three-argument translate(x, y, z) form passes through unchanged on iOS and Android.

    The transform-style: preserve-3d development warning is more accurate: animated 3D transforms are already isolated automatically by the animation adapter, and the warn no longer suggests a manual collapsable={false} workaround for static decls (it has no effect on iOS without a perspective surface).

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

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

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

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

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

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

    const Row = styled.View`
      background: white;
      &:nth-child(2n + 1 of [data-active]) {
        background: silver;
      }
    `;
  • CSS overscroll-behavior and scrollbar-width now work on React Native. Apply them to a styled.ScrollView, styled.FlatList, styled.SectionList, or styled.VirtualizedList: (native-scroll-surfaces.md)

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

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

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

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

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

Patch Changes

  • The arity-2 .attrs((props, ast) => ...) callback now sees ast as a non-optional CompiledAst, so authors no longer need to optional-chain to satisfy the TypeScript compiler under strict: true. The arity-1 form (.attrs((props) => ...)) is unchanged. (attrs-ast-required-in-arity-2.md)

  • A css\``fragment placed after a declaration that was missing its trailing;` is now treated as a sibling block instead of being silently swallowed into the prior value. (fragment-missing-semicolon-recovery.md)

    Before, this composition would render with broken styles because the ${...} fragment was absorbed into the margin value:

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

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

  • Fixed native parsing of comma-separated animation-composition so each value pairs with the matching animation-name entry when you run multiple animations, instead of treating the whole declaration as a single invalid keyword. (native-animation-composition-longhand.md)

  • Fixes border line styles on React Native: hidden acts like no border, repeated sides collapse without noise, mixed sides keep the first drawable style with a development warning, and unsupported keywords such as double are ignored instead of rendering as the wrong border. Web builds keep CSS border styles as authored. (native-border-line-styles.md)

  • Slash-separated border-radius values that are still circular (for example 10px / 10px) now render on native. Truly elliptical combinations are ignored with a development warning instead of painting incorrect corners. Web builds keep the authored value. (native-border-radius-elliptical.md)

  • Fixes React Native spec-compliance edge cases in the flex shorthand. flex: initial and a zero basis after grow and shrink factors now match CSS behavior, while invalid negative grow, shrink, and basis values are ignored. (native-flex-shorthand.md)

  • letter-spacing now accepts the full CSS length grammar on React Native. Absolute lengths (pt, pc, in, cm, mm, Q) fold to dp at compile time. Font-relative units (em, rem, lh, rlh plus the font-metric forms ex, cap, ch, ic and their r-variants), viewport units, and container-query units resolve at render time against the current environment. Numbers, px, and normal continue to work; truly unsupported units still drop with a development warning. (native-letter-spacing-font-relative.md)

  • object-fit on a styled Image now applies correctly across iOS, Android, and the web. Previously the value reached the underlying Image differently on each target, leaving the web bar without the requested fit. (native-object-fit-rnweb.md)

  • Fixes React Native spec-compliance edge cases in the place-content shorthand. start, end, and space-evenly now match CSS Box Alignment behavior. (native-place-content.md)

  • React Native: when you opt into the Reanimated animation adapter, authored CSS animations and keyframes now run on the UI thread as intended instead of being ignored. Reduced motion collapses CSS-layer durations and delays to zero, and @starting-style entry transitions coordinate a two-frame paint so transitions can start from the declared starting snapshot. (reanimated-css-keyframes.md)

  • On react-native-web, parallel animations that use additive composition (add or accumulate) now pass animation-composition through to the browser so layered effects compose per CSS Animations Level 2. When every effect uses the default replace composition, the cascade is unchanged. (rn-web-animation-composition-style.md)

Full Changelog: styled-components@7.0.0-prerelease-20260513173704...styled-components@7.0.0-prerelease-20260519035351

Don't miss a new styled-components release

NewReleases is sending notifications on new releases.