styled-components

    styled-components/styled-components

    #32 this week

    Fast, expressive styling for React. Server components, client components, streaming SSR, React Native—one API.

    frontend
    css
    css-in-js
    react
    reactnative
    rsc
    TypeScript
    MIT
    41.1K stars
    2.6K forks
    41.1K GitHub watchers
    Updated 7/31/2026
    View on GitHub

    Backblaze Generative Media Hackathon

    Build the next generation of AI media apps with Genblaze, stored on Backblaze B2. $10,000 in prizes.

    Enter the hackathon

    Loading star history...

    Use Cases & Benefits

    • Provides a unified API for styling React components using real CSS with automatic scoping and no build step.
    • Enables seamless styling across React server components, client components, streaming SSR, and React Native with full TypeScript support.
    • Use for building type-safe, themeable React web apps with dynamic and reusable styled components.
    • Use for creating consistent, token-driven design systems with theming and CSS custom properties in React Server Components.
    • Use for styling React Native apps with the same API and features as web React, including animations and global styles.

    About styled-components


    Fast, expressive styling for React.
    Server components, client components, streaming SSR, React Native: one API.

    npm downloads gzip size

    styled-components is largely maintained by one person. Please help fund the project for consistent long-term support and updates: Open Collective


    Style React components with real CSS, scoped automatically and delivered only when needed. No class name juggling, no separate files, no build step required.

    • Works everywhere React runs. Server components, client components, streaming SSR, and React Native: same API, automatic runtime detection.
    • Full CSS, no compromises. Media queries, pseudo-selectors, nesting, keyframes, global styles. If CSS supports it, so does styled-components.
    • TypeScript-first. Built-in types ship with the package. Props flow through to your styles with full inference: no @types install, no manual generics.
    • <13kB gzipped. Small enough to disappear in your bundle. No build plugin required.

    Install

    npm install styled-components
    
    pnpm / yarn
    pnpm add styled-components
    
    yarn add styled-components
    

    Quick examples

    Dynamic props

    Vary styles based on component props. Prefix transient props with $ to keep them off the DOM.

    import styled from 'styled-components';
    
    const Button = styled.button<{ $primary?: boolean }>`
      background: ${props => (props.$primary ? 'palevioletred' : 'white')};
      color: ${props => (props.$primary ? 'white' : 'palevioletred')};
      font-size: 1em;
      padding: 0.25em 1em;
      border: 2px solid palevioletred;
      border-radius: 3px;
    `;
    
    <Button>Normal</Button>
    <Button $primary>Primary</Button>
    

    Extending styles

    Build variants on top of existing styled components.

    const TomatoButton = styled(Button)`
      background: tomato;
      color: white;
      border-color: tomato;
    `;
    

    Polymorphic as prop

    Swap the rendered element without changing styles.

    // Renders a <a> tag with Button styles
    <Button as="a" href="/home">
      Link Button
    </Button>
    

    Pseudos and nesting

    Use & to reference the component's generated class name; works with pseudo-classes, pseudo-elements, and nested selectors.

    const Input = styled.input`
      border: 1px solid #ccc;
      border-radius: 4px;
      padding: 0.5em;
    
      &:focus {
        border-color: palevioletred;
        outline: none;
      }
    
      &::placeholder {
        color: #aaa;
      }
    `;
    

    Animations

    Define @keyframes once, reference them across components. Names are scoped automatically.

    import styled, { keyframes } from 'styled-components';
    
    const rotate = keyframes`
      from { transform: rotate(0deg); }
      to { transform: rotate(360deg); }
    `;
    
    const Spinner = styled.div`
      animation: ${rotate} 1s linear infinite;
      width: 40px;
      height: 40px;
      border: 3px solid palevioletred;
      border-top-color: transparent;
      border-radius: 50%;
    `;
    

    Theming

    Share design tokens across your app via React context. Every styled component receives props.theme.

    import styled, { ThemeProvider } from 'styled-components';
    
    const theme = {
      fg: 'palevioletred',
      bg: 'white',
    };
    
    const Card = styled.div`
      background: ${props => props.theme.bg};
      color: ${props => props.theme.fg};
      padding: 2em;
    `;
    
    <ThemeProvider theme={theme}>
      <Card>Themed content</Card>
    </ThemeProvider>;
    

    RSC-compatible themes

    createTheme turns your tokens into CSS custom properties. Class name hashes stay stable across theme variants, so there's no hydration mismatch when switching light/dark.

    import styled, { createTheme, ThemeProvider } from 'styled-components';
    
    const { theme, GlobalStyle: ThemeVars } = createTheme({
      colors: {
        fg: 'palevioletred',
        bg: 'white',
      },
      space: {
        md: '1rem',
      },
    });
    
    const Card = styled.div`
      color: ${theme.colors.fg}; /* var(--sc-colors-fg, palevioletred) */
      background: ${theme.colors.bg};
      padding: ${theme.space.md};
    `;
    
    // Render <ThemeVars /> at the root to emit the CSS variable declarations
    // Pass the theme to ThemeProvider for stable hashes
    <ThemeProvider theme={theme}>
      <ThemeVars />
      <Card>Token-driven content</Card>
    </ThemeProvider>;
    

    Tokens are placeholder references that resolve at render time, not raw values. Interpolate them anywhere a CSS value goes; don't combine them with JS arithmetic. For runtime composition use calc(), or reach for theme.raw.space.md when you genuinely need the original number in JS.

    // works
    padding: ${theme.space.md};
    margin: ${theme.space.sm} ${theme.space.md};
    top: calc(${insets.top}px + ${theme.space.md});
    
    // breaks: JS `+` produces a malformed string the browser drops
    top: ${insets.top + theme.space.md};
    

    See the createTheme API docs for the full composition rules.

    Shared styles with css

    Extract reusable style blocks to share across components or apply conditionally.

    import styled, { css } from 'styled-components';
    
    const truncate = css`
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    `;
    
    const Label = styled.span`
      ${truncate}
      max-width: 200px;
    `;
    

    Styling third-party components

    Wrap any component that accepts a className prop.

    import styled from 'styled-components';
    import { Link } from 'react-router-dom';
    
    const StyledLink = styled(Link)`
      color: palevioletred;
      text-decoration: none;
    
      &:hover {
        text-decoration: underline;
      }
    `;
    

    Global styles

    Inject app-wide CSS like resets and font faces. Supports theming and dynamic updates.

    import { createGlobalStyle } from 'styled-components';
    
    const GlobalStyle = createGlobalStyle`
      body {
        margin: 0;
        font-family: system-ui, sans-serif;
      }
    `;
    
    // Render <GlobalStyle /> at the root of your app
    

    Attrs

    Set default or static HTML attributes so consumers don't have to.

    const PasswordInput = styled.input.attrs({
      type: 'password',
      placeholder: 'Enter password',
    })`
      border: 1px solid #ccc;
      padding: 0.5em;
    `;
    

    The function form receives a second ast argument for bridging declarations or theme tokens into props on third-party components. peek reads a value; pop reads and removes it from the rendered style. Both accept either a CSS property name or a typed dot-separated theme path:

    import { Path } from 'react-native-svg';
    
    const Icon = styled(Path).attrs((_props, ast) => ({
      fill: ast.pop('color'), // lift the CSS color decl
      stroke: ast.peek('palette.brand'), // read from theme via typed path
    }))`
      color: red;
    `;
    

    Both methods take an optional fallback as the second argument, returned when the value is missing. The lift happens at construction time when the callback's behavior is fully determined by static declarations, so renders pay nothing extra.

    Documentation

    Community

    Contributing guidelines | Code of Conduct | awesome-styled-components

    Contributors

    This project exists thanks to all the people who contribute.

    Backers

    Thank you to all our backers! [Become a backer]

    Sponsors

    Support this project by becoming a sponsor. [Become a sponsor]

    Acknowledgements

    This project builds on earlier work by Charlie Somerville, Nik Graf, Sunil Pai, Michael Chan, Andrey Popp, Jed Watson, and Andrey Sitnik. Special thanks to @okonet for the logo.

    License

    Licensed under the MIT License, Copyright © 2016-present styled-components contributors. See LICENSE for details.

    Discover Repositories

    Search across tracked repositories by name or description