Welcome to Vanilla Breeze
This bell pulls live notifications from /go/notify/messages — the same contract documented at /docs/concepts/service-contracts/. Static articles like this one are the no-JS / no-backend fallback.
This bell pulls live notifications from /go/notify/messages — the same contract documented at /docs/concepts/service-contracts/. Static articles like this one are the no-JS / no-backend fallback.
Vanilla Breeze is built on a philosophy of progressive enhancement, simplicity, and respect for the web platform. Understanding these principles helps you get the most out of the library.
Vanilla Breeze organizes web development into three distinct, optional layers. Each layer builds on the previous without requiring it.
Semantic markup that works everywhere. Content is accessible, indexable, and functional with no styling at all.
Required: Always
Design tokens, native element styling, and CSS-only custom elements. Full visual polish without any JavaScript.
Required: Optional
Web components for complex interactivity: animations, keyboard navigation, ARIA management, and dynamic behavior.
Required: Optional
Consider an accordion component:
| Layer | What You Get | Code |
|---|---|---|
| HTML only | Functional expand/collapse with native <details> |
<details><summary>Title</summary>Content</details> |
| HTML + CSS | Styled with proper spacing, typography, and visual hierarchy | Same HTML, Vanilla Breeze CSS loaded |
| HTML + CSS + JS | Smooth animations, keyboard navigation, exclusive mode | <accordion-wc> wrapper added |
Each layer is an enhancement, not a requirement. Your content works at every level.
Many frameworks treat HTML as an afterthought or a compile target. Vanilla Breeze treats it as the foundation.
When JavaScript fails (and it will), your content remains accessible. Forms still submit. Links still navigate. Information is still readable.
HTML renders immediately. Users see content before CSS and JavaScript finish loading. No blank screens, no loading spinners for basic content.
Search engines can index all your content without executing JavaScript. Social media previews work correctly. Screen readers work out of the box.
HTML is the simplest programming language. Anyone can learn it. There's no build step, no transpilation, no framework-specific syntax to master.
HTML from 1995 still works today. Frameworks come and go; semantic HTML persists. Your investment in learning HTML pays dividends forever.
Modern HTML provides more than many developers realize:
<details> and <summary> for accordions<dialog> for modals with built-in focus trappingpopover attribute for popovers and dropdowns<input type="date"> for date pickers<input type="color"> for color pickers<progress> and <meter> for progress indicatorsrequired, pattern, min, max:has(), :is(), and :where() for powerful CSS selectorsVanilla Breeze enhances these native capabilities rather than replacing them.
Progressive enhancement means starting with a baseline experience that works for everyone, then adding capabilities for browsers and users that support them.
Layout elements like <layout-stack> and <layout-grid> work purely with CSS. No JavaScript registration is needed because they use CSS attribute selectors:
/* This selector works whether or not the element is registered */layout-stack { display: flex; flex-direction: column;} layout-stack[data-layout-gap="m"] { gap: var(--size-m);}
JavaScript web components wrap native HTML patterns. The native pattern always works; the web component adds polish:
<!-- This works without JS, styled by CSS --><details> <summary>Click to expand</summary> <p>Content is always accessible</p></details> <!-- This adds animations and keyboard features --><accordion-wc> <details> <summary>Click to expand</summary> <p>Content with smooth animation</p> </details></accordion-wc>
Components use the :defined pseudo-class to style differently before and after JavaScript runs:
/* Before JS registers the component */tab-set:not(:defined) { /* Show all panels stacked */} /* After JS registers the component */tab-set:defined { /* Show tab navigation */}
Vanilla Breeze has no runtime dependencies. The CSS and JavaScript are self-contained.
Vanilla Breeze uses only:
@layer for cascade managementDevelopment dependencies exist for building and testing, but they never ship to users.
Names should describe what something is, not how it looks.
Custom elements use descriptive, hyphenated names that are self-documenting:
<!-- Layout describes what it does --><layout-stack> <!-- Stacks children vertically --><layout-cluster> <!-- Clusters items horizontally with wrapping --><layout-sidebar> <!-- Creates a sidebar layout --><layout-grid> <!-- Responsive grid layout --> <!-- Web components describe their purpose --><accordion-wc> <!-- Accordion behavior --><tab-set> <!-- Tab interface --><toast-msg> <!-- Toast notifications -->
Classes describe variants or purposes, not visual properties:
<!-- Good: describes purpose --><button class="secondary">Cancel</button><button class="ghost">Learn More</button><nav class="horizontal pills">...</nav> <!-- Avoid: describes appearance --><button class="gray">Cancel</button><button class="no-background">Learn More</button>
Tokens use semantic names that adapt to context:
/* Good: semantic purpose */color: var(--color-text); /* Adapts to light/dark */color: var(--color-text-muted); /* Secondary text */background: var(--color-surface); /* Main background */background: var(--color-interactive); /* Interactive elements */ /* Avoid: literal values */color: var(--gray-700);background: var(--white);
Vanilla Breeze uses data-* attributes rather than classes for component configuration and state. This creates a clear separation of concerns.
| Aspect | Classes | Data Attributes |
|---|---|---|
| Purpose | Styling hooks | Configuration and state |
| Values | Boolean only (present/absent) | Any string value |
| JavaScript access | classList.contains() |
dataset.property |
| Collision risk | High (common names) | Low (namespaced) |
<!-- Configuration with values --><layout-stack data-layout-gap="m" data-layout-align="center"><layout-grid data-layout-min="200px" data-layout-gap="l"><tab-set data-orientation="vertical"> <!-- State (boolean or value) --><accordion-wc single><button data-state="loading"><input data-valid="true"> <!-- Classes for variant styling only --><button class="secondary"><nav class="horizontal pills">
Every architectural choice in Vanilla Breeze traces to a specific failure mode it prevents. The principles above — HTML-first, progressive enhancement, zero dependencies, semantic naming, data attributes — are not just preferences. They are structural decisions with engineering rationale.
For the full list of decisions, the failure modes they prevent, and the trade-offs they accept, see Architecture Decisions.
Now that you understand the philosophy, put it into practice:
Get up and running in minutes.
Build a complete page step by step.
Learn how Vanilla Breeze supports accessibility.
Explore all available components.