A styling approach where CSS is written directly in JavaScript files instead of separate .css or .scss files.
- The styles are scoped to components by default.
- They can be dynamic, depending on props or state.
- Libraries generate CSS at runtime or build time, then inject it into
<style>tags in the DOM.
Why use CSS-in-JS in React?
- Scoped styles → Avoids class name collisions.
- Dynamic styling → Easily change styles based on props/state.
- Co-location → Styles live next to the component logic.
- Theming → Share theme variables across components.
- SSR-friendly (with proper setup).
Uses tagged template literals to define styled elements. Styles are attached to React components.
import styled from 'styled-components';
const Button = styled.button`
background: ${(props) => (props.primary ? 'blue' : 'gray')};
color: white;
padding: 10px;
`;
export default function App() {
return <Button primary>Click</Button>;
}Pros:
- Clean, readable syntax.
- Dynamic styles with props.
- Built-in theming. Cons:
- Runtime cost unless using a Babel plugin.
Define styles as JavaScript objects. Used in Emotion, JSS, or Material-UI.
import { css } from '@emotion/react';
const buttonStyle = css({
background: 'blue',
color: 'white',
padding: '10px',
});
export default function App() {
return <button css={buttonStyle}>Click</button>;
}Pros:
- Easy to use JavaScript logic for computed values.
- IDE autocomplete for CSS properties. Cons:
- Syntax is less like normal CSS.
- Can be verbose for complex styles.
Directly pass a style object to the style prop.
function App() {
return (
<button style={{ backgroundColor: 'blue', color: 'white' }}>Click</button>
);
}Pros:
- No setup required.
- Good for quick prototypes. Cons:
- No pseudo-classes (:hover) or media queries.
- Limited to what the style attribute supports.
Use JS functions to generate style objects dynamically.
const getButtonStyle = (primary) => ({
background: primary ? 'blue' : 'gray',
color: 'white',
});
function App() {
return <button style={getButtonStyle(true)}>Click</button>;
}Pros:
- Highly dynamic.
- Reusable logic. Cons:
- Still limited like inline styles.
- No real CSS syntax.
Combine CSS-in-JS with a ThemeProvider.
import { ThemeProvider } from 'styled-components';
const theme = {
colors: { primary: 'blue', secondary: 'gray' },
};
function App() {
return (
<ThemeProvider theme={theme}>
<Button primary>Click</Button>
</ThemeProvider>
);
}Pros:
- Centralized design tokens.
- Easy to switch themes (dark mode, branding).
| Pattern | Library Examples | Dynamic Styles | Pseudo-classes | Theming Support | Performance |
|---|---|---|---|---|---|
| Styled Components | styled-components, Emotion | ✅ | ✅ | ✅ | Medium |
| Object Styles | Emotion, JSS, Material-UI | ✅ | ✅ | ✅ | Medium |
| Inline Styles | Built-in React | ✅ | ❌ | ❌ | High |
| Utility Functions | Custom | ✅ | ❌ | ❌ | High |
-
"What are the pros and cons of CSS-in-JS compared to CSS Modules?" → CSS-in-JS offers dynamic styles and theming but adds runtime overhead, while CSS Modules compile to static CSS with better performance.
-
"How does CSS-in-JS affect performance?" → It injects styles at runtime, which can increase initial render time. Build-time extraction (Babel plugin, Linaria) can mitigate this.
-
"How do you do SSR with CSS-in-JS?" → Use the library’s SSR API (e.g., ServerStyleSheet in styled-components) to collect styles on the server and inject them into HTML.