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.

To top

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.

To top

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
m margin, p padding, t top, b bottom, l left, r right, x horizontal, y vertical
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)

To top

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.

To top

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

  1. Lowercase with hyphens for multi-word names: .horizontal-nav, .button-group
  2. Double-dash for variants: .button--red, .table--striped
  3. 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>

To top

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: dataset API is cleaner than classList manipulation
  • Explicit: Clear separation between structural classes and state
  • Queryable: Easy to select elements by state: [data-state="active"]

To top

HTML conventions


Attribute order

For consistency, order attributes as:

  1. class
  2. id
  3. data-*
  4. src, href, for
  5. type, name, value
  6. aria-*, 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:

  1. Layout/composition classes
  2. Block/component classes
  3. Variant modifiers
  4. 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>

To top

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]

To top