Component reference

Production-ready patterns built with emilyCSS utility classes. Copy the HTML directly into your project — no imports, no runtime.

Button

button

Primary, secondary, outline, and danger variants. Includes hover, focus-visible, active, and disabled states. Works on both button and anchor elements.

Variants

Sizes

HTML
<button class="px-5 py-2.5 rounded text-sm font-medium
         bg-brand-80 text-white
         hover:bg-brand-90 transition
         focus-visible:ring-2">
  Primary
</button>

<button class="px-5 py-2.5 rounded border border-brand-80 text-sm font-medium
         text-brand-80 hover:bg-brand-10 transition
         focus-visible:ring-2">
  Outline
</button>

<button class="px-5 py-2.5 rounded text-sm font-medium
         bg-brand-80 text-white opacity-50 cursor-not-allowed" disabled>
  Disabled
</button>

Alert

div

Success, warning, error, and info variants. All use accessible colour pairings from generated OKLCH token scales. Add role="alert" for live announcements.

Review needed

Check your scan paths before publishing.

Info

emilyCSS works best when config is kept simple.

HTML
<div class="flex gap-3 rounded border-l-4 border-success-80 bg-success-10 p-4"
     role="alert">
  <p class="text-sm font-semibold text-success-90">Changes saved</p>
  <p class="text-sm text-success-70">Your configuration has been updated.</p>
</div>

Badge

span

Compact status indicators using tinted colour scales. Works with any token colour — brand, accent, success, warning, error, or neutral.

Brand Accent Success Warning Error Neutral
HTML
<span class="inline-flex items-center rounded-full
             bg-brand-10 px-3 py-1
             text-xs font-semibold text-brand-90">
  Brand
</span>

Form group

div

Label, input, hint, and error state. Works with any input type. Error uses aria-invalid and aria-describedby for screen reader compatibility.

We'll only use this for account notifications.

Enter a real postcode
Contact preference
HTML
<!-- Text input with hint -->
<div class="flex flex-col gap-1.5">
  <label for="email" class="text-sm font-medium text-neutral-80">
    Email address
  </label>
  <p class="text-xs text-neutral-50">We'll only use this for notifications.</p>
  <input id="email" type="email" placeholder="andy@example.com"
         class="rounded border border-neutral-30 px-4 py-2.5 text-sm
                focus-visible:ring-2 w-full" />
</div>

<!-- Error state -->
<div class="flex flex-col gap-1.5">
  <label for="postcode" class="text-sm font-medium text-neutral-80">Postcode</label>
  <input id="postcode" type="text" aria-invalid="true"
         aria-describedby="postcode-error"
         class="rounded border-2 border-error-80 px-4 py-2.5 text-sm
                focus-visible:ring-2 w-full" />
  <span id="postcode-error" class="text-xs font-medium text-error-80">
    Enter a real postcode
  </span>
</div>

Card

article

Flexible container with border, padding, shadow, and optional badge. Works as article, div, or section.

New

Reusable patterns

Build once, use across projects with consistent spacing.

Read more →
Accessible

Clear defaults

Focus states and contrast built into every generated class.

Learn more →
Portable

Framework agnostic

Works wherever CSS loads. No runtime, no build lock-in.

See setup →
HTML
<article class="rounded-lg border border-neutral-20 p-6 shadow-sm">
  <span class="inline-flex items-center rounded-full
               bg-brand-10 px-3 py-1 text-xs font-semibold text-brand-90 mb-4">
    New
  </span>
  <h3 class="mb-2 text-base font-semibold text-neutral-90">Card title</h3>
  <p class="text-sm text-neutral-60 mb-4">Supporting description text.</p>
  <a href="#" class="text-sm font-semibold text-brand-80">Read more →</a>
</article>

Table

table

Responsive data table with striped header, row borders, and badge status cells. Wrap in overflow-x-auto for mobile.

