defuss-shadcn / Forms & Inputs / form
FormMOL
Consistent field layout for forms. Built on native <form> with .form-field spacing, .form-field-inline for checkbox/switch rows, .form-field-row for notification-style items, and .form-fieldset for grouped fields.
On this page (9)
§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