Skip to main content

React Emotion

Introduction

Emotion is a popular CSS-in-JS library that allows you to write CSS styles with JavaScript. It provides a flexible and powerful way to style your React components with dynamic capabilities. Emotion combines the best parts of inline styles, styled components, and traditional CSS to create a styling solution that works seamlessly with React's component model.

In this guide, you'll learn how to use Emotion in your React applications and explore its key features that make styling React components more maintainable and powerful.

Installation

To get started with Emotion in your React project, you'll need to install a couple of packages:

bash
# Using npm
npm install @emotion/react @emotion/styled

# Using yarn
yarn add @emotion/react @emotion/styled

Basic Usage with the css Prop

One of the simplest ways to use Emotion is with the css prop. However, to use the css prop, you'll need to add the JSX Pragma at the top of your file or configure Babel.

Let's see how to use the css prop with the JSX Pragma:

jsx
/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react';

function Button({ children }) {
return (
<button
css={css`
background-color: #4CAF50;
border: none;
color: white;
padding: 10px 20px;
text-align: center;
font-size: 16px;
cursor: pointer;
border-radius: 4px;
transition: background-color 0.3s;

&:hover {
background-color: #45a049;
}
`}
>
{children}
</button>
);
}

export default Button;

This creates a styled button component with hover effects. The css prop accepts a tagged template literal with CSS syntax. You can use nested selectors (like &:hover) similar to SCSS.

Using Object Styles

If you prefer to write your styles as JavaScript objects, Emotion supports that too:

jsx
/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react';

function Card({ title, content }) {
return (
<div
css={css({
padding: '20px',
backgroundColor: 'white',
borderRadius: '8px',
boxShadow: '0 2px 4px rgba(0, 0, 0, 0.1)',
margin: '16px 0'
})}
>
<h2
css={css({
fontSize: '18px',
color: '#333',
marginBottom: '10px'
})}
>
{title}
</h2>
<p
css={css({
fontSize: '14px',
color: '#666'
})}
>
{content}
</p>
</div>
);
}

export default Card;

Styled Components with Emotion

Emotion provides a styled API similar to styled-components. This allows you to create reusable styled components:

jsx
import styled from '@emotion/styled';

// Create a styled button
const Button = styled.button`
background-color: ${props => props.primary ? '#4CAF50' : '#f0f0f0'};
color: ${props => props.primary ? 'white' : 'black'};
padding: 10px 20px;
border: none;
border-radius: 4px;
font-size: 16px;
cursor: pointer;
transition: all 0.3s ease;

&:hover {
background-color: ${props => props.primary ? '#45a049' : '#e0e0e0'};
transform: translateY(-2px);
}
`;

// Usage
function App() {
return (
<div>
<Button primary>Primary Button</Button>
<Button>Secondary Button</Button>
</div>
);
}

The styled API creates components with styles attached to them. The styles can access props (like primary in the example) to conditionally apply styling.

Dynamic Styling with Props

One of the most powerful features of Emotion is the ability to style components dynamically based on props:

jsx
import styled from '@emotion/styled';

const Box = styled.div`
padding: ${props => props.padding || '10px'};
margin: ${props => props.margin || '0'};
background-color: ${props => props.bgColor || '#fff'};
border: ${props => props.border || 'none'};
border-radius: ${props => props.rounded ? '8px' : '0'};
box-shadow: ${props => props.shadow ? '0 2px 4px rgba(0,0,0,0.1)' : 'none'};
width: ${props => props.width || 'auto'};
max-width: ${props => props.maxWidth || 'none'};
`;

// Usage
function App() {
return (
<div>
<Box padding="20px" bgColor="#f5f5f5" rounded shadow>
This is a box with custom styling!
</Box>

<Box padding="10px" border="1px solid #ddd" margin="20px 0">
Another box with different styling.
</Box>
</div>
);
}

Global Styles

Sometimes you need to apply global styles to your application. Emotion provides the Global component for this purpose:

jsx
import { Global, css } from '@emotion/react';

