CSS-in-JS: Styled-components and Emotion
Write component styles as tagged template literals with styled-components or the css prop with Emotion, and use props for dynamic styles.
CSS-in-JS: Styled-components and Emotion is a free Frontend Academy lesson on CoddyKit — lesson 3 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Frontend Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
What Is CSS-in-JS?
CSS-in-JS writes component styles directly in JavaScript/TypeScript. Styles are co-located with components, support dynamic values from props, and are automatically scoped. The two most popular libraries are styled-components and Emotion.
Styled-components Basics
Use tagged template literals to define styled components. The result is a React component that renders an HTML element with the styles applied.
import styled from 'styled-components';
const Button = styled.button`
background: ${props => props.primary ? '#6366f1' : 'white'};
color: ${props => props.primary ? 'white' : '#6366f1'};
padding: 8px 16px;
border: 2px solid #6366f1;
border-radius: 4px;
cursor: pointer;
&:hover {
opacity: 0.9;
}
`;
<Button primary>Primary</Button>
<Button>Outline</Button>Emotion — css Prop
Emotion's css prop applies styles to any JSX element. Requires the @emotion/react pragma or the Babel preset.
/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react';
function Card({ featured }: { featured?: boolean }) {
return (
<div css={css`
padding: 16px;
border-radius: 8px;
border: ${featured ? '2px solid #6366f1' : '1px solid #e2e8f0'};
`}>
Content
</div>
);
}Dynamic Styles from Props
Both libraries can read props to compute styles. This is their primary advantage over static CSS — no class-switching needed.
Theming with ThemeProvider
Styled-components and Emotion both support a ThemeProvider that injects theme values into all styled components.
import { ThemeProvider } from 'styled-components';
const theme = { colors: { primary: '#6366f1', bg: '#f7fafc' }, space: { sm: 8, md: 16 } };
<ThemeProvider theme={theme}>
<App />
</ThemeProvider>
// Access in styled component:
const Card = styled.div`
background: ${props => props.theme.colors.bg};
padding: ${props => props.theme.space.md}px;
`;Extending Styled Components
Extend an existing styled component to create a variant without duplicating styles.
const Button = styled.button`
padding: 8px 16px;
border-radius: 4px;
`;
const DangerButton = styled(Button)`
background: #e53e3e;
color: white;
`;Global Styles
Use createGlobalStyle (styled-components) or Global (Emotion) for global CSS like body styles and resets.
import { createGlobalStyle } from 'styled-components';
const GlobalStyle = createGlobalStyle`
*, *::before, *::after { box-sizing: border-box; }
body { margin: 0; font-family: system-ui; }
`;
<><GlobalStyle /><App /></>Runtime Cost of CSS-in-JS
CSS-in-JS libraries inject styles at runtime via JavaScript. This adds CPU cost for parsing and style injection, plus JavaScript bundle size. Zero-runtime alternatives (vanilla-extract, linaria) generate static CSS at build time.
Zero-Runtime Alternatives
vanilla-extract: write styles in TypeScript, compiled to static CSS. linaria: CSS-in-JS syntax compiled to CSS Modules. Both give CSS-in-JS ergonomics without runtime overhead.
TypeScript with styled-components
Define a ThemeType and extend the DefaultTheme interface from styled-components for fully typed themes.
import 'styled-components';
import { theme } from './theme';
declare module 'styled-components' {
export interface DefaultTheme extends typeof theme {}
}When to Choose CSS-in-JS
CSS-in-JS is excellent for: dynamic styles driven by runtime JavaScript values, design systems with strong theming needs, teams that prefer JS-first workflows. The runtime cost is usually acceptable for non-performance-critical UIs.
Quick Check
What is the main trade-off of runtime CSS-in-JS libraries compared to static CSS solutions?
Recap: CSS-in-JS
Styled-components: tagged template literals, render a styled React element. Emotion: css prop or styled API. Dynamic styles from props eliminate class-switching. ThemeProvider injects theme values. createGlobalStyle for global CSS. Runtime cost is the main trade-off. Zero-runtime alternatives: vanilla-extract, linaria.
Frequently asked questions
Is the “CSS-in-JS: Styled-components and Emotion” lesson free?
Yes — the full text of “CSS-in-JS: Styled-components and Emotion” is free to read here on the web, and the Frontend Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Frontend Academy course, upgrade to CoddyKit PRO.
What will I learn in “CSS-in-JS: Styled-components and Emotion”?
Write component styles as tagged template literals with styled-components or the css prop with Emotion, and use props for dynamic styles. You practise Frontend Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Frontend Academy?
No prior experience is required. Frontend Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 3 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “CSS-in-JS: Styled-components and Emotion” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Frontend Academy lesson?
Yes. Every Frontend Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- BEM Methodology: Block Element Modifier
- CSS Modules: Scoped Class Names
- CSS-in-JS: Styled-components and Emotion
- Tailwind CSS Utility-First Approach