Theme
On this page (9)
Component Skill — components/form/component-skill.md

Native basis

<form> element with consistent field layout using Label, Input, and description/error helpers. Composes with all form control components.

Web Platform APIs

<form><fieldset>Constraint Validation API:user-valid / :user-invalidaria-describedbyFormData

Classes

.form.form-field.form-field-inline.form-field-row.form-actions.form-fieldset.form-group

Data attributes

data-orientation="horizontal"On .form-field - places label beside controldata-invalidOn .form-field - marks field as invalid, description turns destructivedata-disabledOn .form-field-row - reduces row opacity

Notes

• .form-field provides consistent vertical spacing between fields.

• .form-field-inline aligns checkbox/switch/radio horizontally with their label.

• .form-field-row creates a card-like row for notification-style switch items.

• .form-fieldset styles native <fieldset> with legend and description.

• No JavaScript needed for basic forms - use native Constraint Validation.

• Compose with Label, Input, Textarea, Select, Checkbox, Radio, Switch, Slider, etc.

§Default

Simple form with labeled fields and descriptions.

§Consistent field heights

Every field control renders the same box height for the same data-size - the Input ladder is the standard (40 / 28 / 32 / 36 / 44 / 52px for default / xs / sm / md / lg / xl), so mixed fields sit on one baseline. The rows below use the shipped grid helpers (grid + grid-cols-4 + gap-4) directly.

§Inline fields

Checkbox and switch aligned with labels.

§Switch rows (notifications)

Notification-style rows with label, description, and switch - stacked in a .form-group for the gap between them.

§Fieldset grouping

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

§Horizontal layout

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

§Validation with errors

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

§Full composition

Comprehensive form composing multiple field types.

§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;
    }
  }
}

Comments, ideas or improvements? Edit this page's source on GitHub