function GlobalStyles() {
return (
<Global
styles={css`
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}

body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica,
Arial, sans-serif;
font-size: 16px;
line-height: 1.5;
color: #333;
background-color: #f9f9f9;
}

a {
color: #0077cc;
text-decoration: none;

&:hover {
text-decoration: underline;
}
}
`}
/>
);
}

// Use in your top-level App component
function App() {
return (
<>
<GlobalStyles />
{/* Your app content */}
</>
);
}

Theming with Emotion

Emotion integrates with React's Context API to provide theming capabilities:

jsx
import { ThemeProvider } from '@emotion/react';
import styled from '@emotion/styled';

// Define your theme
const theme = {
colors: {
primary: '#0070f3',
secondary: '#1a2a5e',
success: '#0070f3',
error: '#ff0000',
background: '#ffffff',
text: '#333333'
},
fonts: {
body: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
heading: 'Georgia, serif'
},
fontSizes: {
small: '14px',
medium: '16px',
large: '18px',
xlarge: '24px',
xxlarge: '32px'
},
spacing: {
small: '8px',
medium: '16px',
large: '24px',
xlarge: '32px'
}
};

// Create a themed button
const ThemedButton = styled.button`
background-color: ${props => props.theme.colors.primary};
color: white;
font-family: ${props => props.theme.fonts.body};
font-size: ${props => props.theme.fontSizes.medium};
padding: ${props => props.theme.spacing.small} ${props => props.theme.spacing.medium};
border: none;
border-radius: 4px;
cursor: pointer;

&:hover {
background-color: ${props => props.theme.colors.secondary};
}
`;

// Applying the theme
function App() {
return (
<ThemeProvider theme={theme}>
<div>
<h1>Themed Components</h1>
<ThemedButton>Themed Button</ThemedButton>
</div>
</ThemeProvider>
);
}

Composition and Reuse

Emotion makes it easy to compose and reuse styles:

jsx
/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react';

// Reusable styles
const flexCenter = css`
display: flex;
justify-content: center;
align-items: center;
`;

const card = css`
padding: 20px;
background-color: white;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
`;

function ProfileCard({ name, role, children }) {
return (
<div
css={css`
${card}
width: 300px;
margin: 20px auto;
`}
>
<div
css={css`
${flexCenter}
flex-direction: column;
`}
>
<h2>{name}</h2>
<p>{role}</p>
{children}
</div>
</div>
);
}

function App() {
return (
<ProfileCard name="Jane Doe" role="Developer">
<button
css={css`
margin-top: 10px;
padding: 8px 16px;
background-color: #0077cc;
color: white;
border: none;
border-radius: 4px;
`}
>
Contact Me
</button>
</ProfileCard>
);
}

Real-world Example: A Theme Switcher

Let's create a practical example that demonstrates how to build a theme switcher with Emotion:

jsx
/** @jsxImportSource @emotion/react */
import React, { useState, useContext } from 'react';
import { css, ThemeProvider, Global } from '@emotion/react';
import styled from '@emotion/styled';

// Define themes
const themes = {
light: {
name: 'light',
colors: {
background: '#ffffff',
text: '#333333',
primary: '#0070f3',
secondary: '#f5f5f5',
border: '#dddddd'
}
},
dark: {
name: 'dark',
colors: {
background: '#121212',
text: '#e0e0e0',
primary: '#4da6ff',
secondary: '#2d2d2d',
border: '#444444'
}
}
};

// Create ThemeContext
const ThemeContext = React.createContext({
theme: themes.light,
toggleTheme: () => {}
});

// Button component
const Button = styled.button`
background-color: ${props => props.theme.colors.primary};
color: ${props => props.theme.name === 'dark' ? '#ffffff' : '#ffffff'};
padding: 10px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
margin: 5px;
transition: background-color 0.3s ease;

&:hover {
opacity: 0.9;
}
`;

// Card component
const Card = styled.div`
background-color: ${props => props.theme.colors.secondary};
color: ${props => props.theme.colors.text};
padding: 20px;
border-radius: 8px;
border: 1px solid ${props => props.theme.colors.border};
margin: 20px 0;
transition: all 0.3s ease;
`;

