Skip to content
All essays
WebFebruary 1, 202412 min

CSS-in-JS Deep Dive: Styled Components vs Emotion

Comprehensive comparison of CSS-in-JS solutions with performance analysis and best practices

Ü
Ümit Uz
Mobile & Full Stack Developer

CSS-in-JS has transformed how we style React applications. Let's explore the two most popular solutions.

What is CSS-in-JS?

CSS-in-JS uses JavaScript to style components, offering:

  • Scoped styles by default
  • Dynamic styling with props
  • Theme support
  • Critical CSS extraction
  • No class name conflicts

Styled Components

Installation

bash
npm install styled-components

Basic Usage

javascript
import styled from 'styled-components';

const Button = styled.button`
  background: ${props => props.primary ? '#0066cc' : '#ffffff'};
  color: ${props => props.primary ? '#ffffff' : '#0066cc'};
  padding: 12px 24px;
  border-radius: 4px;
  border: 2px solid #0066cc;
  cursor: pointer;
`;

// Usage
<Button primary>Click me</Button>

Advanced Features

Theming

javascript
import { ThemeProvider } from 'styled-components';

const theme = {
  colors: {
    primary: '#0066cc',
    secondary: '#6c757d'
  }
};

<ThemeProvider theme={theme}>
  <App />
</ThemeProvider>

Adapting based on props

javascript
const Button = styled.button`
  font-size: ${props => `
    ${props.small ? '12px' : props.large ? '18px' : '14px'}
  `};
`;

Global Styles

javascript
import { createGlobalStyle } from 'styled-components';

const GlobalStyle = createGlobalStyle`
  body {
    margin: 0;
    font-family: -apple-system, sans-serif;
  }
`;

Emotion

Installation

bash
npm install @emotion/react @emotion/styled

Basic Usage

javascript
import styled from '@emotion/styled';

const Button = styled.button`
  background: ${props => props.primary ? '#0066cc' : '#ffffff'};
  color: ${props => props.primary ? '#ffffff' : '#0066cc'};
  padding: 12px 24px;
  border-radius: 4px;
  border: 2px solid #0066cc;
  cursor: pointer;
`;

CSS Prop

Emotion's unique feature:

jsx
/** @jsxImportSource @emotion/react */

<div css={`
  background: #0066cc;
  color: white;
  padding: 12px;
`}>
  Styled div
</div>

Performance Comparison

Bundle Size

  • Styled Components: ~13KB gzipped
  • Emotion: ~3KB gzipped

Winner: Emotion 🏆

Runtime Performance

Both libraries generate unique class names, but:

  • Styled Components: Uses components, slightly slower
  • Emotion: Uses babel plugin, faster at runtime

Winner: Emotion 🏆

Developer Experience

  • Styled Components: More intuitive API, better documentation
  • Emotion: More flexible, CSS prop is powerful

Tie 🤝

When to Use Each

Choose Styled Components when:

  • Building a design system
  • Want excellent documentation
  • Prefer component-based API
  • Need consistent theming

Choose Emotion when:

  • Bundle size is critical
  • Need maximum flexibility
  • Want the CSS prop
  • Building performance-critical apps

Best Practices

1. Use Theme Prop

javascript
const Button = styled.button`
  background: ${props => props.theme.colors.primary};
`;

2. Avoid Inline Styles in Components

javascript
// Bad
const Badge = styled.span`
  top: ${props => props.position.top}px;
  left: ${props => props.position.left}px;
`;

// Good
const Badge = styled.span`
  position: absolute;
  top: ${props => props.top}px;
  left: ${props => props.left}px;
`;

3. Extract Reusable Styles

javascript
import { css } from 'styled-components';

const flexCenter = css`
  display: flex;
  justify-content: center;
  align-items: center;
`;

const Container = styled.div`
  ${flexCenter}
  height: 100vh;
`;

4. Use TypeScript

typescript
import styled from 'styled-components';

interface ButtonProps {
  primary?: boolean;
  size?: 'small' | 'medium' | 'large';
}

const Button = styled.button<ButtonProps>`
  // Types are now available
`;

SSR Setup

Styled Components

javascript
import { ServerStyleSheet } from 'styled-components';

app.get('*', (req, res) => {
  const sheet = new ServerStyleSheet();
  const html = ReactDOMServer.renderToString(
    sheet.collectStyles(<App />)
  );
  const styles = sheet.getStyleTags();

  res.send(`
    <!DOCTYPE html>
    <html>
      <head>${styles}</head>
      <body>${html}</body>
    </html>
  `);
});

Emotion

javascript
import { renderStylesToString } from '@emotion/server';

const html = ReactDOMServer.renderToString(<App />);
const styles = renderStylesToString(html);

res.send(`
  <!DOCTYPE html>
  <html>
    <head>${styles}</head>
    <body>${html}</body>
  </html>
`);

Migration Tips

From CSS Modules

  1. 1Start with new components
  2. 2Migrate one component at a time
  3. 3Use styled-components/macros for performance
  4. 4Set up theme provider early

From Plain CSS

  1. 1Create styled component for each element
  2. 2Copy CSS rules into template literal
  3. 3Convert dynamic values to props
  4. 4Extract theme values

Conclusion

Both Styled Components and Emotion are excellent choices. Pick based on your priorities: use Styled Components for DX and ecosystem, or Emotion for performance and flexibility. Either way, CSS-in-JS will improve your styling workflow.

Related essays

Next essay
Frontend Build Optimization: Vite vs Webpack