78 UI Kit
Components

Forms

Text entry, and the wrapper that gives it a label, a hint and an error. Every control shares one focus treatment — an accent border plus a --ring-w ring in --ring — so a form looks like one thing. Checkboxes, radios and the toggle switch are on Selection controls.

The field

_78-field wraps a label, a control and an optional hint or error, and supplies the spacing between fields. A <label> directly inside it is styled automatically.

Click into it — accent border plus the focus ring.
field
<div class="_78-field">
  <label for="f-1">Workspace name</label>
  <input class="_78-input" id="f-1" type="text" placeholder="Acme Design">
  <div class="_78-field-hint">Click into it &mdash; accent border plus the focus ring.</div>
</div>

Labels outside a field

_78-label is the same label styling as a standalone class, for a label that is not a direct child of _78-field — a label above a group, or one inside your own layout.

_78-label
<span class="_78-label" id="notify-label">Notify me about</span>
<div role="group" aria-labelledby="notify-label">
  <label class="_78-check"><input type="checkbox"> Mentions</label>
  <label class="_78-check"><input type="checkbox"> Replies</label>
</div>

Rows

_78-field-row puts fields side by side, each flexing from a 180px basis, so they stack on their own on a narrow screen.

field row
<div class="_78-field-row">
  <div class="_78-field">
    <label for="f-2">Plan</label>
    <select class="_78-select" id="f-2">
      <option>Starter</option><option>Team</option><option>Enterprise</option>
    </select>
  </div>
  <div class="_78-field">
    <label for="f-3">Seats</label>
    <input class="_78-input" id="f-3" type="number" value="24" step="1">
  </div>
</div>

Inline form

Some forms are one field and a button: dismiss with a reason, add a row, a quick filter. _78-form-inline puts them on one row with their bottoms aligned, so the button sits level with the input under its label. Fields flex from a 180px basis and drop their bottom margin; buttons, checkboxes and switches keep their size. On a phone the row wraps.

Its natural home is a card foot, which already gives it the padding and the rule above — no classes of your own:

Northwind

Watched since Sep 14 for a renewal at the new price.

a form in a card foot
<div class="_78-card">
  <div class="_78-card-title">Northwind</div>
  <p class="_78-text-dim">Watched since Sep 14 for a renewal at the new price.</p>
  <div class="_78-card-foot">
    <form class="_78-form-inline">
      <div class="_78-field">
        <label for="dismiss-why">Why (optional)</label>
        <input class="_78-input" id="dismiss-why" name="reason" maxlength="500" autocomplete="off">
      </div>
      <button class="_78-btn" type="submit">Dismiss</button>
    </form>
  </div>
</div>
_78-form-inline with a checkbox
<form class="_78-form-inline">
  <div class="_78-field">
    <label for="add-name">Name</label>
    <input class="_78-input" id="add-name" placeholder="Account name">
  </div>
  <label class="_78-check"><input type="checkbox"> Notify me</label>
  <button class="_78-btn _78-btn-primary" type="submit">Add</button>
</form>
ClassWhat it does
_78-form-inlineA wrapping flex row, bottoms aligned, --space-3 apart.
> _78-fieldFlexes from 180px; no bottom margin.
> _78-btn, _78-btn-groupKeep their size, level with the input.
> _78-check, _78-switchKeep their size, centered on the input's line.

Put a hint or an error after the form, not inside a field: a line under one input pushes the button out of line with it.

Controls

Three control classes cover the native inputs. They share hover, focus and disabled treatments.

controls
<div class="site-demo-block">
  <div class="_78-field">
    <label for="f-4">Text input</label>
    <input class="_78-input" id="f-4" type="text" placeholder="Placeholder text">
  </div>
  <div class="_78-field">
    <label for="f-5">Select</label>
    <select class="_78-select" id="f-5"><option>Choose one</option><option>Or the other</option></select>
  </div>
  <div class="_78-field">
    <label for="f-6">Textarea</label>
    <textarea class="_78-textarea" id="f-6" placeholder="Anything the team should know…"></textarea>
  </div>
  <div class="_78-field">
    <label for="f-7">Disabled</label>
    <input class="_78-input" id="f-7" type="text" value="Locked by your plan" disabled>
  </div>
</div>

Validation

Two ways to mark a control invalid, and they are not equivalent. aria-invalid="true" is the one to reach for: it colors the border and tells assistive technology the value is rejected. _78-invalid is the class-only fallback for when you cannot set the attribute — it looks identical but says nothing to a screen reader.

Either way, point at the message with aria-describedby so it is announced with the field rather than sitting there unread.

Must be a positive number.
Same look, but nothing is announced.
validation
<div class="site-demo-block">
  <div class="_78-field">
    <label for="f-8">Seats</label>
    <input class="_78-input" id="f-8" type="text" value="-4"
           aria-invalid="true" aria-describedby="f-8-err">
    <div class="_78-field-error" id="f-8-err">Must be a positive number.</div>
  </div>

  <div class="_78-field">
    <label for="f-9">Seats</label>
    <input class="_78-input _78-invalid" id="f-9" type="text" value="-4">
    <div class="_78-field-error">Same look, but nothing is announced.</div>
  </div>
</div>
Prefer the attribute
aria-invalid also drives the focus treatment, so an invalid field keeps its red border while focused instead of reverting to the accent.

Checkboxes, radios and the switch moved

This page is about entering a value. The controls that record a choice — _78-check for checkboxes and radios, and _78-switch for the toggle — are documented on Selection controls, with every variant and the same live examples.