← Writing  ·  Essays · CSS · Architecture

CUBE CSS — a methodology that finally clicked.

Composition, Utility, Block, Exception. Why CUBE CSS replaced my BEM habit and made big codebases easier to live with.

S
Saugat Rimal
Frontend Developer · Oct 02, 2023
9 min read CSS Methodology
CUBE

For three years I wrote CSS exclusively in BEM. .card__title--featured, that whole world. It worked, but my stylesheets kept getting bigger and the names kept getting longer. When I found CUBE CSS in 2023, something clicked. Here is why I switched and how the four parts fit together.

01The problem with BEM-only

BEM (Block, Element, Modifier) is a good naming convention. It is not a complete architecture. With BEM alone, I kept hitting three problems:

  • Layout was always inside a block. So generic page layouts got named .card__grid and were not reusable across other blocks.
  • Utility classes felt dirty. If I wanted a quick margin-top, I would write a one-off modifier — when a .mt-4 would have been clearer.
  • Edge cases multiplied. Every special case became another modifier, then a modifier of a modifier.

CUBE CSS, by Andy Bell, names these forces explicitly and lets each do its job.

02What CUBE stands for

CUBE = Composition · Utility · Block · Exception. The order matters: it is the order in which styles get layered onto an element. Each layer answers a different question.

“Group your styles by what they do, not by which component they live in.”— the whole shift in one line

03C — Composition

Composition handles layout. Spacing, grids, flow — the macro arrangement of stuff on a page. Composition classes are typically used by themselves, on a parent. They do not care what is inside.

/* a stack with vertical rhythm */
.stack > * + * {
  margin-top: var(--space);
}

/* a centered, max-width container */
.center {
  max-width: var(--measure);
  margin-inline: auto;
}

04U — Utility

Utility classes do one thing each. Margin. Font size. Background color. Like Tailwind, but bespoke to your design tokens.

.text-mute { color: var(--ink-mute); }
.mt-4      { margin-top: 1rem; }
.flex-row  { display: flex; gap: .5rem; }

05B — Block

Blocks are components: cards, buttons, navs. They have their own visual identity that is not just composition + utility.

.btn {
  padding: .75rem 1.5rem;
  border: 2px solid var(--ink);
  border-radius: 999px;
  background: var(--cobalt);
  color: white;
}

06E — Exception

Sometimes a block needs a one-off variation. Exception is the right layer for that — applied with data-* attributes (not modifier classes):

.btn[data-variant="ghost"] {
  background: transparent;
  color: var(--ink);
}

Using data-* instead of .btn--ghost keeps your HTML semantic and signals “this is a state, not a sibling component.”

07How to try it on a project

  1. On your next project, start with a tiny utility set (8–12 classes). Spacing, color, layout.
  2. Build 2–3 composition classes for the macro layout (stack, cluster, sidebar, grid).
  3. Build blocks only when a chunk of UI clearly has its own identity.
  4. Reach for exceptions sparingly — they are the safety valve, not the default.

The mindset shift takes about a week. The maintenance payoff lasts the life of the project.

CSS Methodology Architecture CUBE CSS BEM