Skip to content

Migrating to V4

Ruo Ling edited this page Mar 11, 2026 · 54 revisions

What's new in V4?

We have moved away from Styled Component (CSS-in-JS) to Linaria (build-time), which improves compatibility with projects that rely on SSR or strict CSP.

Migrating from V3

If your project uses V3, follow these steps to install V4.

Changes

General

<TOC>

Components

<TOC>


Extracting design tokens

  • Show example for Colour and useDesignToken

Border

  • Removed Border.Util

Breakpoint

  • Show example with useMediaQuery and useDesignToken

DSThemeProvider

  • Removed and replaced with ThemeProvider

ErrorDisplay

  • Replace usage of ErrorDisplay.ImagePathAttributes with ErrorDisplayImagePathAttributes

MediaQuery

  • Order of media query now matters

ThemeProvider

  • Replaces styled-components ThemeProvider
  • Usage instructions
    • Wrap your application, typically in the root such as your NextJS layout.tsx
    • Specify theme
    • Import the corresponding css stylesheet

ThemeSpec object

  • Removed
  • No mixing and matching of schemes
  • Use a custom stylesheet or adhoc customisation instead

Customisation

What changes in V4

In V3, ad hoc theming was typically done by modifying the styled-components theme object (for example by injecting a modified colourScheme into token helpers).

In V4, ThemeProvider only accepts theme and mode. Theme extension for ad hoc customisation is done through CSS variable overrides using useApplyStyle.

In V4, you can style a scoped theme container directly:

  1. Use the V4 ThemeProvider to define the scope
  2. Get its themeElement from useTheme()
  3. Apply ad hoc CSS variables with useApplyStyle

Extending theme presets: V3 vs V4

In V3, you can construct a custom ThemeSpec and set overrides.

import { LifeSGTheme, ThemeSpec } from "@lifesg/react-design-system/theme";
import { ThemeProvider } from "styled-components";
import { Component } from "./index";

const customTheme: ThemeSpec = {
    ...LifeSGTheme,
    overrides: {
        primitiveColour: {
            "primary-10": "#F3C85C",
        },
        font: {
            "heading-size-xxl": "4rem",
            "heading-lh-xxl": "4.5rem",
            "heading-ls-xxl": "0.056rem",
        },
    },
};

const App = () => {
    return (
        <ThemeProvider theme={myCustomTheme}>
            <Component />
        </ThemeProvider>
    );
};

export default App;

In V4, there is no ThemeSpec / overrides API in ThemeProvider. For ad hoc customisation, scope your overrides to the provider element:

  1. Wrap scope with V4 ThemeProvider
  2. Read themeElement from useTheme()
  3. Apply CSS variable overrides with useApplyStyle
import styled, { css } from "styled-components";
import { V3_Colour } from "@lifesg/react-design-system/V3_theme";

const Card = styled.div`
    ${(props) => {
        const modifiedProps = {
            ...props,
            theme: {
                ...props.theme,
                colourScheme: "bookingsg",
            },
        };

        return css`
            background: ${V3_Colour["bg-primary"](modifiedProps)};
            color: ${V3_Colour["text-inverse"](modifiedProps)};
        `;
    }}
`;

Element-level styling migration

In V3 advanced usage, element-level customisation was done by constructing modifiedProps and calling token helpers with that temporary theme.

In v4, apply styles directly to the target element ref:

import { useRef } from "react";
import { useApplyStyle } from "@lifesg/react-design-system/theme/utils";

const SomeComponent = () => {
    const targetRef = useRef<HTMLDivElement>(null);

    useApplyStyle(targetRef, {
        "--fds-colour-bg-primary": "#0043ce",
        "--fds-colour-text-inverse": "#ffffff",
    });

    return <TargetComponent ref={targetRef}>Custom target</TargetComponent>;
};

Clone this wiki locally