Style Application
a) CSS Modules:
CSS Modules allow you to write CSS that’s scoped to a specific component, preventing style conflicts across your application.
How to use CSS Modules:
- Create a CSS file with a
.module.css
extension, e.g.,Button.module.css
- Import the styles in your component file
- Use the imported styles as an object
Example:
Button.module.css:
.button { background-color: blue; color: white; padding: 10px 20px; border: none; border-radius: 5px;}
Button.js:
import React from "react";import styles from "./Button.module.css";
function Button({ children }) { return <button className={styles.button}>{children}</button>;}
export default Button;
Key benefits:
- Locally scoped class names
- Reusable styles
- Compatibility with existing CSS workflows
b) styled-components:
styled-components is a CSS-in-JS library that allows you to write actual CSS code to style your components.
How to use styled-components:
- Install the library:
npm install styled-components
- Import styled-components in your component file
- Create styled components using the styled object
Example:
import React from "react";import styled from "styled-components";
const StyledButton = styled.button` background-color: blue; color: white; padding: 10px 20px; border: none; border-radius: 5px;`;
function Button({ children }) { return <StyledButton>{children}</StyledButton>;}
export default Button;
Key benefits:
- No class name bugs
- Easier deletion of CSS
- Dynamic styling based on props
- Apply basic styling to your components
Let’s apply some basic styling to a simple Todo application using both CSS Modules and styled-components.
Using CSS Modules:
TodoApp.module.css:
.container { max-width: 500px; margin: 0 auto; padding: 20px; font-family: Arial, sans-serif;}
.input { width: 100%; padding: 10px; margin-bottom: 10px;}
.button { background-color: #4caf50; color: white; padding: 10px 20px; border: none; cursor: pointer;}
.list { list-style-type: none; padding: 0;}
.item { background-color: #f1f1f1; margin: 5px 0; padding: 10px; display: flex; align-items: center;}
.checkbox { margin-right: 10px;}
TodoApp.js:
import React, { useState } from "react";import styles from "./TodoApp.module.css";
function TodoApp() { const [todos, setTodos] = useState([]); const [input, setInput] = useState("");
const addTodo = (e) => { e.preventDefault(); if (input) { setTodos([...todos, { id: Date.now(), text: input, completed: false }]); setInput(""); } };
const toggleTodo = (id) => { setTodos( todos.map((todo) => todo.id === id ? { ...todo, completed: !todo.completed } : todo, ), ); };
return ( <div className={styles.container}> <form onSubmit={addTodo}> <input className={styles.input} value={input} onChange={(e) => setInput(e.target.value)} placeholder="Add a todo" /> <button className={styles.button} type="submit"> Add </button> </form> <ul className={styles.list}> {todos.map((todo) => ( <li key={todo.id} className={styles.item}> <input type="checkbox" className={styles.checkbox} checked={todo.completed} onChange={() => toggleTodo(todo.id)} /> <span style={{ textDecoration: todo.completed ? "line-through" : "none", }} > {todo.text} </span> </li> ))} </ul> </div> );}
export default TodoApp;
Using styled-components:
import React, { useState } from "react";import styled from "styled-components";
const Container = styled.div` max-width: 500px; margin: 0 auto; padding: 20px; font-family: Arial, sans-serif;`;
const Input = styled.input` width: 100%; padding: 10px; margin-bottom: 10px;`;
const Button = styled.button` background-color: #4caf50; color: white; padding: 10px 20px; border: none; cursor: pointer;`;
const List = styled.ul` list-style-type: none; padding: 0;`;
const Item = styled.li` background-color: #f1f1f1; margin: 5px 0; padding: 10px; display: flex; align-items: center;`;
const Checkbox = styled.input` margin-right: 10px;`;
function TodoApp() { const [todos, setTodos] = useState([]); const [input, setInput] = useState("");
const addTodo = (e) => { e.preventDefault(); if (input) { setTodos([...todos, { id: Date.now(), text: input, completed: false }]); setInput(""); } };
const toggleTodo = (id) => { setTodos( todos.map((todo) => todo.id === id ? { ...todo, completed: !todo.completed } : todo, ), ); };
return ( <Container> <form onSubmit={addTodo}> <Input value={input} onChange={(e) => setInput(e.target.value)} placeholder="Add a todo" /> <Button type="submit">Add</Button> </form> <List> {todos.map((todo) => ( <Item key={todo.id}> <Checkbox type="checkbox" checked={todo.completed} onChange={() => toggleTodo(todo.id)} /> <span style={{ textDecoration: todo.completed ? "line-through" : "none", }} > {todo.text} </span> </Item> ))} </List> </Container> );}
export default TodoApp;
Both these examples achieve similar styling, but with different approaches. CSS Modules keep your CSS separate from your JavaScript, while styled-components allow you to write your styles directly in your component files.
The choice between CSS Modules and styled-components often comes down to personal or team preference, as well as the specific needs of your project.