CSS‑in‑JS in React: Problems with Traditional CSS, Various Styling Approaches and Comparison of Popular Solutions
The article explains why traditional global CSS is problematic for component‑based development, reviews several ways to write styles in React—including BEM‑constrained classNames, inline styling, CSS Modules and css‑loader—then introduces CSS‑in‑JS concepts, demonstrates the Emotion library, compares popular packages and offers practical recommendations for choosing a styling solution.
With the rise of component‑based frameworks such as React and Vue, writing plain CSS directly in JavaScript has become increasingly popular, but many developers still encounter the limitations of traditional global CSS.
Key pain points of classic CSS are:
It applies globally, making it hard to scope styles to a single component.
Component styles that need to react to data changes are difficult to express.
Enforcing conventions (e.g., BEM) reduces productivity and hampers cross‑team collaboration.
An example of a BEM‑styled form component shows the verbosity of the markup:
<style>
.form { }
.form--theme-xmas { }
.form--simple { }
.form__input { }
.form__submit { }
.form__submit--disabled { }
</style>
<form class="form form--theme-xmas form--simple">
<input type="text" />
<input class="form__submit form__submit--disabled" type="submit" />
</form>To address these issues, the article outlines four main styling approaches used in React:
Class‑name with naming conventions (e.g., BEM). This keeps CSS separate but still suffers from global leakage.
Inline styling using JSX style={{…}} , which is concise for simple tweaks but cannot reuse complex styles.
CSS Modules / css‑loader that scope class names by generating unique identifiers (e.g., .App__app___hash ) during webpack bundling.
CSS‑in‑JS libraries that let developers write CSS inside JavaScript files; the article focuses on the emotion library.
Emotion is introduced with a minimal example:
import { css } from '@emotion/core'
const color = 'white'
const App = props => (
<div className={css`
padding: 32px;
background-color: hotpink;
font-size: 24px;
border-radius: 4px;
&:hover { color: ${color}; }
`}>
This is test.
</div>
)When compiled, Emotion generates a unique class name, injects the corresponding <style> block into the document head, and supports features such as automatic vendor prefixing, pseudo‑classes, media queries, keyframes, and source‑maps.
A comparison table of popular CSS‑in‑JS packages (styled‑components, emotion, radium, aphrodite, jss) shows that:
styled‑components has the most stars and the most complete documentation.
emotion has the smallest bundle size and a rich feature set.
aphrodite, jss, and emotion support the widest range of features.
The article concludes with practical advice:
For low‑level component libraries, a well‑structured CSS approach (BEM or a pre‑processor like LESS) keeps the bundle size minimal and allows easy style overrides.
For business‑level UI development, CSS‑in‑JS (e.g., Emotion) or CSS Modules are recommended because they provide scoped styles, allow dynamic values from JavaScript, and reduce the risk of style collisions in large, fast‑moving teams.
The final choice should depend on team familiarity and project requirements; there is no one‑size‑fits‑all solution.
ByteDance ADFE Team
Official account of ByteDance Advertising Frontend Team
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.