Skip to content

Readable DOM

Structure before styling. Intent in the markup.

Styling describes appearance. Structure describes intent. Here's what that looks like in real markup.

Compare

Same UI. Different story. Appearance vs intent.

Utility classes aren't the enemy. Walls of appearance utilities are hard to keep consistent. Intent in the class names is easier for humans and AI to follow.

Appearance

<div class="flex flex-col gap-4 p-6 bg-white
     rounded-lg border shadow-sm">
  <h2 class="text-xl font-semibold
      text-gray-900">Payment Settings</h2>
  <p class="text-gray-600">Manage methods.</p>
  <div class="flex gap-2">
    <button class="px-4 py-2 bg-blue-600
            text-white rounded">Save</button>
  </div>
</div>

Describes how it looks.

Intent

<div class="af-card af-stack af-gap-lg">
  <h2 class="af-card__title">Payment Settings</h2>
  <p class="af-card__body">Manage methods.</p>
  <div class="af-inline">
    <button class="af-btn">Save</button>
  </div>
</div>

Describes what the UI is.

Examples

Markup that reads. Code left. Live UI right.

Read the classes, understand the UI.

Dashboard shell

af-sidebar for aside + main. af-stack for vertical flow.

<div class="af-sidebar af-gap-xl">
  <aside>
    <nav class="af-stack af-gap-sm">
      <a href="#">Dashboard</a>
      <a href="#">Settings</a>
    </nav>
  </aside>
  <main class="af-stack af-gap-lg">
    <header class="af-inline af-justify-between">
      <h1>Welcome</h1>
      <button class="af-btn">Create</button>
    </header>
    <p>Content here</p>
  </main>
</div>

Welcome

Content here

Responsive card grid

af-grid + responsive suffixes. Cards that grow from 1 to 3 columns.

<div class="af-grid af-grid-1 af-grid-2@md af-grid-3@lg af-gap-lg">
  <div class="af-card">
    <h3 class="af-card__title">Revenue</h3>
    <p class="af-text-h2">$84k</p>
  </div>
  <div class="af-card">
    <h3 class="af-card__title">Users</h3>
    <p class="af-text-h2">12.4k</p>
  </div>
  <div class="af-card">
    <h3 class="af-card__title">Orders</h3>
    <p class="af-text-h2">1,280</p>
  </div>
</div>

Revenue

$84k

Users

12.4k

Orders

1,280

Form layout

af-field, af-input, af-inline for actions.

<form class="af-stack af-gap-lg">
  <div class="af-field">
    <label class="af-field__label" for="email">Email</label>
    <input type="email" id="email" class="af-input">
    <p class="af-field__help">We'll never share your email.</p>
  </div>
  <div class="af-inline">
    <button type="submit" class="af-btn">Submit</button>
    <button type="button" class="af-btn af-is-secondary">Cancel</button>
  </div>
</form>

We'll never share your email.

Page composition

Stack the vocabulary: header inline, body grid, patterns nested inside.

<main class="af-stack af-gap-xl">
  <header class="af-inline af-justify-between af-items-center">
    <div class="af-stack af-gap-xs">
      <h1>Projects</h1>
      <p class="af-text-muted">Active this quarter</p>
    </div>
    <button class="af-btn">New project</button>
  </header>
  <section class="af-grid af-grid-2 af-gap-lg">
    <article class="af-card af-stack af-gap-md">
      <h2 class="af-card__title">Atlas</h2>
      <p class="af-text-muted">Design system refresh</p>
      <span class="af-badge af-is-success">On track</span>
    </article>
    <article class="af-card af-stack af-gap-md">
      <h2 class="af-card__title">Orbit</h2>
      <p class="af-text-muted">Billing migration</p>
      <span class="af-badge af-is-warning">At risk</span>
    </article>
  </section>
</main>

Projects

Active this quarter

Atlas

Design system refresh

On track

Orbit

Billing migration

At risk

Markup that says what the UI is. Humans compose it. AI can follow it.