Architecture Decisions

Every major architectural choice in Vanilla Breeze traces to a failure mode it prevents. This page documents those decisions so future contributors understand not just what was decided, but why. For the philosophy these decisions serve, see Principles.

Hyphenated Element Names

Decision
Custom elements must use a hyphen in their name (e.g. <tab-set>, not <tabset>).
Because
The HTML spec reserves unhyphenated names for future standard elements. Using a hyphen prevents collision with any current or future HTML element, ensures the parser routes the element through the custom element registry, and makes third-party component origins visually identifiable in markup.
Trade-off
Slightly more verbose tag names. Acceptable given the collision protection and parser guarantee.

State via data-* Attributes

Decision
Component state is communicated via data-* attributes, not CSS classes.
Because
CSS classes conflate styling concerns with state concerns. data-* attributes are queryable via the dataset API, can be targeted by CSS attribute selectors without class specificity issues, survive serialization (e.g. server-side rendering produces correct initial state), and are unambiguous in their purpose. A class named active could mean anything; data-state="active" cannot.
Trade-off
Slightly more verbose selectors ([data-state="active"] vs .active). Acceptable given the clarity and API benefits.

Single @layer Declaration

Decision
@layer order is declared once in the framework entry file; no other file may redeclare layer order.
Because
Multiple @layer order declarations in different files produce unpredictable cascade behavior as load order varies. A single declaration point guarantees deterministic cascade behavior regardless of which stylesheets load first or in what order. This is the CSS equivalent of a single source of truth.
Trade-off
All consuming projects must import the framework entry file before any other stylesheet. Documented as a usage requirement.

Theme Restrictions

Decision
Themes may not change layout, spacing structure, or display values — only color, typography, and surface tokens.
Because
Layout changes in a theme layer break the component's pre-upgrade CSS baseline, potentially causing the :not(:defined) fallback and the upgraded state to have different layout models. This would produce layout shift on upgrade even with pre-upgrade CSS in place.
Trade-off
Theme authors have less control. This is intentional — visual identity lives in color and type; structural layout lives in components.

<details>-Based Tabs

Decision
The <tab-set> component is built on native <details> elements with the name attribute for exclusive accordion behavior.
Because
Native <details> provides disclosure interactivity without JavaScript, keyboard support, screen reader announcements, and form state restoration for free. The name attribute (supported in all modern browsers) provides exclusive-open behavior. This means tabs degrade gracefully to a working accordion when JS fails to load.
Trade-off
Summary elements cannot use ARIA role="tab" without conflicting with their implicit button role. VB accepts this by relying on the native semantics rather than imposing tab semantics.

OKLCH Color System

Decision
All color tokens use OKLCH color space with hue-angle custom properties.
Because
OKLCH provides perceptually uniform lightness (unlike HSL), consistent chroma across hues, and enables algorithmic palette generation via hue rotation. The @property-registered hue angles (--hue-primary, etc.) allow themes to shift the entire palette with a single value change.
Trade-off
OKLCH requires modern browser support (2023+). Fallback hex values are provided where critical.

Pack Architecture

Decision
Visual themes, effects, and component extensions are bundled as "packs" (e.g. kawaii, retro) that layer onto the base framework.
Because
Packs allow themed experiences without polluting the core framework. Each pack appends to the declared bundle-theme, bundle-effects, and bundle-components layers, ensuring predictable cascade behavior. Packs are additive and optional — the framework is fully functional without any pack.
Trade-off
Pack authors must understand the layer system and token contract. Documentation and the /validate-component command help enforce compliance.

Custom Elements over Utility Classes

Decision
<layout-stack data-layout-gap="m"> instead of <div class="flex flex-col gap-4">.
Because
Custom elements are self-documenting in the DOM inspector, clearly show nesting relationships, and don't pollute the global class namespace. They create a semantic vocabulary for layout intent rather than encoding visual properties in markup.
Trade-off
Slight unfamiliarity for developers used to utility-class frameworks. The readability and maintainability benefits outweigh this learning curve.

Logical Properties Throughout

Decision
All component CSS uses logical properties (inline-size, margin-block-start, inset-inline-end) instead of physical equivalents.
Because
Physical CSS properties (margin-left, width, top) break silently in RTL layouts and non-horizontal writing modes. Logical properties adapt automatically to any writing direction, making components work correctly in English (LTR), Arabic (RTL), and vertical scripts without code changes.
Trade-off
Less familiar syntax. Intentional exceptions exist for float: left (limited float: inline-start support), CSS Anchor Positioning (uses physical inset properties), and JS-computed viewport coordinates.

Selective Normalization, Not Reset

Decision
Vanilla Breeze uses targeted normalization rather than a comprehensive CSS reset.
Because
Browser defaults are often sensible and reflect user preferences (e.g. font size, link colors). A heavy reset discards those defaults and forces re-declaration of everything. Selective normalization adjusts only what needs adjusting (box-sizing, margin collapse, tap targets), resulting in smaller CSS and better alignment with user settings.
Trade-off
Components inherit some browser variation. Acceptable because design tokens override the meaningful values.

Zero Runtime Dependencies

Decision
Vanilla Breeze ships no runtime dependencies. The CSS and JavaScript are self-contained.
Because
Every dependency is a supply chain risk, a source of breaking changes, and a chunk of code you don't control. Zero dependencies means no transitive vulnerabilities, no forced upgrades, no package manager required, and a stable artifact that works as long as browsers support standard web APIs.
Trade-off
Some functionality that libraries provide for free must be implemented directly. Acceptable given the security, stability, and longevity benefits.

MIT License

Decision
The project uses the MIT license.
Because
MIT is maximally permissive. Students can use it in coursework. Companies can use it without legal review. Contributors face no licensing friction. This removes barriers to adoption and encourages learning.
Trade-off
No copyleft protection. Acceptable because the goal is maximum adoption and educational use.

Pre-upgrade CSS Baseline

Decision
Every web component must include :not(:defined) CSS rules that render content readably before JavaScript upgrades the element.
Because
The gap between HTML parsing and custom element upgrade produces a Flash of Undefined Content (FOUC). Without pre-upgrade styles, elements may render as unstyled blocks, shift layout on upgrade, or be invisible. The :not(:defined) selector targets exactly this window.
Trade-off
Component authors must maintain two visual states (pre and post upgrade). The spec template and validation command enforce this requirement.