Overrides

How to override, tweak, and extend Vanilla Breeze without fighting the framework. The cascade layer architecture means your CSS always wins — no !important needed.

The Cascade Contract

Vanilla Breeze ships all framework CSS inside @layer blocks:

@layer reset, base, theme, components, utilities;

This single architectural decision makes everything else on this page work. Any CSS you write outside a layer — a plain class, an ID rule, anything unlayered — beats all layered CSS automatically.

/* Framework — inside @layer, always loses to unlayered CSS */ @layer components { .card { background: var(--color-surface); } } /* Your CSS — unlayered, always wins */ .card { background: hotpink; }

This is the guarantee. The four levels below all build on it.

Level 1: Named Theme Override

Switch to a different theme for any section of the page by setting data-theme on an element. All descendants inherit the new theme’s tokens — colour, type, spacing, shape — automatically.

<html data-theme="swiss"> <!-- This section switches to Cyber --> <section data-theme="cyber"> <h1>Cyber Heading</h1> <p>All tokens come from the Cyber theme here.</p> </section> <!-- Back to Swiss --> <section> <p>Swiss again.</p> </section> </html>

Each [data-theme] block redefines CSS custom properties at that element. Because custom properties inherit down the DOM, every child picks up the new values. Nesting works to any depth — the nearest ancestor data-theme always wins.

Notice how the same card markup produces three distinct results: default tokens, Swiss (red, Helvetica, flat), and Cyber (cyan, monospace, dark). The nested example shows Swiss → Cyber → Swiss, each layer inheriting correctly.

Level 2: Token Tweaks

Stay in a theme but adjust specific token values for a section or element. This is the most surgical option — you keep all the theme’s decisions except the ones you override.

/* Stay in Swiss, just adjust a few tokens */ .editorial-section { --color-primary: #555; /* Swiss red → neutral grey */ --line-height-normal: 1.9; /* More breathing room */ }

Set custom properties on any element. Everything inside that element consumes the adjusted values. Font, spacing, and all other tokens remain untouched.

The first card shows standard Swiss. The second swaps --color-primary to purple — only the accent changes. The third overrides primary colour, border radius, and shadow all at once, but the typography and structure remain Swiss.

Level 3: Plain CSS Overrides

Write CSS. That’s it. Because the framework uses @layer, your rules win automatically. This handles cases where token tweaks aren’t enough — you want to change a specific property on a specific element, add a behaviour the theme doesn’t model, or just write your own component.

/* No @layer, no !important — just CSS */ .pull-quote { font-size: 1.5rem; font-style: italic; border-left: 4px solid var(--color-primary); padding-left: var(--space-4); color: var(--color-text-muted); }

You can still use framework tokens inside your own rules. The token values respond to whatever theme is active at that element’s position in the DOM. Your rules add to the system rather than fighting it.

The left column shows Swiss defaults. The right column shows identical markup with unlayered classes applied: purple rounded card, italic pull-quote, pill-shaped button. No !important anywhere — the unlayered rules win by the cascade spec.

Level 4: Theme-Aware Utilities

Vanilla Breeze ships a @layer utilities with token-connected single-purpose classes. Unlike Tailwind utilities that bake in values at build time, VB utilities reference tokens. They respond to the active theme.

<!-- Swiss context: .bg-primary = red --> <section data-theme="swiss"> <p class="bg-primary text-inverse p-2">Swiss red</p> </section> <!-- Cyber context: .bg-primary = cyan --> <section data-theme="cyber"> <p class="bg-primary text-inverse p-2">Cyber cyan</p> </section>

The same .bg-primary class produces Swiss red in one context and Cyber cyan in another. This is the key difference from static utility frameworks — your utilities inherit meaning from the theme.

Overriding a Utility

Utilities are inside @layer utilities. Your unlayered CSS overrides them the same way it overrides any framework style:

/* Utilities are in @layer utilities — your CSS wins */ .custom-highlight { color: oklch(55% 0.2 265); /* overrides .text-primary */ }

Combining All Four Levels

All four levels compose cleanly on the same page. This demo shows a realistic magazine-style layout that uses every level together:

  • Level 1: Swiss defaults in the header; Cyber theme switch on the CTA panel
  • Level 2: Muted --color-primary and wider leading in the editorial section
  • Level 3: Custom .pull-quote and .author-byline components (unlayered CSS)
  • Level 4: Utility classes (.font-bold, .text-muted, .text-sm) on the byline

No conflicts. No specificity wars. Each level operates in its own lane because the cascade layer architecture keeps the framework out of your way.

What Not to Do

Do not use !important

It is never needed. If your rule isn’t winning, check that it is unlayered (not inside @layer). Unlayered CSS always wins.

/* Wrong — never needed */ .card { background: hotpink !important; } /* Right — just write the rule */ .card { background: hotpink; }

Do not write overrides inside framework layer names

If you declare @layer components in your own stylesheet, rules in it compete with framework component rules by source order — not a reliable override path.

/* Wrong — fights the framework by source order */ @layer components { .card { background: hotpink; } } /* Right — unlayered, always wins */ .card { background: hotpink; }

Do not hardcode values when a token exists

If the framework has --color-primary, use it. Hardcoding breaks theme inheritance.

/* Wrong — breaks when themes change */ .button { background: #e63312; } /* Right — responds to the active theme */ .button { background: var(--color-primary); }

Decision Guide

When you need to deviate from defaults, pick the right level:

Situation Approach
Entire section needs a different visual identity data-theme attribute on the section
Same theme but the accent colour differs here Token override: --color-primary: ...
A specific component behaviour needs to change Unlayered modifier class
One-off layout or component not in the framework Unlayered CSS class with your own rules
Repeated one-liner visual adjustment Utility class from @layer utilities
You think you need !important Something is wrong — check layer architecture first

How This Differs from Tailwind

Tailwind starts with a blank slate and builds up every visual property through classes in markup. Vanilla Breeze starts with sensible defaults and steps aside when you need to change something.

Tailwind Vanilla Breeze
No styles by default Styled by default
Add classes to build up Override tokens or write CSS to change
Style lives in HTML Style lives in CSS
Utility values baked at build time Utility values connected to live tokens
!important for overrides Unlayered CSS wins automatically
Purge/JIT build step required No build step

This is not anti-utility. It’s proportional. Most elements on a page should look like the theme. Classes are for exceptions, not construction.

Next Steps

Themes

Browse available themes and learn the token API.

Principles

The philosophy behind the framework.

Tokens

The full list of design tokens you can override.

Architecture Decisions

Why each structural choice was made.