const Container = styled.div`
max-width: 800px;
margin: 0 auto;
padding: 20px;
`;

// ThemeSwitcher component
function ThemeSwitcher() {
const { theme, toggleTheme } = useContext(ThemeContext);

return (
<button
onClick={toggleTheme}
css={css`
background-color: ${theme.colors.secondary};
color: ${theme.colors.text};
padding: 10px;
border: 1px solid ${theme.colors.border};
border-radius: 4px;
cursor: pointer;
position: fixed;
top: 20px;
right: 20px;
`}
>
Switch to {theme.name === 'light' ? 'Dark' : 'Light'} Mode
</button>
);
}

// App component
function App() {
const [currentTheme, setCurrentTheme] = useState(themes.light);

const toggleTheme = () => {
setCurrentTheme(currentTheme.name === 'light' ? themes.dark : themes.light);
};

const themeContextValue = {
theme: currentTheme,
toggleTheme
};

return (
<ThemeContext.Provider value={themeContextValue}>
<ThemeProvider theme={currentTheme}>
<Global
styles={css`
body {
background-color: ${currentTheme.colors.background};
color: ${currentTheme.colors.text};
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
margin: 0;
padding: 0;
transition: background-color 0.3s ease, color 0.3s ease;
}
`}
/>
<Container>
<ThemeSwitcher />
<h1>Emotion Theme Switcher Demo</h1>

<Card>
<h2>What is Emotion?</h2>
<p>Emotion is a performant and flexible CSS-in-JS library that lets you write styles with JavaScript.</p>
<Button>Learn more</Button>
</Card>

<Card>
<h2>Key Features</h2>
<ul
css={css`
li {
margin: 8px 0;
}
`}
>
<li>Dynamic styling with props</li>
<li>Theme support</li>
<li>Composition and style reuse</li>
<li>Global styles</li>
<li>Server-side rendering support</li>
</ul>
<Button>View Documentation</Button>
</Card>
</Container>
</ThemeProvider>
</ThemeContext.Provider>
);
}

export default App;

Performance Considerations

Emotion is designed to be performant, but here are some tips to ensure your styles don't impact performance:

  1. Memoize dynamic styles: When creating styles that depend on props, consider using React.useMemo to prevent unnecessary style recalculations.
jsx
import React, { useMemo } from 'react';
import { css } from '@emotion/react';

function DynamicComponent({ color, fontSize }) {
const dynamicStyle = useMemo(() =>
css`
color: ${color};
font-size: ${fontSize}px;
`,
[color, fontSize]
);

return <div css={dynamicStyle}>Dynamic Content</div>;
}
  1. Extract reusable styles: Define common styles outside of your component to avoid recreating them on each render.

Summary

Emotion is a powerful CSS-in-JS library that provides a flexible and intuitive way to style your React applications. We've covered the basic usage with the css prop, object styles, the styled API, dynamic styling with props, global styles, theming, composition, and a real-world example.

Key takeaways:

  • Emotion allows you to write CSS directly in your JavaScript/React code
  • It supports dynamic styling based on props and themes
  • You can use both string styles (template literals) or object styles
  • Emotion makes it easy to reuse and compose styles
  • It provides theming capabilities via React's Context API
  • Emotion is designed to be performant but requires some considerations for optimal performance

Additional Resources

To deepen your understanding of Emotion, consider exploring these resources:

  1. Emotion Official Documentation
  2. Theming in Emotion
  3. Composition Patterns
  4. Server-Side Rendering with Emotion

Exercises

  1. Create a Button component with multiple variants (primary, secondary, warning, danger) using Emotion's styled API.
  2. Build a simple form with styled form elements (inputs, labels, submit button) using Emotion.
  3. Implement a card component with different visual states based on props (loading, error, success).
  4. Create a responsive navigation bar that adapts to different screen sizes using Emotion's media queries.
  5. Build a theme switcher that allows users to toggle between different color schemes.

By completing these exercises, you'll gain hands-on experience with Emotion and strengthen your styling skills in React.



If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)