Code style guide
CSS and HTML naming conventions for Live Wires, based on CUBE CSS methodology.
Philosophy
Live Wires uses CUBE CSS, a methodology created by Andy Bell that embraces the cascade rather than fighting it. CUBE stands for:
- Composition — Layout primitives that control flow and spacing
- Utility — Single-purpose classes for design tokens
- Block — Component-specific styles
- Exception — State variations and deviations
The key insight: most styling is done by global defaults and utilities. By the time you reach “blocks” (components), there’s minimal work left. This aligns perfectly with Live Wires’ cascade layers.
How CUBE maps to Live Wires layers
| CUBE Layer | Live Wires Layer | Directory |
|---|---|---|
| — | tokens |
1_tokens/ |
| — | reset |
3_generic/ |
| — | base |
4_elements/ |
| Composition | layouts |
5_layouts/ |
| Block | components |
6_components/ |
| Utility | utilities |
7_utilities/ |
| Exception | (inline via data-*) |
— |
The cascade layers
Live Wires defines six cascade layers: tokens, reset, base, layouts, components, and utilities. Each layer has specific naming conventions. Understanding which layer a class belongs to helps predict its behavior and specificity.
Cascade layers handle specificity. Utilities always beat components, components always beat layouts. No !important needed.
Utilities
Single-purpose classes that do one thing well. Named using Tailwind-style conventions: lowercase, abbreviated, with numeric scales.
Naming pattern
.{property-abbrev}-{value}
Examples
| Class | Property | Value |
|---|---|---|
.mt-4 |
margin-block-start | var(--line-4) |
.px-3 |
padding-inline | var(--line-3) |
.text-center |
text-align | center |
.font-bold |
font-weight | 700 |
.scheme-warm |
color scheme | warm palette |
Abbreviations
- Spacing
mmargin,ppadding,ttop,bbottom,lleft,rright,xhorizontal,yvertical- Typography
text-for size/alignment,font-for family/weight,leading-for line-height- Color
scheme-for color schemes,theme-for theme variants,bg-for backgrounds,fg-for foreground
Numeric scales
Spacing utilities use numeric scales that map to --line-* tokens:
0,025,05,075,1,15,2,3,4,5,6- Pixel-precise:
1px(e.g.,.mt-1px) - Auto:
.mt-auto,.mx-auto - Negative values:
.-mt-2(note leading dot-dash)
Composition (Layouts)
Layout primitives that control flow, spacing, and structure. They are context-agnostic—they don’t know or care what’s inside them.
Naming pattern
.{layout-name}
.{layout-name}-{variant}
Core layouts
| Class | Purpose |
|---|---|
.stack |
Vertical flow with consistent spacing |
.cluster |
Horizontal grouping that wraps |
.grid |
Auto-responsive grid |
.sidebar |
Main content with sidebar |
.center |
Horizontally centered with max-width |
.box |
Padding container |
.section |
Sectional wrapper |
.cover |
Full-height centered layout |
Variants use single-dash
.stack-compact
.stack-comfortable
.stack-spacious
.cluster-center
.cluster-space-between
.grid-columns-3
.grid-columns-4
Why single-dash for layouts? Layout variants are applied alongside the base class (e.g., class="stack stack-compact"), so they read naturally. Component variants use double-dash to indicate modification of a base component.
Blocks (Components)
Component-specific styles. Because global defaults and utilities handle most styling, blocks should be minimal—only what’s truly unique to that component.
Naming pattern
.{component-name}
.{component-name}--{variant}
Rules
- Lowercase with hyphens for multi-word names:
.horizontal-nav,.button-group - Double-dash for variants:
.button--red,.table--striped - CSS nesting for children, not BEM
__syntax
Child elements
Use native CSS nesting to style children. This keeps HTML clean and leverages the cascade:
/* Good: CSS nesting */
.callout {
& .content {
padding: var(--line-3);
}
& .title {
font-weight: var(--font-weight-bold);
}
}
/* Avoid: BEM element syntax */
.callout__content { }
.callout__title { }
Why not BEM elements? With CSS nesting now native, the __ convention adds verbosity without benefit. Nesting makes the relationship clear in CSS while keeping HTML cleaner.
Component variants
.button { }
.button--red { }
.button--large { }
.button--disabled { }
.table--bordered { }
.table--striped { }
.table--lined { }
.field--half { }
.field--quarter { }
HTML usage
<button class="button button--red button--large">
Delete
</button>
<table class="table--bordered table--striped">
...
</table>
<div class="callout scheme-warm">
<div class="content">
...
</div>
</div>
Exceptions (State)
Exceptions handle state changes and contextual deviations. Live Wires uses data-* attributes for state, which provides semantic meaning and easy JavaScript integration.
State with data attributes
[data-state="active"]
[data-state="open"]
[data-state="disabled"]
[data-state="loading"]
[data-state="error"]
Boolean states
For simple on/off states, use attribute presence:
[data-open]
[data-active]
[data-expanded]
[data-hidden]
CSS usage
.offcanvas {
transform: translateX(-100%);
&[data-open] {
transform: translateX(0);
}
}
.nav-link {
color: var(--color-fg);
&[data-state="active"] {
color: var(--color-accent);
font-weight: var(--font-weight-bold);
}
}
.button {
&[data-state="loading"] {
opacity: 0.7;
cursor: wait;
}
&[data-state="disabled"] {
opacity: 0.5;
cursor: not-allowed;
pointer-events: none;
}
}
HTML usage
<!-- Boolean state -->
<nav class="offcanvas" data-open>...</nav>
<!-- Named state -->
<a href="/" class="nav-link" data-state="active">Home</a>
<!-- Multiple states -->
<button class="button" data-state="loading" data-busy>
Saving...
</button>
JavaScript integration
// Toggle boolean state
element.toggleAttribute('data-open');
// Set named state
element.dataset.state = 'active';
// Check state
if (element.dataset.state === 'active') { }
if (element.hasAttribute('data-open')) { }
Why data attributes over classes?
- Semantic: State is data, not styling
- JavaScript-friendly:
datasetAPI is cleaner than classList manipulation - Explicit: Clear separation between structural classes and state
- Queryable: Easy to select elements by state:
[data-state="active"]
HTML conventions
Attribute order
For consistency, order attributes as:
classiddata-*src,href,fortype,name,valuearia-*,role
<button class="button button--red" id="delete-btn" data-state="disabled" type="button" aria-label="Delete item">
Delete
</button>
Class order
Order classes from general to specific:
- Layout/composition classes
- Block/component classes
- Variant modifiers
- Utility classes
<!-- Layout → Block → Variant → Utilities -->
<section class="stack box callout callout--featured scheme-warm mt-4">
Semantic HTML first
Always start with appropriate semantic elements. Add classes only when needed:
<!-- Good: semantic element, minimal classes -->
<article class="stack">
<h2>Article title</h2>
<p>Content that looks good by default.</p>
</article>
<!-- Avoid: div soup -->
<div class="article-wrapper">
<div class="article-title">...</div>
<div class="article-content">...</div>
</div>
Quick reference
| Layer | Pattern | Examples |
|---|---|---|
| Utility | .{abbrev}-{value} |
.mt-4, .text-center |
| Composition | .{layout}.{layout}--{variant} |
.stack, .grid--columns-3 |
| Block | .{component}.{component}--{variant} |
.button, .button--red |
| Exception | [data-state="{state}"][data-{boolean}] |
[data-state="active"], [data-open] |