shadcn-html / form
Built with: CSS
Form
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.
Default
Simple form with labeled fields and descriptions.
<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.
<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>.
<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".
<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.
<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.
<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;
}
}
}