We use cookies to enhance your experience on the site
CodeWorlds

CSS-in-JS - Advanced Navigation Systems

Styled-components is not the only CSS-in-JS library. There are others, each with unique advantages. Let's explore two of the most important ones: Emotion and vanilla-extract.

Emotion

Emotion is a CSS-in-JS library that offers two ways of using it:

Object API (
@emotion/react
)

1/** @jsxImportSource @emotion/react */
2import { css } from '@emotion/react';
3
4function SpacePanel({ isActive }) {
5  return (
6    <div css={css`
7      background: #0d1137;
8      border: 2px solid ${isActive ? '#00e676' : '#3949ab'};
9      border-radius: 12px;
10      padding: 20px;
11      transition: border-color 0.3s ease;
12    `}>
13      <h2>Navigation Panel</h2>
14    </div>
15  );
16}

Styled API (
@emotion/styled
)

1import styled from '@emotion/styled';
2
3const Card = styled.div`
4  background: #1a1a4e;
5  padding: 20px;
6  border-radius: 12px;
7`;
8
9// Or object syntax:
10const CardObj = styled.div({
11  background: '#1a1a4e',
12  padding: 20,
13  borderRadius: 12,
14});

Advantages of Emotion

  • Two APIs -- you can use template literals or JS objects
  • Lightweight -- smaller bundle than styled-components
  • High performance -- optimized runtime
  • css prop -- you can add styles directly via the
    css
    prop

Vanilla-extract -- Zero-runtime CSS-in-JS

Vanilla-extract is a completely different approach: styles are generated at compile time, not at runtime. Zero JavaScript in the client bundle!

1// styles.css.ts
2import { style, globalStyle } from '@vanilla-extract/css';
3
4export const panel = style({
5  background: '#0d1137',
6  border: '2px solid #3949ab',
7  borderRadius: 12,
8  padding: 20,
9  ':hover': {
10    borderColor: '#7c4dff',
11  },
12});
13
14export const title = style({
15  color: '#7c4dff',
16  fontSize: 24,
17});
1// Component.tsx
2import { panel, title } from './styles.css.ts';
3
4function SpacePanel() {
5  return (
6    <div className={panel}>
7      <h2 className={title}>Panel</h2>
8    </div>
9  );
10}

Advantages of vanilla-extract

  • Zero runtime -- no additional JS in the browser
  • TypeScript-first -- full typing, auto-completion
  • Type-safe -- compilation error when using a non-existent style
  • Theming -- built-in theme system with CSS variables

CSS-in-JS Comparison

| Feature | Styled-components | Emotion | Vanilla-extract | |---------|-------------------|---------|-----------------| | Runtime | Yes | Yes | No (zero-runtime) | | Bundle | Larger | Medium | Minimal | | TypeScript | Good support | Good support | Native TS | | SSR | Requires configuration | Requires configuration | Seamless | | DX | Very good | Very good | Requires build |

When to use which library?

The choice of CSS-in-JS library depends on several factors:

Choose styled-components when:

  • Your team already knows this library -- it's the most popular and has the largest community
  • You need a rich ecosystem of plugins and tools
  • You care about code readability -- tagged template literals are intuitive for developers who know CSS

Choose Emotion when:

  • You want flexibility -- you can use both template literals and JS objects
  • You care about a smaller bundle size
  • You use Next.js or another framework where Emotion has better integration
  • You need the
    css
    prop for quickly adding inline-like styles with the full power of CSS

Choose vanilla-extract when:

  • Performance is the number one priority -- zero JS in the client bundle
  • You use TypeScript and want full type safety
  • You're building a large application where bundle size matters
  • You don't need dynamic styles based on runtime props

Trend: zero-runtime CSS-in-JS

More and more projects are moving to zero-runtime solutions like vanilla-extract, Panda CSS, or Linaria. The reason? In large applications, runtime CSS-in-JS (styled-components, Emotion) can slow down rendering because it generates styles in JavaScript while the application is running.

Zero-runtime generates CSS classes at compile time -- it's like preparing a navigation map before launch instead of calculating the route in flight. The result: faster page loading and better Core Web Vitals scores.

1// Panda CSS -- another popular zero-runtime alternative
2import { css } from '../styled-system/css';
3
4function Panel() {
5  return (
6    <div className={css({
7      bg: 'slate.900',
8      p: '4',
9      rounded: 'xl',
10      border: '2px solid',
11      borderColor: 'indigo.700'
12    })}>
13      Panel content
14    </div>
15  );
16}

Regardless of which library you choose, the key is to stick with one approach within a project and establish conventions with your team.

Go to CodeWorlds