Gigson Expert

/

March 10, 2026

CSS-in-JS vs Traditional CSS: Which One Should You Use?

CSS-in-JS vs traditional CSS explained. Compare performance, scalability, scoping, and developer experience to choose the right styling approach.

Blog Image

Nwaokocha Michael

A Web Developer with experience building scalable web and mobile applications. He works with React, TypeScript, Golang, and Node.js, and enjoys writing about the patterns that make software easier to understand. When not debugging distributed systems or writing articles, you can find him reading sci-fi novels or hiking.

Article by Gigson Expert

The CSS-in-JS versus traditional CSS debate has been going on for years, and if you search for answers, you'll find people on both sides absolutely convinced they're right. The CSS-in-JS folks talk about scoping and co-location like it's the greatest invention since sliced bread. The traditional CSS folks talk about separation of concerns and browser optimisation.

Here's what I've learned after using both extensively: they're both right. And they're both wrong. Because the real answer isn't "which one is better?" It's "which one fits your situation?"

How We Got Here

CSS wasn't always the way it is now. When it was first introduced in 1996, it was revolutionary. Before CSS, if you wanted to style text, you'd write <font color="red" size="4">Hello World</font> every single time. Want to change the colour? Find and replace everywhere. It was a nightmare.

CSS came along and said, "What if we separate structure from presentation?" Write your HTML for structure, and CSS for styling. Want all h1 tags to be red? Write one rule. Want to change it? Change it once. Brilliant.

h1 {
  color: red;
  font-size: 2em;
}

Then websites got bigger. Teams got bigger. And suddenly, everyone discovered the same problems: Global scope was a disaster. Specificity wars were real. Dead code piled up. Maintenance was painful.

The community tried solutions like BEM, Sass, and CSS Modules. Each helped, but also added complexity. Then, JavaScript frameworks like React changed how we built UIs. Instead of pages, we built components. Each component was self-contained with its own logic and markup... but the styling was still global and separate.

That's when CSS-in-JS emerged. The idea: if components own their logic and markup, why not their styles too?

Traditional CSS: The Classic Approach

Traditional CSS means writing styles in .css files and linking them to your HTML or importing them into your JavaScript.

/* styles.css */
.card {
  border: 1px solid #ddd;
  padding: 16px;
  background: white;
}

.card-title {
  font-size: 1.5em;
  color: #333;
}

// Card.jsx
import './styles.css';

function Card({ title, children }) {
  return (
    <div className="card">
      <h2 className="card-title">{title}</h2>
      <div>{children}</div>
    </div>
  );
}

Simple. Familiar. It works.

Why Teams Still Choose Traditional CSS

  • It's fast. Browsers have been optimising CSS parsing for decades. No JavaScript execution needed.
  • It's cacheable. Your styles.css file can be cached by browsers and CDNs. Users download it once, and it's there for every page load.
  • Developer tools are excellent. Browser DevTools were built for traditional CSS. Inspect element, see your styles, edit them live.
  • It's shareable across frameworks. CSS doesn't care if you're using React, Vue, or plain HTML. This is huge for large organisations with mixed tech stacks.
  • The learning curve is gentler. "HTML for structure, CSS for style, JavaScript for behaviour" is a clean mental model.

Where Traditional CSS Breaks Down

  • Global scope by default. Everything is global unless you use CSS Modules, requiring conventions and discipline to manage.
  • No dead code elimination. When refactoring, CSS is often forgotten. Traditional CSS cannot be tree-shaken.
  • Lack of co-location. Component logic and styles are in separate files, hindering a complete view.
  • Limited dynamic styling. Changing styles based on props or state involves toggling class names or inline styles, which can be clunky.

CSS-in-JS: The Modern Contender

CSS-in-JS flips the traditional approach. Instead of writing CSS in separate files, you write it in JavaScript, usually right next to the component that uses it.

import styled from 'styled-components';

const Card = styled.div`
  border: 1px solid #ddd;
  padding: 16px;
  background: white;
`;

const CardTitle = styled.h2`
  font-size: 1.5em;
  color: #333;
`;

function Card({ title, children }) {
  return (
    <Card>
      <CardTitle>{title}</CardTitle>
      <div>{children}</div>
    </Card>
  );
}

Same result, different approach.

Why Teams Choose CSS-in-JS

  • Scoping is automatic: Each styled component gets a unique class name generated at build time, eliminating naming conflicts and specificity wars.
  • Co-location is natural: Styles reside right alongside the component logic, making refactoring and deletion simpler.
  • Dynamic styling is easy: Styles can be easily changed based on props through interpolation.
  • Dead code elimination works: Deleting a component also deletes its styles, allowing bundlers to tree-shake unused styled components.
  • Theming is built in: Most CSS-in-JS libraries include out-of-the-box theming support.
  • Type safety (with TypeScript): Typing props enables autocomplete and compile-time error checking.

Where CSS-in-JS Falls Short

  • Runtime cost: In most runtime-based CSS-in-JS solutions, styles are parsed and injected via JavaScript execution, which blocks rendering.
  • Larger bundle sizes: The library and runtime logic make it larger than traditional CSS. Compared to build-time extraction approaches, the difference is less pronounced but still present.
  • SSR complexity: Server-side rendering is more difficult to set up.
  • Mixed DevTools experience: Debugging is harder due to unreadable, generated class names (e.g., .sc-bdVaJa).
  • Framework lock-in: Most libraries are framework-specific, making styles hard to share across technologies.

Access a Global pool of Talented and Experienced Developers

Hire skilled professionals to build innovative products, implement agile practices, and use open-source solutions

Start Hiring

