1. Introduction
In modern React development, styling is no longer limited to simple CSS files. Developers now rely on powerful libraries that combine the flexibility of JavaScript with the structure of CSS. Among these libraries, Emotion stands out as one of the most versatile and high-performance CSS-in-JS solutions available for React.
Emotion enables developers to write CSS directly inside JavaScript or TypeScript files, supporting both string and object syntax. It offers a perfect balance between developer convenience and runtime efficiency. Unlike other libraries, Emotion focuses on flexibility, performance, and compatibility with existing React setups.
This post explores how Emotion works, why it’s considered more flexible than alternatives like Styled Components, and how it empowers developers to create dynamic, theme-based designs with ease.
2. What Is Emotion?
Emotion is a CSS-in-JS library designed for styling React applications. It allows you to write CSS styles within JavaScript, generating unique class names and injecting styles dynamically into the DOM.
At its core, Emotion combines three key principles:
- Dynamic styling using JavaScript expressions.
- Scoped CSS classes to prevent style conflicts.
- High performance through static extraction and optimized runtime.
Emotion provides two main APIs:
- The
@emotion/reactpackage for writing styles using thecssprop or thecssfunction. - The
@emotion/styledpackage for creating styled components similar to the Styled Components library.
Together, these APIs make Emotion both flexible and powerful, allowing you to style React components any way you prefer.
3. Why Emotion Was Created
Before Emotion, developers used libraries like Styled Components or plain CSS Modules to manage scoped styles. While these worked well, they had limitations:
- Performance bottlenecks due to runtime style generation.
- Limited flexibility when mixing static and dynamic styles.
- Complex integration with TypeScript and server-side rendering.
Emotion was created to address these challenges. Its goal was to deliver high performance, smaller bundles, better developer experience, and flexibility in how styles are written and organized.
By providing both object-based and string-based syntax, Emotion allows teams to choose the style that fits their workflow, whether that’s traditional CSS syntax or JavaScript-driven styling logic.
4. Key Features of Emotion
Emotion offers several important features that make it a leading choice for React developers:
- Scoped and Predictable Styles: Emotion automatically generates unique class names, ensuring no CSS conflicts.
- High Performance: It can statically extract and optimize styles at build time, improving runtime speed.
- Dynamic Styling: Developers can conditionally apply styles using props, states, or themes.
- Comprehensive Theming Support: Emotion integrates seamlessly with theme providers.
- Flexible Syntax: It supports both CSS strings and JavaScript objects.
- Server-Side Rendering Support: Perfect for frameworks like Next.js.
- TypeScript Compatibility: Offers complete type safety for large-scale projects.
5. Installing and Setting Up Emotion in React
To get started with Emotion, install the required packages using npm or yarn.
npm install @emotion/react @emotion/styled
If you’re using TypeScript, install the types as well:
npm install --save-dev @types/react
Once installed, you can start styling components using either of Emotion’s two main approaches: styled components or the css prop.
6. The Two Primary Ways to Style with Emotion
Emotion provides two equally powerful APIs:
A. The styled API
This is similar to how Styled Components works. You create styled React components using a template literal.
import styled from '@emotion/styled';
const Button = styled.button`
background-color: #007bff;
color: white;
padding: 10px 20px;
border-radius: 5px;
`;
function App() {
return <Button>Click Me</Button>;
}
B. The css Prop and css Function
This approach lets you apply styles directly via the css prop or by defining styles separately using the css function.
/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react';
const style = css`
color: white;
background: #007bff;
padding: 10px;
border-radius: 5px;
`;
function App() {
return <div css={style}>Emotion Example</div>;
}
Both methods generate scoped styles that Emotion injects into the document head at runtime.
7. Understanding Scoped Styles in Emotion
One of Emotion’s most powerful features is that styles are scoped automatically. When you use Emotion, it creates unique class names for each styled component.
For example, when you define this:
const Card = styled.div`
background: white;
border-radius: 8px;
`;
Emotion generates something like this in the DOM:
<div class="css-1a2b3c">...</div>
This ensures no global CSS collisions, even if multiple components use similar property names. Every style belongs to its respective component, which improves maintainability in large projects.
8. Combining Static and Dynamic Styles
Emotion allows you to combine static styles (fixed CSS rules) with dynamic ones (computed at runtime based on props).
Example:
const Button = styled.button`
background: ${props => (props.primary ? 'blue' : 'gray')};
color: white;
padding: 10px;
`;
When you render:
<Button primary>Primary</Button>
<Button>Secondary</Button>
Emotion dynamically applies the appropriate background color at runtime. This feature is one of the reasons Emotion is known for flexibility and reusability.
9. The css Function and Composable Styles
The css function in Emotion enables composition, meaning you can reuse and combine style definitions.
Example:
import { css } from '@emotion/react';
const baseStyle = css`
padding: 10px;
border-radius: 5px;
`;
const primary = css`
background: blue;
color: white;
`;
function Button() {
return <button css={[baseStyle, primary]}>Click</button>;
}
Emotion merges both style objects into one final CSS class. This makes your styles modular and composable — a major advantage over other CSS-in-JS libraries.
10. Theming in Emotion
Emotion provides a ThemeProvider component that makes theme values available to all styled components in your app.
import { ThemeProvider } from '@emotion/react';
const theme = {
colors: {
primary: '#007bff',
secondary: '#6c757d',
},
};
<ThemeProvider theme={theme}>
<App />
</ThemeProvider>
Inside any styled component, you can access the theme using a function:
const Button = styled.button`
background: ${props => props.theme.colors.primary};
color: white;
`;
This allows you to centralize all colors, typography, and spacing values in one place — perfect for light/dark modes or multi-brand designs.
11. Object-Based Styling in Emotion
In addition to the string-based syntax, Emotion supports object-based styling, which is especially useful for conditional logic.
import { css } from '@emotion/react';
const dynamicStyle = isActive => css({
backgroundColor: isActive ? 'green' : 'gray',
padding: '10px',
borderRadius: '4px'
});
This syntax integrates perfectly with JavaScript and TypeScript because styles are written as objects instead of strings. It’s a great choice when you need to compute or toggle styles based on props or application state.
12. Comparing Emotion with Styled Components
Emotion and Styled Components are often seen as competitors, but they share many similarities. Both use the concept of CSS-in-JS and template literals. However, Emotion is more flexible and lightweight.
| Feature | Emotion | Styled Components |
|---|---|---|
| Syntax Options | String + Object | Only String |
| Performance | Slightly faster | Slight runtime cost |
| Bundle Size | Smaller | Larger |
| Theming | Built-in | Built-in |
| TypeScript Support | Strong | Good |
| Composition | Easier with css() | Limited |
| SSR Support | Excellent | Excellent |
Emotion’s dual API (object and string) makes it adaptable to different coding styles and team preferences, giving it an edge in flexibility.
13. Conditional and Responsive Styling
Emotion supports conditional styles using standard JavaScript expressions. You can even handle media queries inline.
const Box = styled.div`
background: lightgray;
${props => props.primary && background: blue;}
@media (max-width: 600px) {
background: red;
}
`;
This ability to mix conditional logic with responsive design makes Emotion perfect for modern adaptive interfaces.
14. Reusing and Extending Styles
Emotion allows components to inherit or extend styles from others easily.
const BaseButton = styled.button`
padding: 10px;
border-radius: 4px;
`;
const PrimaryButton = styled(BaseButton)`
background: blue;
color: white;
`;
This pattern ensures reusability, consistency, and maintainability across your entire React codebase.
15. Using Emotion with TypeScript
Emotion provides built-in type definitions for its APIs. For example, when defining themes, you can declare their types to ensure full IDE support.
import { Theme, ThemeProvider } from '@emotion/react';
const theme: Theme = {
colors: {
primary: '#007bff',
},
};
TypeScript integration ensures that developers catch theme or prop-related errors at compile time, making large applications more stable.
16. Server-Side Rendering (SSR) with Emotion
Emotion integrates seamlessly with frameworks like Next.js. It supports server-side rendering, which ensures that styled components render their styles before the HTML is sent to the browser.
This means no flash of unstyled content (FOUC), and your application’s CSS is immediately available to the client. Emotion provides utilities such as extractCritical to handle SSR efficiently.
17. Performance and Optimization
Emotion is built with performance in mind. Some of its optimization features include:
- Static extraction: Emotion extracts static styles at build time.
- Runtime caching: Emotion caches styles to avoid regenerating them.
- Minimized CSS injection: Styles are injected once and reused.
- Tree-shaking support: Unused styles are removed during bundling.
These features make Emotion one of the fastest CSS-in-JS libraries in the React ecosystem.
18. Integrating Emotion with Other Libraries
Emotion can work alongside Tailwind CSS, Material UI, or even plain CSS Modules. For example, Material UI’s v5 styling system is powered by Emotion internally.
This compatibility makes Emotion a natural choice for projects that use hybrid styling approaches or want to customize existing component libraries.
19. Real-World Example: Themed Button Component
Below is a complete example of a theme-enabled button using Emotion.
import styled from '@emotion/styled';
import { ThemeProvider } from '@emotion/react';
const theme = {
colors: {
primary: '#007bff',
secondary: '#6c757d',
},
};
const Button = styled.button`
background: ${props => props.theme.colors.primary};
color: white;
padding: 10px 15px;
border: none;
border-radius: 4px;
`;
function App() {
return (
<ThemeProvider theme={theme}>
<Button>Emotion Button</Button>
</ThemeProvider>
);
}
This example shows how easy it is to apply consistent, reusable styling across components using Emotion’s theming system.
20. Advantages of Using Emotion
- Performance-optimized CSS-in-JS solution.
- Lightweight bundle size compared to alternatives.
- Dual syntax support (string and object).
- Strong TypeScript and SSR support.
- Dynamic styling capabilities with props and conditions.
- Theme support for consistent design systems.
- Excellent developer experience with auto-completion and debugging tools.
21. Limitations of Emotion
While Emotion is powerful, there are a few limitations to consider:
- Slight runtime overhead when generating dynamic styles.
- Complex configuration for projects that mix multiple styling methods.
- Requires build setup for optimal performance extraction.
- May be overkill for very small applications.
However, in most production React projects, the benefits far outweigh these drawbacks.
22. When to Use Emotion
Emotion is ideal for:
- Large-scale applications that need modular, dynamic styling.
- Design systems requiring consistent theming.
- Next.js or Remix projects that need SSR-friendly styling.
- TypeScript-based codebases needing type-safe CSS.
- Teams that want maximum flexibility between CSS and JS styling approaches.
23. Common Best Practices
- Use composition (
cssfunction) to avoid duplication. - Define themes globally for shared color and typography systems.
- Avoid excessive dynamic styles for performance reasons.
- Organize styles logically (e.g., folders for components, themes, and utilities).
- Leverage Emotion’s caching by avoiding inline functions in large loops.
- Document your design tokens for consistent usage across the team.
Leave a Reply