Forms

Wrap a control in a <label> and it is styled. No classes for the common cases.

Text inputs

<label>Name <input type="text" placeholder="Jane Doe" /></label>
<label>Email <input type="email" placeholder="jane@example.com" /></label>
<label>Password <input type="password" placeholder="••••••••" /></label>
<label>Phone <input type="tel" placeholder="503-555-0100" /></label>
<label>Website <input type="url" placeholder="https://example.com" /></label>
<label>Search <input type="search" placeholder="Search" /></label>
<label>Quantity <input type="number" value="1" min="0" /></label>

Label structure

A bare text node in the label works. Wrapping it in <p> gives you a block you can style, and it is what the invalid-state selector keys off of.

<label>
  <p>Birth date</p>
  <input type="date" />
</label>
<label>
  <p>Reminder</p>
  <input type="time" />
</label>

Date, time, and select controls get an icon from --icon-calendar, --icon-clock, and --icon-chevron. Each is an inline base64 SVG that swaps between a black and white stroke with the color scheme. Size and inset come from --icon-width and --icon-position.

Select and textarea

<label>
  Role
  <select>
    <option value="">Select a role</option>
    <option>Developer</option>
    <option>Designer</option>
    <option>Project manager</option>
  </select>
</label>

<label>
  Bio
  <textarea placeholder="Tell us about yourself"></textarea>
</label>

Checkboxes and radios

Put the control inside the label, before the text.

<label><input type="checkbox" /> Subscribe to updates</label>
<label><input type="checkbox" checked /> Already subscribed</label>

<label><input type="radio" name="plan" checked /> Free plan</label>
<label><input type="radio" name="plan" /> Pro plan</label>

Helper text

A <small> immediately after a control collapses the control's bottom margin and becomes helper text at --text-lc-3.

<label>
  Username
  <input type="text" />
  <small>Letters, numbers, and underscores only.</small>
</label>

Validation

Set aria-invalid="true" on the control. The label's <p> and the control both pick up --error-color. Pair it with small.error.

<label>
  <p>Username</p>
  <input type="text" value="taken_username" aria-invalid="true" />
  <small class="error">This username is already taken.</small>
</label>

<label>
  <p>Password</p>
  <input type="password" aria-invalid="true" />
  <small class="error">Must be at least 8 characters.</small>
</label>

Disabled and readonly

<label>
  Locked field
  <input type="text" value="Cannot edit" disabled />
</label>
<label>
  Read only
  <input type="text" value="Can select, cannot edit" readonly />
</label>

Fieldsets

Contact info
<fieldset>
  <legend>Contact info</legend>
  <label>Name <input type="text" /></label>
  <label>Email <input type="email" /></label>
</fieldset>

Kitchen sink

Everything above, in one realistic form.

Contact info
Preferences
<form>
  <fieldset>
    <legend>Contact info</legend>
    <label>Name <input type="text" placeholder="Jane Doe" /></label>
    <label>Email <input type="email" placeholder="jane@example.com" /></label>
    <label>
      <p>Phone</p>
      <input type="tel" aria-invalid="true" />
      <small class="error">Enter a valid phone number.</small>
    </label>
  </fieldset>

  <fieldset>
    <legend>Preferences</legend>
    <label>
      Favorite language
      <select>
        <option>TypeScript</option>
        <option>Go</option>
        <option>CSS</option>
      </select>
    </label>
    <label><input type="checkbox" /> Send me updates</label>
    <label><input type="radio" name="tier" checked /> Free</label>
    <label><input type="radio" name="tier" /> Pro</label>
  </fieldset>

  <label>
    Message
    <textarea></textarea>
    <small>Markdown is supported.</small>
  </label>

  <div class="flex">
    <button type="reset" class="secondary">Reset</button>
    <button type="submit">Submit</button>
  </div>
</form>