Skip to main content

Breaking changes in React package 3.0

@yleisradio/yds-components-react 3.0 drops styled-components, ships styles as CSS Modules, and applies color themes (and other design tokens) through CSS custom properties instead of React context.

Component props are unchanged. What breaks is theming, bundler setup, and anything that read the old theme object. Behaviorally and visually components themselves are virtually unchanged besides some small bugs that were found in re-implementation phase.

TL;DR migration plan​

The app bundler must process *.module.css from this package (including under node_modules). Confirm YDS tokens are still on the application root as CSS custom properties — they were required in 2.x as well; file lists: Get started. If styled-components was only a YDS peer, you can remove it.

If the app keeps styled-components as its own styling library, convert props.theme.yds reads with Using styled-components with YDS 3.0. That work can land on 2.x first: defaultTheme and the token CSS already ship in @yleisradio/yds-core 2.x.

At a glance​

2.x3.0
styled-components is a peer dependencyNot a peer. YDS does not render a styled-components ThemeProvider
YdsThemeProvider put tokens on React context (props.theme.yds)Theme tokens are used as CSS custom properties. YdsThemeProvider now pushes CSS variables in a <style> block targeting a wrapper.
YdsThemeProvider theme defaulted to 'light'theme defaults to 'default' (follows prefers-color-scheme)
unit / baseUnit converted px/rem sizes at runtimeProps removed. Component CSS uses rem at 1rem = 16px baseline
A root provider themed the whole app, including portalsImport token CSS onto :root. The provider themes only its subtree
Styles were styled-components output (unlayered)Unprocessed .module.css in @layer yds. The app bundler must process them
yds-core defaultShadow held literal light box-shadow stringsdefaultShadow holds var(--yds-shadow-*, <light fallback>)

Styled-components is no longer a peer​

YDS does not depend on styled-components. You can keep it in the app, or drop it if it was only there for YDS.

2.x rendered styled-components' ThemeProvider inside YdsThemeProvider and replaced the theme with { ydsThemeName, yds, ydsThemeProps }. 3.0 renders no such provider:

  • props.theme.yds, props.theme.ydsThemeName, and props.theme.ydsThemeProps are gone.
  • If YdsThemeProvider was the only styled-components provider in the tree, props.theme is now {} and every props.theme.* read breaks, not only the YDS ones. Render your own <ThemeProvider> if the app still needs one.
  • If your provider sat outside YdsThemeProvider, 2.x was shadowing it inside that subtree. Those keys become visible again.

The packaged styled-components DefaultTheme augmentation is gone. If the app keeps its own styled.d.ts with yds / ydsThemeName / ydsThemeProps, those reads still type-check and fail at runtime. Delete the YDS fields before upgrading.

If the app keeps styled-components, convert theme.yds usage with Using styled-components with YDS 3.0.

YdsThemeProvider themes a subtree, not the document​

YDS component styles now uses design tokens as CSS custom properties. yds-core tokens belong on application root as CSS. File lists: Get started. YdsThemeProvider is an alternative for a subtree or a React-driven theme. It does not write to :root unless you pass scope=":root" as a transitional step.

theme now defaults to 'default', which follows prefers-color-scheme. Pass theme="light" to keep 2.x behavior.

Tokens inherit through the DOM. Content you portal out of the subtree does not get them. Apply useThemeContext().className to the portal container, or put tokens on :root.

unit and baseUnit are removed​

Component CSS uses rem on a 1rem = 16px baseline. There is no runtime conversion. Make sure your :root font size is not a fixed/percentage-based value for accessibility.

If you used ydsThemeUnit for font sizing, it's still exported. 2.x read unit / baseUnit from props.theme.ydsThemeProps. Pass the values yourself, or delete the call: a 2.x provider defaulted to rem at 16px, which is what 3.0 already emits.

caution

ydsThemeUnit(value) defaults to 'px', not to the 'rem' the 2.x provider defaulted to. Pass 'rem' explicitly or remove the helper.

If the app used unit="px" or a custom baseUnit, convert once in PostCSS (postcss-rem-to-pixel, postcss-pxtorem) instead of at every call site.

Bundler must process CSS Modules from this package​

Styles ship as unprocessed *.module.css next to the compiled JavaScript, with "sideEffects": ["*.css"] so they are not tree-shaken away. The app bundler has to compile those files including under node_modules. Token files from @yleisradio/yds-core must stay global CSS (not hashed).

An optional bundled all.css with stable class names exists for CDN and prototypes without React. Importing it together with the React components duplicates styles: the components still use hashed CSS Module names. Class grammar: CSS class naming conventions.

Global resets beat @layer yds​

Library styles live in @layer yds. Layer order is resolved before specificity, so an unlayered * { margin: 0; padding: 0 } strips padding and margins from every component.

Put the reset in a layer below yds, and declare @layer reset, yds, app; in the first stylesheet the app loads — before any component CSS is imported:

@layer reset, yds, app;

@layer reset {
*,
*::before,
*::after {
box-sizing: border-box;
}

* {
margin: 0;
padding: 0;
}
}

box-sizing: border-box on * is what YDS is built against; leave it. It is margin: 0 and padding: 0 that collide.

If the reset cannot be layered (a host page, a shared bundle), unwrap @layer yds in the app build. Apps that inject the reset through styled-components' createGlobalStyle have extra constraints: Using styled-components with YDS 3.0 — Global CSS resets.

defaultShadow follows the active theme​

In @yleisradio/yds-core, defaultShadow now exports var(--yds-shadow-*, <light value>) references, matching defaultTheme. Shadows read through it follow the document theme instead of staying light.

The literal fallback keeps CSS usage rendering when the shadow token CSS is absent. Values read outside a CSS context (string comparison, canvas, native APIs) no longer resolve to a finished box-shadow. Use lightShadow to pin the previous literals.

What does not change​

  • Public component props.
  • Component visual identity and functionality.
  • JS token imports from @yleisradio/yds-core: spacing, radius, typography, border, transition, color, and the theme objects. Interpolating spacing.SPACING_16 into styled-components is still valid.
  • ydsThemeUnit remains exported (although you probably shouldn't need it).
  • You do not have to leave styled-components. It is just no longer required by YDS.