DEV Community

Cover image for [07 | CSS 06] Mastering Styled Components: A Modern Approach to CSS in React
Anik Paul
Anik Paul

Posted on

[07 | CSS 06] Mastering Styled Components: A Modern Approach to CSS in React

1. Introduction to Styled Components

Styled Components is a popular CSS-in-JS library for React that enables you to write actual CSS inside your JavaScript. It leverages tagged template literals (a feature from ES6) to define scoped, reusable styles directly within your components.

This approach brings a number of modern benefits:

  • Scoped styles by default (no class name collisions)
  • Theming support via context
  • Dynamic styling using props
  • Eliminates global CSS problems
  • Cleaner code separation in React projects

Here’s a basic example:

import { styled } from 'styled-components';

const H1 = styled.h1`
  font-size: 30px;
  font-weight: 600;
  background-color: yellow;
`;

const Button = styled.button`
  font-size: 1.4rem;
  padding: 1.2rem 1.6rem;
  font-weight: 500;
  border: none;
  border-radius: 7px;
  background-color: purple;
  color: white;
  cursor: pointer;
  margin: 20px;
`;

function App() {
  return (
    <div>
      <H1>Hotel California</H1>
      <Button onClick={() => alert('Check in')}>Check in</Button>
      <Button onClick={() => alert('Check out')}>Check out</Button>
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

2. Installation (2025)

The latest version of Styled Components is fully compatible with React 18+ and modern bundlers like Vite, Webpack, and Next.js.

Install using npm or yarn:

npm install styled-components
Enter fullscreen mode Exit fullscreen mode

For TypeScript users, install the types:

npm install -D @types/styled-components
Enter fullscreen mode Exit fullscreen mode

Note: From v6 onward, styled-components provides both ESM and CJS builds. If you're using Vite or other ESM-first tools, it works natively.


3. Basic Usage and Syntax

3.1 Creating Styled Elements

You use styled.[element] followed by a template literal containing your CSS:

const Container = styled.div`
  padding: 20px;
  background-color: #f7f7f7;
`;

const Heading = styled.h1`
  font-size: 2rem;
  color: darkblue;
`;
Enter fullscreen mode Exit fullscreen mode

3.2 Using Styled Components in JSX

Use them just like normal React components:

<Container>
  <Heading>Styled Components are awesome</Heading>
</Container>
Enter fullscreen mode Exit fullscreen mode

The styles are automatically scoped and do not bleed into other components.


4. How Styled Components Work Behind the Scenes

Styled Components dynamically generates unique class names for each styled definition. These classes are injected into the DOM at runtime.

Example:

const H1 = styled.h1`
  font-weight: bold;
`;
Enter fullscreen mode Exit fullscreen mode

Generates:

<h1 class="sc-gTRQi iXbVjY">Styled Heading</h1>
<style>
  .sc-gTRQi.iXbVjY {
    font-weight: bold;
  }
</style>
Enter fullscreen mode Exit fullscreen mode

This guarantees:

  • No class name collisions
  • True component-level scoping
  • Automatic deduplication of styles

5. Developer Tooling and Extensions

5.1 VS Code Syntax Highlighting

To enable full syntax highlighting and formatting, install this VS Code extension:

  • Name: vscode-styled-components
  • Publisher: Julien Poissonnier
  • Benefit: Adds syntax highlighting inside template literals, linting, and IntelliSense

5.2 Prettier Support

If you use Prettier, it automatically formats styled components. Just make sure prettier-plugin-styled-components is not installed anymore — it's deprecated and no longer required.


6. Styling Existing Components

You can use styled() to style not only HTML elements, but also custom React components:

const BaseButton = ({ children, ...props }) => (
  <button {...props}>{children}</button>
);

const StyledButton = styled(BaseButton)`
  padding: 10px 16px;
  border-radius: 5px;
  background-color: teal;
  color: white;
`;
Enter fullscreen mode Exit fullscreen mode

You can also extend existing styled components:

const PrimaryButton = styled(Button)`
  background-color: green;
`;

const DangerButton = styled(Button)`
  background-color: crimson;
`;
Enter fullscreen mode Exit fullscreen mode

7. Recap: Core Concepts and Setup

  • What Styled Components are and how they work
  • Installation and compatibility (React 18+, Vite, Webpack)
  • Creating styled elements with tagged template literals
  • How styles are scoped and rendered
  • Styling React components and extending styles
  • Editor support and formatting

8. Dynamic Styling with Props

One of the most powerful features of Styled Components is that it supports JavaScript logic inside CSS, especially when driven by component props.

Example: Dynamic Color

const Button = styled.button`
  background-color: ${(props) => (props.primary ? 'blue' : 'gray')};
  color: white;
  padding: 1rem 1.4rem;
  border: none;
  border-radius: 5px;
  font-size: 1rem;
  cursor: pointer;
`;
Enter fullscreen mode Exit fullscreen mode

Usage:

<Button primary>Primary</Button>
<Button>Default</Button>
Enter fullscreen mode Exit fullscreen mode

The primary prop controls which style is applied. This is incredibly helpful when building a design system with reusable buttons, cards, badges, etc.


9. Theming with ThemeProvider

Styled Components offers built-in support for global themes using React Context under the hood.

Step 1: Define a Theme Object

// theme.js
export const theme = {
  colors: {
    primary: '#0070f3',
    secondary: '#facc15',
    text: '#333333',
    background: '#f7f7f7',
  },
  fonts: {
    heading: '"Poppins", sans-serif',
    body: '"Open Sans", sans-serif',
  },
};
Enter fullscreen mode Exit fullscreen mode

Step 2: Wrap Your App with ThemeProvider

// App.jsx
import { ThemeProvider } from 'styled-components';
import { theme } from './theme';
import Home from './Home';

function App() {
  return (
    <ThemeProvider theme={theme}>
      <Home />
    </ThemeProvider>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Step 3: Access Theme in Components

const Container = styled.div`
  background-color: ${(props) => props.theme.colors.background};
  color: ${(props) => props.theme.colors.text};
  font-family: ${(props) => props.theme.fonts.body};
`;
Enter fullscreen mode Exit fullscreen mode

This way, all components have theme access via props, and your design system becomes centralized and maintainable.


10. Global Styles

Styled Components allows you to write global CSS (e.g., resets, base styles) using the createGlobalStyle helper.

Step 1: Import the helper

import { createGlobalStyle } from 'styled-components';
Enter fullscreen mode Exit fullscreen mode

Step 2: Define Global Styles

const GlobalStyle = createGlobalStyle`
  * {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
  }

  body {
    font-family: ${(props) => props.theme.fonts.body};
    background-color: ${(props) => props.theme.colors.background};
    color: ${(props) => props.theme.colors.text};
    line-height: 1.6;
  }

  button {
    font-family: inherit;
  }
`;
Enter fullscreen mode Exit fullscreen mode

Step 3: Use in App

<ThemeProvider theme={theme}>
  <GlobalStyle />
  <App />
</ThemeProvider>
Enter fullscreen mode Exit fullscreen mode

You can also use multiple createGlobalStyle declarations for modularity (e.g., reset + base + typography).


11. CSS Helpers: css and keyframes

Styled Components offers powerful helpers for advanced styling use cases.


11.1 Reusable Styles with css

Use the css helper to define and reuse chunks of CSS:

import { css } from 'styled-components';

const buttonBase = css`
  padding: 0.8rem 1.2rem;
  font-size: 1rem;
  border-radius: 6px;
  border: none;
  cursor: pointer;
`;

const Button = styled.button`
  ${buttonBase}
  background-color: navy;
  color: white;
`;
Enter fullscreen mode Exit fullscreen mode

You can also conditionally inject different blocks:

const variant = css`
  background-color: green;
  color: white;
`;

const Button = styled.button`
  ${buttonBase}
  ${(props) => props.success && variant}
`;
Enter fullscreen mode Exit fullscreen mode

11.2 Animations with keyframes

import { keyframes } from 'styled-components';

const fadeIn = keyframes`
  from {
    opacity: 0;
    transform: translateY(5px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
`;

const Notification = styled.div`
  animation: ${fadeIn} 0.5s ease-out;
`;
Enter fullscreen mode Exit fullscreen mode

Use this for tooltips, modals, transitions, or any animation state.


12. Media Queries and Responsive Design

Styled Components supports regular CSS media queries inside template literals.

const Card = styled.div`
  padding: 2rem;

  @media (max-width: 768px) {
    padding: 1rem;
  }
`;
Enter fullscreen mode Exit fullscreen mode

To centralize breakpoints, you can define them in your theme:

// theme.js
export const theme = {
  breakpoints: {
    sm: '480px',
    md: '768px',
    lg: '1024px',
  },
};
Enter fullscreen mode Exit fullscreen mode

And use:

const Wrapper = styled.div`
  padding: 2rem;

  @media (max-width: ${(props) => props.theme.breakpoints.md}) {
    padding: 1rem;
  }
`;
Enter fullscreen mode Exit fullscreen mode

13. Recap: Dynamic Styling, Theming, and Helpers

  • Dynamically styling components using props
  • Building a global theme system using ThemeProvider
  • Applying global styles with createGlobalStyle
  • Writing reusable CSS blocks using css
  • Adding animations with keyframes
  • Responsive styles via media queries

14. Nesting and Selector Support

Styled Components allows you to write nested CSS just like in SCSS. You can nest child elements, pseudo-selectors, or class-based styles.

Example: Nested Elements and States

const Card = styled.div`
  padding: 2rem;
  background-color: white;
  border-radius: 10px;

  h2 {
    font-size: 1.5rem;
    margin-bottom: 1rem;
  }

  p {
    font-size: 1rem;
    color: #555;
  }

  &:hover {
    background-color: #f9f9f9;
  }
`;
Enter fullscreen mode Exit fullscreen mode

Styling Child Components via Class or Props

You can use attribute selectors if necessary:

const ListItem = styled.li`
  &[data-active='true'] {
    font-weight: bold;
    color: blue;
  }
`;
Enter fullscreen mode Exit fullscreen mode

15. Polymorphic Components with as Prop

Styled Components support the as prop, which allows a component to render a different HTML tag without changing its style.

const Text = styled.p`
  font-size: 1rem;
  color: #444;
`;

<Text>This is a paragraph</Text>
<Text as="span">This is a span</Text>
<Text as="h2">This is a heading</Text>
Enter fullscreen mode Exit fullscreen mode

This is helpful when reusing the same styles across different HTML elements (e.g., links vs buttons vs spans).


16. Composition Patterns

There are two ways to reuse and extend styled components.


16.1 Extend a Styled Component

const BaseButton = styled.button`
  padding: 1rem 1.5rem;
  font-size: 1rem;
`;

const PrimaryButton = styled(BaseButton)`
  background-color: royalblue;
  color: white;
`;
Enter fullscreen mode Exit fullscreen mode

16.2 Share CSS Blocks with css

import { css } from 'styled-components';

const cardBase = css`
  border-radius: 10px;
  padding: 2rem;
  box-shadow: 0 1px 6px rgba(0, 0, 0, 0.1);
`;

const Card = styled.div`
  ${cardBase}
  background-color: white;
`;

const Modal = styled.div`
  ${cardBase}
  background-color: #fffdf5;
`;
Enter fullscreen mode Exit fullscreen mode

17. Testing Styled Components

You can test styled components using tools like Jest and React Testing Library.


17.1 Unit Testing Components

import { render, screen } from '@testing-library/react';
import { ThemeProvider } from 'styled-components';
import { theme } from '../theme';
import Button from './Button';

test('renders styled button with correct text', () => {
  render(
    <ThemeProvider theme={theme}>
      <Button>Submit</Button>
    </ThemeProvider>
  );

  expect(screen.getByText('Submit')).toBeInTheDocument();
});
Enter fullscreen mode Exit fullscreen mode

You don’t need to test styles directly — just focus on behavior and output. You can use snapshot testing if needed.


18. Best Practices

Here are key strategies for writing clean, scalable styled components:


18.1 Structure Components Clearly

  • Name styled versions with a prefix like Styled, e.g. StyledContainer
  • Keep styled components near the component that uses them
  • Group common styles in a styles.js file per component when needed

18.2 Keep CSS Logic Minimal

Avoid overcomplicating styles with too much logic:

// OK
color: ${(props) => (props.active ? 'blue' : 'gray')};

// Avoid this
color: ${(props) =>
  props.active ? (props.theme.dark ? '#fff' : '#000') : props.disabled ? 'gray' : 'red'};
Enter fullscreen mode Exit fullscreen mode

Instead, compute values earlier or use utility functions.


18.3 Prefer css for Shared Styles

// Avoid duplication
const buttonStyles = css`
  padding: 1rem;
  border-radius: 5px;
`;

const Button = styled.button`
  ${buttonStyles}
  background-color: blue;
`;

const LinkButton = styled.a`
  ${buttonStyles}
  background-color: transparent;
`;
Enter fullscreen mode Exit fullscreen mode

18.4 Theming and Responsiveness

  • Always extract theme values instead of hardcoding colors or fonts
  • Use props.theme.breakpoints for responsive styles
  • Keep theme definitions in a centralized file

18.5 Keep createGlobalStyle Minimal

Only include base resets and typography in global styles. Avoid injecting component-specific styles globally.


19. Styled Components Reference Table

Feature Description
styled.[tag] Create styled HTML elements (div, h1, button, etc.)
styled(Component) Style existing React components
ThemeProvider Provide theme context globally
props Dynamically change styles with JS logic
createGlobalStyle Inject global CSS rules
css Reuse or compose chunks of CSS
keyframes Define animations
as prop Polymorphic rendering (e.g., button rendered as link)
@media queries Responsive styling
.extend, class nesting Extend and nest styles like SCSS

20. Final Thoughts

Styled Components brings the full power of CSS into your React component system — while solving key pain points like style leakage, naming conflicts, and theming.

Whether you're building small reusable UI kits or large-scale design systems, Styled Components enables:

  • Co-located styles and logic
  • Dynamic styling via props
  • Full JavaScript power in your CSS
  • Encapsulation and reusability by default

Adopting it takes a small learning curve, but once you embrace its model, you’ll likely never return to traditional CSS or even CSS Modules.


21. Frequently Asked Questions (FAQs)


Q: Is Styled Components still relevant in 2025?

A: Yes. Styled Components is actively maintained, compatible with React 18+, and widely used in both open-source and enterprise projects.


Q: What are alternatives to Styled Components?

A: Emotion, Linaria, Stitches, and even Tailwind (utility-first CSS) are viable alternatives. Choose based on your project needs.


Q: Will Styled Components slow down my app?

A: In most cases, no. Runtime injection is lightweight. However, if you're rendering large component trees or complex animations, consider static extraction via Babel plugin.


Q: Can I use Styled Components with Next.js?

A: Yes. Next.js supports Styled Components out of the box, but you’ll need to set up a custom _document.js with SSR support using ServerStyleSheet.


Q: Should I use Styled Components or Tailwind?

A: Both solve different problems. Tailwind emphasizes low-level utility composition, while Styled Components emphasizes encapsulated, component-scoped CSS. You can even use both together in hybrid setups.


📬 Let’s Connect
🌐 Portfolio: paulanik.com
💼 LinkedIn: Anik Paul
🐙 GitHub: anikpaul99
📩 Email: hello@paulanik.com

Top comments (0)