Styling in React can be done in several ways — from simple inline styles to advanced CSS Modules or CSS-in-JS solutions like styled-components. React gives you the flexibility to choose the method that best fits your project and team.
In this topic, you’ll learn how to style React components using:
? Goal: Build clean, maintainable, and scalable React UI styles.
style prop.Inline styles are defined as JavaScript objects and applied using the style attribute. This approach is ideal for dynamic styling based directly on component state or props.
// Toggle button styled with inline style objects
function InlineStyleExample() {
const [active, setActive] = React.useState(false);
const style = {
padding: "10px 20px",
color: "#fff",
backgroundColor: active ? "#28a745" : "#6c757d",
border: "none",
borderRadius: "5px",
cursor: "pointer"
};
return (
<button style={style} onClick={() => setActive(!active)}>
{active ? "Active" : "Inactive"}
</button>
);
}
The button style is stored in a JavaScript object called style. When active is true, the button has a green background; otherwise, it’s gray. Clicking the button toggles the state and updates its visual appearance.
Note that inline style properties use camelCase (e.g., backgroundColor) instead of kebab-case (background-color).
You can use regular CSS files and import them into your React components. This approach is familiar and works well for small to medium-sized projects.
// Button.css – reusable button styles
.button {
padding: 10px 15px;
border: none;
border-radius: 4px;
background-color: steelblue;
color: white;
cursor: pointer;
}
.button:hover {
background-color: dodgerblue;
}
// Button.js – importing and using the CSS class
import "./Button.css";
function Button() {
return <button className="button">Click Me</button>;
}
The .button class is defined in Button.css. In Button.js, you import the CSS file and use the class with className. The hover rule adds a simple interactive effect.
Styles defined in regular CSS files are global by default and may affect any element using the same class name throughout your app.
CSS Modules provide scoped and component-specific styles. Each class name is locally scoped to the component, preventing naming collisions in larger codebases.
// Card.module.css – styles scoped to the Card component
.card {
background: #f8f9fa;
border-radius: 8px;
padding: 15px;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}
// Card.js – importing styles as a module
import styles from "./Card.module.css";
function Card() {
return (
<div className={styles.card}>
<h4>CSS Module Example</h4>
<p>This card is styled using a scoped CSS module.</p>
</div>
);
}
The CSS file is named with the .module.css suffix. When you import it as styles, each class (like styles.card) becomes a unique, locally scoped class name in the rendered HTML.
This makes CSS Modules a great choice for large projects or when multiple developers work on the same codebase.
You can dynamically apply multiple classes using template literals or helper libraries like classnames. This is especially useful for toggling light/dark modes or active states.
// Dynamically swap classes based on the isDark state
function DynamicClasses() {
const [isDark, setIsDark] = React.useState(false);
return (
<div className={`p-3 text-center ${isDark ?
"bg-dark text-light" : "bg-light text-dark"}`}>
<p>Dynamic Styling Example</p>
<button
className="btn btn-outline-primary"
onClick={() => setIsDark(!isDark)}
>
Toggle Mode
</button>
</div>
);
}
The outer div switches between bg-dark text-light and bg-light text-dark based on the isDark state.
You can scale this pattern using utility classes (e.g., Tailwind) or by using the classnames package for cleaner conditional logic.
Styled-components let you write real CSS directly in JavaScript using tagged template literals. Styles are scoped to components and can respond to props, making them powerful for design systems.
// Styled button that changes style based on the primary prop
import styled from "styled-components";
const StyledButton = styled.button`
background-color: ${(props) => (props.primary ? "#007bff" : "#6c757d")};
color: white;
border: none;
padding: 10px 20px;
border-radius: 5px;
cursor: pointer;
&:hover {
opacity: 0.9;
}
`;
function StyledButtonExample() {
return (
<div>
<StyledButton primary>Primary</StyledButton>
<StyledButton className="ms-2">Default</StyledButton>
</div>
);
}
The StyledButton component is a styled version of a native <button>. The primary prop controls which background color it uses.
Styled-components also support themes, nesting, and composition, which makes them ideal for building reusable UI libraries.
Inline conditional styling changes styles on the fly based on data or user actions. This is handy for statuses, scores, alerts, and validation messages.
// Score color changes based on value thresholds
function ConditionalStyle() {
const [score, setScore] = React.useState(70);
const scoreStyle = {
color: score >= 75 ? "green" : score >= 50 ? "orange" : "red",
fontWeight: "bold"
};
return (
<div>
<h4>Score: <span style={scoreStyle}>{score}</span></h4>
<button
className="btn btn-info me-2"
onClick={() => setScore(score + 5)}
>
+
</button>
<button
className="btn btn-danger"
onClick={() => setScore(score - 5)}
>
-
</button>
</div>
);
}
The text color of the score changes based on its value: green for high scores, orange for average, and red for low.
This creates instant visual feedback for the user without needing complex class toggling.
Here’s a quick comparison of the main styling approaches in React:
| Method | Scope | Dynamic? | Typical Use Case |
|---|---|---|---|
| Inline Styles | Local to element | ✅ Yes | Dynamic visual updates |
| CSS Stylesheet | Global | ❌ Limited | Simple static designs |
| CSS Modules | Scoped to component | ✅ Yes | Component-level styling |
| Styled-components | Scoped to component | ✅ Yes | Reusable design systems |
variant prop.Goal: Understand when to use inline styles, global CSS, CSS Modules, and CSS-in-JS so you can choose the right approach for each React project.