So Which One Should You Use?

Here's the truth: both approaches are legitimate. The question isn't "which is better?" The question is "which fits your situation?"

Use traditional CSS if:

  • You're building content-heavy websites where performance and caching matter most
  • You have specialised CSS developers who prefer working in stylesheets
  • You need to support multiple frameworks or technologies
  • Performance is critical, and every millisecond counts

Use CSS-in-JS if:

  • You're building a complex, highly interactive application with dynamic styling needs
  • Your team is primarily JavaScript developers, more comfortable writing everything in JS
  • You're working on a greenfield project and want co-location benefits
  • Theming is a core requirement

Real-World Scenarios

  • For startups: If you're a small team moving fast, CSS-in-JS often wins. The co-location and automatic scoping mean less cognitive overhead when shipping features. You can hire JavaScript developers who'll be productive immediately without needing CSS architecture expertise.
  • For enterprises: Traditional CSS (especially with CSS Modules) often makes more sense. You might have dedicated frontend specialists, multiple teams working across different frameworks, and strict performance budgets. The separation also makes code reviews clearer; style changes don't mix with logic changes.
  • For content sites: If your performance budget is tight and you're serving millions of users, traditional CSS's caching advantages compound. News sites, blogs, and documentation sites benefit enormously from static CSS files that load once and work everywhere.
  • For SaaS applications: CSS-in-JS shines when theming is core to your product. If customers can customise colours, or you offer light/dark modes with dozens of variations, the dynamic capabilities save significant development time.

Team Considerations

Your styling choice affects more than just performance—it affects how your team works. CSS-in-JS lowers the barrier for JavaScript developers to contribute styling changes, which can accelerate development in JS-heavy teams. However, it can complicate code reviews when style and logic changes are intertwined. Traditional CSS makes it easier to onboard junior developers with a clear separation of concerns, but requires more discipline to maintain architecture over time.

For growing teams, consider this: CSS-in-JS makes refactoring safer (delete a component, delete its styles) but makes performance optimization harder to audit. Traditional CSS makes performance easier to measure but technical debt easier to accumulate.

Or maybe use both?

Lots of successful projects use traditional CSS for base styles and global layouts, and CSS-in-JS for component-specific styles. You get the caching and performance of traditional CSS for the bulk of your styles, and the convenience of CSS-in-JS where it matters most.

/* global.css - Traditional CSS for base styles */
:root {
  --color-primary: blue;
  --spacing-unit: 8px;
}

body {
  font-family: sans-serif;
  line-height: 1.6;
}
// Component-specific styles with CSS-in-JS
const Button = styled.button`
  background: var(--color-primary);
  padding: calc(var(--spacing-unit) * 2);
  /* Dynamic styles */
  opacity: ${props => props.disabled ? 0.5 : 1};
`;

The Real Decision: Know Your Tradeoffs

There's no universal answer. Both make tradeoffs, and the right choice depends on what tradeoffs make sense for your project.

Traditional CSS trades convenience for performance and portability. You need more discipline, but you get faster rendering, better caching, and framework independence.

CSS-in-JS trades performance for convenience and safety. You get automatic scoping and powerful dynamic styling, but you pay in bundle size, runtime cost, and framework coupling.

Neither is wrong. They're optimising for different priorities.

The mistake is picking a side based on what you read in a blog post without thinking about your specific situation. What's your performance budget? What's your team's skill set? What are you building? How fast is your team growing? Those questions matter more than "which is better in the abstract?"

My Recommendation

If you're starting a new project and you're not sure, start with traditional CSS and a good methodology. Use CSS Modules if you want scoping without runtime cost. Learn how to structure CSS well.

If you hit pain points that CSS-in-JS solves better, then switch. You'll switch with understanding of what problem you're solving.

Either way, learn both. Understanding the tradeoffs makes you a better developer, regardless of which tool you reach for.

Because at the end of the day, the best approach is the one that lets you ship working software that performs well and can be maintained by your team. Everything else is details.

Frequently Asked Questions

Q: Tailwind CSS?

Tailwind is utility-first CSS. It uses single-purpose classes in HTML/JSX. Pros: fast development, consistent design. Cons: verbose HTML, learning curve. A distinct approach, worth considering.

Q: Is CSS-in-JS dying due to performance?

No, it's evolving. Newer solutions (vanilla-extract, Linaria) generate CSS at build time, removing runtime cost while keeping co-location benefits.

Q: CSS Modules & CSS-in-JS?

Unusual; they both provide scoping. Most teams choose one. Some use Modules for general components and CSS-in-JS for heavy dynamic styling.

Q: CSS frameworks (Bootstrap, Material UI)?

These are component libraries, not styling approaches. Bootstrap uses traditional CSS; Material UI uses CSS-in-JS (Emotion). The framework choice may influence your styling.

Q: Switching approaches?

Don't switch if the current method works. If a new approach solves real pain points, document the issues, show the solution, and acknowledge tradeoffs. Avoid switching based only on external opinions.

Q: Do we lose the CSS cascade with CSS-in-JS?

Yes, deliberately. The cascade aids style sharing but causes conflicts (specificity wars). CSS-in-JS trades the cascade for predictable, isolated component styles.

Q: Personal preference?

It's project-dependent. For a static blog: Traditional CSS with CSS Modules (simplicity, performance). For a complex dashboard: CSS-in-JS with styled-components (dynamic themes, easier maintenance). Choose the right tool for the job.

Subscribe to our newsletter

The latest in talent hiring. In Your Inbox.

Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.

Hiring Insights. Delivered.

Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.

Request a call back

Lets connect you to qualified tech talents that deliver on your business objectives.

Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.