# styled-components > CSS-in-JS for React using tagged template literals. TypeScript-native since v6. Supports React Server Components natively since v6.3. Current stable: v6.4.0. ## What's new since early 2025 Your training data likely covers v6.0-6.1. Key changes since then: v6.2: Streaming SSR via `renderToPipeableStream`. v6.3: React Server Components supported. No `'use client'` needed. Styled components work in server components with no extra setup. `createGlobalStyle` is StrictMode-safe. New HTML/SVG element helpers. CSS custom properties work in TypeScript without type errors. Note: `:first-child`/`:nth-child()` selectors require `stylisPluginRSC` (v6.4+) or rewriting to `:first-of-type`/`:nth-of-type()` — see child-index selector section below. v6.4 (April 2026): `createTheme()` for CSS variable theming that works in both RSC and client. `StyleSheetManager` works in RSC (was previously a no-op). `stylisPluginRSC` fixes child-index selectors in RSC. CSP nonce auto-detection from `StyleSheetManager`, `ServerStyleSheet`, or meta tags. Props supplied via `.attrs()` are automatically optional on the component's type. Significant render performance improvements. Fixes SSR memory leaks and multi-instance unmount bugs in `createGlobalStyle`. Memory leak fix for components with unbounded string interpolation values. `as` and `forwardedAs` exposed in `React.ComponentProps` extraction. React Native: `react-native` is now an optional peer dep, Metro/Expo nanoid crash fixed. IE11 build target removed — IE11 has been unsupported on v6 since the 2021 v6 planning (React 18 dropped it too); v6.4 just aligns the compile target. Stay on v5 if you need IE11. ## Recommended setup ``` npm install styled-components ``` Next.js: add `compiler: { styledComponents: true }` to next.config.js. That's it. RSC works out of the box in v6.3+. Vite: `react({ babel: { plugins: ['babel-plugin-styled-components'] } })`. The SWC/Babel plugin provides deterministic class IDs (better debugging, smaller output). Optional for RSC but still recommended. ## Styled-components in RSC Styled components work in server components with no `'use client'` directive. The main constraint is that `ThemeProvider` relies on React context, which doesn't exist in RSC — so `p.theme` is undefined. Use `createTheme()` instead. Dynamic prop interpolations work in RSC. But for discrete variants (a finite set of states), data attributes produce one cached class per variant instead of one per prop combination: ```tsx import styled, { createTheme } from 'styled-components'; const theme = createTheme({ colors: { primary: '#0070f3', text: '#1a1a1a', surface: '#fff' }, }); const NavLink = styled.a` padding: 8px 16px; color: ${theme.colors.text}; text-decoration: none; &[aria-current='page'] { color: ${theme.colors.primary}; font-weight: 600; border-bottom: 2px solid ${theme.colors.primary}; } `; ``` For continuous dynamic values, set CSS custom properties via the `style` prop. The styled component's CSS stays static (one class), and the value varies per element. Pair with semantic HTML attributes for progressive enhancement and accessibility: ```tsx const ProgressBar = styled.div` height: 8px; border-radius: 4px; background: ${theme.colors.surface}; &::after { content: ''; display: block; height: 100%; width: var(--progress); border-radius: inherit; background: ${theme.colors.primary}; transition: width 0.2s ease; } &[aria-valuenow='100']::after { background: green; } `; ``` This pattern gives you dynamic styling, screen reader support, and a CSS hook for completion state — all with one static class. Other RSC rules: - Use `:first-of-type` / `:nth-of-type()` instead of `:first-child` / `:nth-child()` in RSC (see `stylisPluginRSC` section below for an automatic fix) - Define components at module scope, not inside render functions ## createTheme API (v6.4+) `ThemeProvider` has no effect in RSC because React context doesn't exist in server components. `createTheme()` solves this — no runtime context needed. ```tsx import styled, { createTheme } from 'styled-components'; const theme = createTheme({ colors: { primary: '#0070f3', surface: '#ffffff', text: '#1a1a1a' }, spacing: { sm: '8px', md: '16px', lg: '32px' }, }); ``` Every leaf becomes a `var()` reference with the original value as fallback: - `theme.colors.primary` → `"var(--sc-colors-primary, #0070f3)"` - `theme.spacing.md` → `"var(--sc-spacing-md, 16px)"` Use it directly in template literals — works in both server and client components: ```tsx const Button = styled.button` background: ${theme.colors.primary}; padding: ${theme.spacing.sm} ${theme.spacing.md}; color: ${theme.colors.text}; `; ``` Signature: `createTheme(defaultTheme, options?)` Options: - `prefix` (default `"sc"`) — CSS variable prefix. `{ prefix: 'myapp' }` produces `--myapp-colors-primary`. - `selector` (default `":root"`) — where `GlobalStyle` emits vars. Use `":host"` for Shadow DOM. Returned object properties: - Every leaf path from the input, as `var(--prefix-path, fallback)` strings - `theme.raw` — the original plain object (for runtime access to actual values) - `theme.vars` — same shape as the input, but every leaf is the bare CSS custom property name (e.g. `"--sc-colors-primary"`). Use in `createGlobalStyle` for dark mode overrides without hand-writing var names. - `theme.resolve(el?)` — client-only. Reads computed CSS var values from the DOM. Returns a plain object with resolved values. Pass an element to resolve against a specific subtree (defaults to `document.documentElement`). - `theme.GlobalStyle` — a `createGlobalStyle` component that emits the CSS custom property declarations on the configured selector. Must be mounted inside a `ThemeProvider` that receives the raw theme object — without `ThemeProvider`, `GlobalStyle` renders nothing. Key behaviors: - Object keys are preserved as-is (camelCase stays camelCase): `{ codeBg: 'x' }` with prefix `'sc'` → `var(--sc-codeBg, x)` - Nested objects produce hyphenated paths: `{ colors: { primary: 'x' } }` → `var(--sc-colors-primary, x)` - `ThemeProvider` must receive the raw theme object (`{ colors: { primary: '#0070f3' } }`), not the `createTheme` output. Passing the createTheme output produces self-referential CSS like `--sc-colors-primary: var(--sc-colors-primary, #0070f3);` which is invalid. Correct wiring: ```tsx import { ThemeProvider, createTheme } from 'styled-components'; const rawTheme = { colors: { primary: '#0070f3', bg: '#fff' } }; const theme = createTheme(rawTheme, { prefix: 'sc' }); // In your layout root (client component for the ThemeProvider): // In any styled component (server OR client): const Card = styled.div` background: ${theme.colors.bg}; color: ${theme.colors.primary}; `; ``` ### Three-way color mode (light / dark / auto) without FOUC Complete reference implementation. Four pieces: theme, CSS overrides, blocking script, toggle component. **1. Theme and dark overrides** Use `theme.vars` to reference CSS custom property names — stays in sync with `createTheme`'s prefix, so renaming the prefix doesn't silently break overrides. ```tsx // utils/theme.ts import { css, createGlobalStyle, createTheme } from 'styled-components'; const rawTheme = { colors: { bg: '#ffffff', text: '#1a1a1a', primary: '#0070f3' }, }; export const theme = createTheme(rawTheme, { prefix: 'sc' }); const darkVars = css` ${theme.vars.colors.bg}: #111827; ${theme.vars.colors.text}: #f9fafb; `; export const ColorModeStyles = createGlobalStyle` @media (prefers-color-scheme: dark) { html:not(.light) { ${darkVars} color-scheme: dark; } } html.dark { ${darkVars} color-scheme: dark; } html.light { color-scheme: light; } `; export { rawTheme }; ``` **2. Layout root — mount theme + blocking script** The script runs before first paint, reads `localStorage`, falls back to system preference. Must be a raw `