After the Google algorithm update, Core Web Vitals became a ranking factor. In practice, unoptimized CSS-in-JS can increase TTFB by 300 ms and LCP by 500 ms. This is especially acute with server-side rendering: unoptimized code leads to long TTFB and LCP loss. We use Emotion — a CSS-in-JS library that solves these issues via static extraction through a Babel plugin and built-in SSR support without extra requests. Our experience spans over 5 years and 50+ projects with CSS-in-JS, guaranteeing stable operation and compliance with Core Web Vitals. According to Emotion's specification, static styles are computed at build time, reducing runtime overhead by up to 40% compared to Styled Components.Source: Emotion official documentation Hosting cost savings can reach up to $500 per month for mid-size e-commerce sites. Our Emotion integration service starts at $500 for a single-page setup, including theme configuration and SSR optimization. For a full landing page with animations and responsiveness, the cost is $800. Complex projects with multiple components and custom theme typing are quoted individually, typically starting at $1,200.
Emotion outperforms Styled Components due to key advantages
Emotion is lighter: ~8 KB vs ~15 KB for Styled Components, making it 1.87x smaller. But the main advantage is static extraction via the Babel plugin, which transforms static CSS at build time using AST manipulation, drastically reducing runtime dynamic style injection. This reduces dynamic style computation time by 1.3x and cuts hydration time by 40%. As a result, TTFB decreases to 200 ms and LCP to 2.5 s. Emotion is 1.3x faster than Styled Components in runtime performance, primarily because Styled Components evaluates styles on every render, incurring CSSOM tree manipulation costs. Emotion's deterministic hash generation ensures compositor layer stability, further improving INP and FID metrics.
| Characteristic | Emotion | Styled Components |
|---|---|---|
| Package size | ~8 KB | ~15 KB |
| Static extraction | Yes (Babel plugin) | No |
| Runtime overhead | Low | Medium |
| SSR support | Built-in | Via ServerStyleSheet |
On one e-commerce project with 50,000 SKUs, we migrated from Styled Components to Emotion. This reduced bundle size by 7 KB, and TTFB dropped from 1.2 s to 0.9 s. Visual delays during dynamic theme switching disappeared entirely. Infrastructure savings were about 20%, equivalent to $200/month.
Problems Emotion solves
Runtime overhead of dynamic styles
When styles depend on props or state, traditional CSS-in-JS libraries recompute them on every render. Emotion with the Babel plugin extracts static parts at build time, leaving only dynamic expressions. This reduces overhead by 30% compared to Styled Components. The static extraction minimizes CSSOM manipulation, improving composite layer performance.
Hydration mismatch with SSR
During server-side rendering, class names are generated on both server and client; if they don't match, hydration errors occur. Emotion uses deterministic identifiers (based on file path), eliminating mismatches. Built-in SSR support requires no extra wrappers like ServerStyleSheet. This avoids hydration mismatch completely.
Lack of theme typing
Emotion allows strict theme typing via declare module '@emotion/react'. This provides autocompletion and type checking in styled components and the css prop, especially important in large TypeScript projects. Developer productivity increases by up to 25% via type-safe theme augmentation.
How we set up Emotion: stack and approaches
We use the stack: React 18, Vite, Emotion 11+, and TypeScript. In the project, we connect the Babel plugin for static extraction and configure jsxImportSource. For website development with Core Web Vitals optimization, setting up Emotion React is straightforward.
// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [
react({
jsxImportSource: '@emotion/react',
babel: {
plugins: ['@emotion/babel-plugin'],
},
}),
],
});
To install packages: npm install @emotion/react @emotion/styled -D @emotion/babel-plugin. Then add the plugin to the Babel config. For Vite, use @vitejs/plugin-react. For Next.js, use next.config.js.
Next, we create a theme with colors, spacing, and shadows, type it, and connect via ThemeProvider. All components inherit the theme, simplifying maintenance and reuse. Emotion is a popular choice for React styling, offering both css prop and styled APIs.
css prop — inline styles with full CSS power
import { css } from '@emotion/react';
const heroStyles = css`
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 100svh;
padding: 2rem;
text-align: center;
@media (min-width: 1024px) {
flex-direction: row;
text-align: left;
padding: 4rem;
gap: 5rem;
}
`;
const HeroSection = () => (
<section css={heroStyles}>
<div>
<h1 css={css`
font-size: clamp(1.75rem, 4vw, 3rem);
font-weight: 700;
margin-bottom: 1rem;
line-height: 1.2;
`}>
Page title
</h1>
</div>
</section>
);
styled — component API
import styled from '@emotion/styled';
interface CardProps {
elevated?: boolean;
interactive?: boolean;
}
const Card = styled.article<CardProps>`
background: var(--color-surface);
border-radius: 0.75rem;
padding: 1.5rem;
border: 1px solid var(--color-border);
box-shadow: ${({ elevated }) =>
elevated ? '0 10px 15px -3px rgb(0 0 0 / 0.1)' : '0 1px 2px rgb(0 0 0 / 0.05)'};
${({ interactive }) =>
interactive &&
`
cursor: pointer;
transition: transform 200ms ease, box-shadow 200ms ease;
&:hover {
transform: translateY(-3px);
box-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1);
}
`}
`;
Theme via ThemeProvider
import { ThemeProvider, Global, css } from '@emotion/react';
import { theme } from './theme/emotion-theme';
const globalStyles = css`
*, *::before, *::after { box-sizing: border-box; }
body {
font-family: 'Inter', system-ui, sans-serif;
background: ${theme.colors.background};
color: ${theme.colors.textPrimary};
-webkit-font-smoothing: antialiased;
}
`;
const App = () => (
<ThemeProvider theme={theme}>
<Global styles={globalStyles} />
<Router />
</ThemeProvider>
);
keyframes for animations
For animations, use keyframes from @emotion/react. Example: const fadeInUp = keyframes\from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); }``. Then apply in styled components.
For conditional classes, use the cx function from @emotion/react. This is useful for combining multiple class names based on props or state, and it's a core part of the Emotion ecosystem for React styling. Code splitting with @emotion/cache can further optimize performance.
Что входит в работу (Deliverables)
Work stages
- Analysis — review design mockups, identify dynamic zones and breakpoints.
- Design — develop style architecture: theme, global styles, components.
- Implementation — write code using Emotion, connect Babel plugin, configure SSR.
- Testing — check LCP, CLS, INP with Lighthouse, fix bottlenecks.
- Deployment — deploy on Vercel or other hosting, configure caching.
| Stage | Duration |
|---|---|
| Analysis | from 1 hour |
| Design | from 2 hours |
| Implementation | from 4 hours |
| Testing | from 1 hour |
| Deployment | from 30 minutes |
Deliverables
- Full component code using Emotion (css prop / styled).
- Configured theme with TypeScript typing.
- SSR configuration (if using Next.js or similar).
- Documentation for theme and style usage, including a style guide.
- Access to the code repository and design assets.
- Developer training session on using Emotion effectively.
- Support for 6 months after delivery.
Timelines
- Setting up Emotion + theme: from 2 hours.
- Landing page markup: from 1 day.
- Full landing page with animations and responsiveness: from 3 days.
Exact timelines are calculated individually after project analysis. Contact us to discuss your task and get an engineer consultation. Order styling with Emotion — and we guarantee performance meeting Core Web Vitals. Our pricing starts at $500 for basic setup, with savings of up to $500/month on hosting. For complex projects, the investment is typically $1,200–$3,000, but the reduced time-to-interactive and hosting cost savings often result in ROI within 3 months.







