Introdução

Styled-components permite escrever CSS real dentro dos seus arquivos JavaScript, com escopo restrito a um componente específico. Os estilos viajam junto com o componente, eliminando colisões de nomes de classe e acabando com a necessidade de procurar um arquivo CSS separado quando algo parece errado. Se você já perdeu tempo depurando qual folha de estilos global está sobrescrevendo qual, a proposta é imediatamente atraente.

Por que Usar Styled-Components?

Escopo de Estilo

Os estilos são automaticamente limitados ao componente ao qual pertencem. Sem convenções de nomenclatura BEM, sem preocupações com a ordem de cascata entre arquivos.

Estilização Dinâmica

Você pode ramificar com base em props diretamente dentro do template literal. Alternar uma variante não exige mais manter classes CSS paralelas e lógica JavaScript separadas.

Manutenibilidade Aprimorada

Estilos e marcação vivem no mesmo arquivo. Quando um componente é deletado, seus estilos vão junto. Você não descobre CSS órfão um ano depois.

Prefixação de Vendor Automática

Styled-components aplica os prefixes de vendor automaticamente, então você escreve propriedades CSS padrão e ele cuida da compatibilidade entre navegadores.

Primeiros Passos com Styled-Components

Instalação

npm install styled-components

ou

yarn add styled-components

Uso Básico

Veja como criar um componente de botão estilizado:

import React from 'react';
import styled from 'styled-components';

const Button = styled.button`
  background-color: #6200ee;
  color: white;
  padding: 10px 15px;
  border: none;
  border-radius: 5px;
  cursor: pointer;
  
  &:hover {
    background-color: #3700b3;
  }
`;

const App = () => (
  <Button>Click Me</Button>
);

export default App;

styled.button retorna um componente React com o CSS aplicado. Você o usa como qualquer outro componente.

Estilização com Props

Styled-components permitem passar props para os elementos estilizados a fim de aplicar estilos condicionalmente.

const Button = styled.button`
  background-color: ${props => props.primary ? '#6200ee' : '#white'};
  color: ${props => props.primary ? 'white' : '#6200ee'};
  padding: 10px 15px;
  border: ${props => props.primary ? 'none' : '2px solid #6200ee'};
  border-radius: 5px;
  cursor: pointer;
  
  &:hover {
    background-color: ${props => props.primary ? '#3700b3' : '#f2e7fe'};
  }
`;

const App = () => (
  <>
    <Button primary>Primary Button</Button>
    <Button>Secondary Button</Button>
  </>
);

export default App;

Ao passar a prop primary, podemos alternar os estilos do botão de forma dinâmica.

Estendendo Styled Components

Você pode criar novos styled components estendendo os existentes:

const OutlineButton = styled(Button)`
  background-color: transparent;
  color: #6200ee;
  border: 2px solid #6200ee;
  
  &:hover {
    background-color: #f2e7fe;
  }
`;

OutlineButton herda tudo de Button e adiciona suas próprias sobreposições.

Temas com Styled-Components

Para design tokens consistentes em uma árvore de componentes grande, use ThemeProvider.

import { ThemeProvider } from 'styled-components';

const theme = {
  primary: '#6200ee',
  secondary: '#03dac6',
};

const Button = styled.button`
  background-color: ${props => props.theme.primary};
  color: white;
  padding: 10px 15px;
`;

const App = () => (
  <ThemeProvider theme={theme}>
    <Button>Themed Button</Button>
  </ThemeProvider>
);

Atualize o objeto de tema em um único lugar e todos os componentes que usam props.theme capturam a mudança.

Criando uma Aplicação de Exemplo Completa

Aqui está um app básico de tarefas que demonstra como essas peças se encaixam.

Configurando o Projeto

npx create-react-app styled-components-todo
cd styled-components-todo
npm install styled-components

Estruturando o App

Três componentes:

  • App: o componente principal e contêiner de estado.
  • TodoList: renderiza a lista de tarefas.
  • TodoForm: formulário para adicionar novas tarefas.

Componente App

// src/App.js
import React, { useState } from 'react';
import styled from 'styled-components';
import TodoForm from './TodoForm';
import TodoList from './TodoList';

const Container = styled.div`
  max-width: 500px;
  margin: 50px auto;
  padding: 20px;
  background-color: #f2e7fe;
  border-radius: 10px;
`;

const Title = styled.h1`
  text-align: center;
  color: #6200ee;
`;

const App = () => {
  const [todos, setTodos] = useState([]);

  const addTodo = text => {
    const newTodos = [...todos, { text }];
    setTodos(newTodos);
  };

  return (
    <Container>
      <Title>Styled Components To-Do App</Title>
      <TodoForm addTodo={addTodo} />
      <TodoList todos={todos} />
    </Container>
  );
};

export default App;

Componente TodoForm

// src/TodoForm.js
import React, { useState } from 'react';
import styled from 'styled-components';

const Form = styled.form`
  display: flex;
  margin-bottom: 20px;
`;

const Input = styled.input`
  flex: 1;
  padding: 10px;
  border: 2px solid #6200ee;
  border-radius: 5px;
  margin-right: 10px;
  font-size: 16px;
`;

const Button = styled.button`
  background-color: #6200ee;
  color: white;
  padding: 0 20px;
  border: none;
  border-radius: 5px;
  font-size: 16px;
  cursor: pointer;
  
  &:hover {
    background-color: #3700b3;
  }
`;

const TodoForm = ({ addTodo }) => {
  const [value, setValue] = useState('');

  const handleSubmit = event => {
    event.preventDefault();
    if (!value) return;
    addTodo(value);
    setValue('');
  };

  return (
    <Form onSubmit={handleSubmit}>
      <Input
        type="text"
        placeholder="Add a new task"
        value={value}
        onChange={e => setValue(e.target.value)}
      />
      <Button type="submit">Add</Button>
    </Form>
  );
};

export default TodoForm;

Componente TodoList

// src/TodoList.js
import React from 'react';
import styled from 'styled-components';

const List = styled.ul`
  list-style: none;
  padding-left: 0;
`;

const ListItem = styled.li`
  background-color: white;
  padding: 15px 20px;
  border-bottom: 1px solid #ddd;
  
  &:nth-child(even) {
    background-color: #fafafa;
  }
`;

const TodoList = ({ todos }) => (
  <List>
    {todos.map((todo, index) => (
      <ListItem key={index}>{todo.text}</ListItem>
    ))}
  </List>
);

export default TodoList;

Executando a Aplicação

npm start

Navegue até http://localhost:3000 para interagir com seu app de tarefas estilizado.

Conclusão

Styled-components é uma escolha prática quando você quer que estilos e componentes permaneçam sincronizados. CSS com escopo significa sem sobrescritas inesperadas, estilização baseada em props substitui a lógica de classes condicionais, e temas mantêm os design tokens consistentes sem variáveis CSS espalhadas por vários arquivos.

A contrapartida é o tamanho do bundle e o custo de runtime adicional para gerar nomes de classe. Para a maioria das aplicações React essa troca vale a pena, mas é válido fazer benchmarks se você estiver trabalhando em um contexto sensível à performance.

Dicas Adicionais

  • Use createGlobalStyle para resets de base e importações de fontes que devem se aplicar ao documento inteiro.
  • Ao adicionar styled-components a um projeto existente, migre um componente por vez em vez de fazer uma reescrita completa.
  • O plugin Babel do styled-components melhora a legibilidade dos nomes de classe no DevTools e vale a pena adicionar a qualquer projeto não trivial.

Leitura Adicional