Component Classes Status
Button bg, text, px, py, hover Pass
Alert border-l-4, bg, text Pass
Form border, ring, focus-visible Check
HTML
<div class="overflow-x-auto rounded-lg border border-neutral-20">
  <table class="w-full border-collapse text-sm">
    <thead>
      <tr class="bg-neutral-10 border-b border-neutral-20">
        <th class="text-left px-4 py-3 font-semibold text-neutral-80">Column</th>
        <th class="text-left px-4 py-3 font-semibold text-neutral-80">Column</th>
      </tr>
    </thead>
    <tbody>
      <tr class="border-b border-neutral-10">
        <td class="px-4 py-3 text-neutral-80">Cell</td>
        <td class="px-4 py-3 text-neutral-60">Cell</td>
      </tr>
    </tbody>
  </table>
</div>

Pagination

nav

Previous/next links and numbered pages. Active page uses brand colour. Add aria-current="page" to the current item.

HTML
<nav aria-label="Pagination" class="flex gap-2">
  <a href="#" class="inline-flex items-center justify-center rounded
                     border border-neutral-30 px-3 py-2 text-sm
                     hover:bg-neutral-10">
    Previous
  </a>
  <a href="#" aria-current="page"
     class="inline-flex items-center justify-center rounded
            bg-brand-80 px-3 py-2 text-sm font-semibold text-white">
    1
  </a>
  <a href="#" class="inline-flex items-center justify-center rounded
                     border border-neutral-30 px-3 py-2 text-sm
                     hover:bg-neutral-10">
    Next
  </a>
</nav>

Tabs

div

Tab bar with active underline indicator. Use role="tablist" and role="tab" for full keyboard and screen reader support.

Tab panel content goes here.
HTML
<div role="tablist" aria-label="Section tabs" class="flex gap-1 border-b border-neutral-20">
  <!-- Active tab -->
  <button role="tab" aria-selected="true"
          class="px-4 py-2.5 text-sm font-semibold text-brand-80
                 border-b-2 border-brand-80 -mb-px
                 focus-visible:ring-2">
    Overview
  </button>
  <!-- Inactive tab -->
  <button role="tab" aria-selected="false"
          class="px-4 py-2.5 text-sm text-neutral-60 hover:text-neutral-80
                 border-b-2 border-transparent -mb-px
                 focus-visible:ring-2">
    Usage
  </button>
</div>

Accordion

details

Collapsible section using native HTML details/summary. No JavaScript required. Screen readers announce open/closed state automatically.

What is emilyCSS?

A config-driven CSS utility system. Define tokens once, generate utilities, ship anywhere CSS loads.

Does it need a build step in production?

No. You run the build once locally. The output is a static CSS file you link with a tag — no runtime required.

Can I use it with Vue or Nuxt?

Yes. Link the generated CSS in your Nuxt config or import it in your app entry. The utility classes work identically in any framework.

HTML
<details class="rounded-lg border border-neutral-20 overflow-hidden">
  <summary class="cursor-pointer px-5 py-4 text-sm font-semibold text-neutral-80
                  hover:bg-neutral-10 list-none flex items-center justify-between">
    Accordion heading
    <span aria-hidden="true" class="text-neutral-40">+</span>
  </summary>
  <p class="border-t border-neutral-10 px-5 py-4 text-sm text-neutral-60">
    Accordion body content.
  </p>
</details>

Progress

div

Visual progress indicator. Use the native progress element for proper accessibility, or provide role="progressbar" with aria-valuenow/min/max.

CSS generated 75%
CSS purged 97%
HTML
<div class="flex items-center justify-between mb-2">
  <span class="text-sm font-medium text-neutral-80">Label</span>
  <span class="text-sm font-semibold text-brand-80">75%</span>
</div>
<div class="h-3 rounded-full bg-neutral-20 overflow-hidden"
     role="progressbar"
     aria-valuenow="75" aria-valuemin="0" aria-valuemax="100"
     aria-label="Progress label">
  <div class="h-full rounded-full bg-brand-80 transition"
       style="width: 75%">
  </div>
</div>