Default

Simple form with labeled fields and descriptions.

This is your public display name.

You can manage email addresses in your settings.

You can @mention other users and organizations.

<form class="form">
  <div class="form-field">
    <label class="label" for="name">Username</label>
    <input class="input" type="text" id="name" required>
    <p class="field-description">This is your public display name.</p>
  </div>
  <div class="form-field">
    <label class="label" for="email">Email</label>
    <input class="input" type="email" id="email" required>
    <p class="field-description">You can manage email addresses in your settings.</p>
  </div>
  <div class="form-field">
    <label class="label" for="bio">Bio</label>
    <textarea class="textarea" id="bio"></textarea>
    <p class="field-description">You can @mention other users and organizations.</p>
  </div>
  <div class="form-actions">
    <button class="btn" type="submit" data-variant="default">Submit</button>
    <button class="btn" type="reset" data-variant="outline">Reset</button>
  </div>
</form>

Inline fields

Checkbox and switch aligned with labels.

<div class="form-field-inline">
  <input class="checkbox" type="checkbox" id="terms">
  <label for="terms">Accept terms and conditions</label>
</div>
<div class="form-field-inline">
  <input class="switch" type="checkbox" role="switch" id="news">
  <label for="news">Subscribe to newsletter</label>
</div>

Switch rows (notifications)

Notification-style rows with label, description, and switch.

Receive emails about new products, features, and more.

Receive emails about your account security.

<div class="form-field-row">
  <div>
    <label class="label" for="marketing">Marketing emails</label>
    <p class="field-description">Receive emails about new products, features, and more.</p>
  </div>
  <input class="switch" type="checkbox" role="switch" id="marketing">
</div>
<div class="form-field-row">
  <div>
    <label class="label" for="security">Security emails</label>
    <p class="field-description">Receive emails about your account security.</p>
  </div>
  <input class="switch" type="checkbox" role="switch" id="security" checked disabled>
</div>

Fieldset grouping

Group related fields with <fieldset> and <legend>.

Notify me about...
<fieldset class="form-fieldset">
  <legend>Notify me about...</legend>
  <div class="form-group">
    <div class="form-field-inline">
      <input class="radio" type="radio" name="notify" id="all" checked>
      <label for="all">All new messages</label>
    </div>
    <div class="form-field-inline">
      <input class="radio" type="radio" name="notify" id="direct">
      <label for="direct">Direct messages and mentions</label>
    </div>
    <div class="form-field-inline">
      <input class="radio" type="radio" name="notify" id="none">
      <label for="none">Nothing</label>
    </div>
  </div>
</fieldset>

Horizontal layout

Label placed beside the control with data-orientation="horizontal".

Your full name for identification.

<div class="form-field" data-orientation="horizontal">
  <label class="label" for="name">Name</label>
  <div>
    <input class="input" type="text" id="name">
    <p class="field-description">Your full name for identification.</p>
  </div>
</div>

Validation with errors

Fields with data-invalid and aria-invalid for error states.

Optional message.

<div class="form-field" data-invalid>
  <label class="label" for="user">Username</label>
  <input class="input" type="text" id="user"
    aria-invalid="true" aria-describedby="user-err">
  <p class="field-error" id="user-err" role="alert">
    Username must be at least 3 characters.
  </p>
</div>

Full composition

Comprehensive form composing multiple field types.

This is your public display name.

You can manage email addresses in your settings.

You can @mention other users and organizations.

Your date of birth is used to calculate your age.

Notify me about...

Receive emails about new products, features, and more.

Receive emails about your account security.

<form class="form">
  <div class="form-field">
    <label class="label" for="name">Username</label>
    <input class="input" type="text" id="name" required>
    <p class="field-description">This is your public display name.</p>
  </div>
  <div class="form-field">
    <label class="label" for="email">Email</label>
    <select class="select" id="email">
      <option>m@example.com</option>
    </select>
  </div>
  <fieldset class="form-fieldset">
    <legend>Notify me about...</legend>
    <div class="form-group">
      <div class="form-field-inline">
        <input class="radio" type="radio" name="notify" id="all" checked>
        <label for="all">All new messages</label>
      </div>
    </div>
  </fieldset>
  <div class="form-field-row">
    <div>
      <label class="label" for="marketing">Marketing emails</label>
      <p class="field-description">Receive emails about new products.</p>
    </div>
    <input class="switch" type="checkbox" role="switch" id="marketing">
  </div>
  <div class="form-actions">
    <button class="btn" type="submit">Submit</button>
  </div>
</form>

CSS view file

/* -- Form component --------------------------------------------- */

@layer components {
  .form {
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
  }

  /* -- Form field -------------------------------------------- */
  .form-field {
    display: flex;
    flex-direction: column;
    gap: 0;

    /* -- Horizontal orientation (label beside control) ------- */
    &[data-orientation="horizontal"] {
      flex-direction: row;
      align-items: start;
      gap: 1rem;

      & > .label {
        margin-bottom: 0;
        padding-top: 0.5rem;
        min-width: 8rem;
        flex-shrink: 0;
      }
    }

    /* -- Invalid state -------------------------------------- */
    &[data-invalid] {
      & > .field-description {
        color: var(--destructive);
      }
    }
  }

  /* -- Inline field (checkbox, switch, radio inline) -------- */
  .form-field-inline {
    display: flex;
    align-items: center;
    gap: 0.5rem;

    & > .label {
      margin-bottom: 0;
    }
  }

  /* -- Notification / switch row layout --------------------- */
  .form-field-row {
    display: flex;
    flex-direction: row;
    align-items: start;
    justify-content: space-between;
    gap: 1rem;
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 1rem;
    box-shadow: var(--shadow-xs);

    & > div {
      display: flex;
      flex-direction: column;
      gap: 0.125rem;
    }

    & > div > .label {
      margin-bottom: 0;
      line-height: 1.4;
    }

    & > div > .field-description {
      margin: 0;
    }

    &[data-disabled] {
      opacity: 0.6;
    }
  }

  /* -- Button actions row ----------------------------------- */
  .form-actions {
    display: flex;
    gap: 0.5rem;
    align-items: center;
    padding-top: 0.5rem;
  }

  /* -- Fieldset --------------------------------------------- */
  .form-fieldset {
    border: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: 1rem;

    & > legend {
      font-size: 0.875rem;
      font-weight: 500;
      font-family: var(--font-sans);
      color: var(--foreground);
      padding: 0;
      margin-bottom: 0.25rem;
    }

    & > .field-description {
      margin: -0.25rem 0 0.5rem;
    }
  }

  /* -- Form group (vertical stack of fields) ---------------- */
  .form-group {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
  }

  /* -- Accessibility ---------------------------------------- */
  @media (prefers-contrast: more) {
    .form-field-row {
      border-width: 2px;
    }
  }

  @media (forced-colors: active) {
    .form-field-row {
      border-color: ButtonBorder;
    }

    .form-fieldset > legend {
      color: LinkText;
    }
  }
}