Components
Form
A way to build structured forms.
Usage
<form class="form"> <fieldset class="fieldset"> <legend><!-- --></legend> <p class="field-description"><!-- --></p>
<div class="field-group" role="group"> <!-- form fields --> </div>
<div class="field-group" role="group"> <!-- form fields --> </div> </fieldset></form>
<!-- or -->
<div class="form"> <div class="fieldset"> <p class="legend"><!-- --></p> <p class="field-description"><!-- --></p>
<div class="field-group" role="group"> <!-- form fields --> </div> <div class="field-group" role="group"> <!-- form fields --> </div> </div></div>Non-semantic elements
Sometimes you can't use semantic form elements like <fieldset> and <legend>. Replace them with <div role="group"> paired with a <span class="legend"> (or any heading)
to keep the visual treatment without the native semantics.
Fieldset
Used to show a relationship between form elements.
-
<legend> - to describe what it's about.
-
.field-description(optional) - to give extra context about the fieldset.
-
.field-group - groups related fields.
<fieldset class="fieldset"> <legend>Favorite Pet</legend> <p class="field-description">Please select your favorite type of pet.</p> <div class="field-group" role="group"> <label class="radio"> <input name="pet" type="radio" value="dog" /> <span class="label">Dog</span> </label> <label class="radio"> <input name="pet" type="radio" value="cat" /> <span class="label">Cat</span> </label> <label class="radio"> <input name="pet" type="radio" value="hamster" /> <span class="label">Hamster</span> </label> </div></fieldset>Required
<fieldset class="fieldset"> <legend>Pet info</legend> <p class="field-description">We must know your pet's information.</p> <div class="field-group" role="group"> <label class="text-field"> <span class="label">Name</span> <input type="text" name="name"> </label> <label class="textarea"> <span class="label">Life story</span> <textarea name="bio" required></textarea> </label> </div></fieldset>Disabled
Turns out you can disable an entire fieldset.
<fieldset class="fieldset" disabled> <legend>Pet dating</legend> <p class="field-description">You can't change these settings</p> <div class="field-group" role="group"> <label class="checkbox"> <input checked name="notifications" type="checkbox" value="horse-tinder" /> <span class="label">Horse Tinder</span> </label> <label class="checkbox"> <input name="notifications" type="checkbox" value="onlyhorsefans" checked /> <span class="label">OnlyHorseFans</span> </label> </div></fieldset>Field Legend
Use FieldLegend (or <legend>) to describe
the fieldset.
<fieldset class="fieldset"> <legend>Legend</legend></fieldset>Field Description
Use FieldDescription (or .field-description) to
give extra context about the fieldset.
<fieldset class="fieldset"> <legend>Legend</legend> <p class="field-description">This is a field description.</p></fieldset>Field Group
Use .field-group to wrap related fields.
<form class="form"> <fieldset class="fieldset"> <legend>Choose your favorite Radiohead album</legend> <p class="field-description">There are no wrong answers.</p> <div class="field-group" role="group"> <label class="radio"> <input type="radio" name="albums" value="ok-computer"> <span class="label">OK Computer</span> </label> <label class="radio"> <input type="radio" name="albums" value="kid-a"> <span class="label">Kid A</span> </label> <label class="radio"> <input type="radio" name="albums" value="in-rainbows"> <span class="label">In Rainbows</span> </label> <label class="radio"> <input type="radio" name="albums" value="the-king-of-limbs"> <span class="label">The King of Limbs</span> </label> </div> </fieldset>
<fieldset class="fieldset"> <legend>Which side projects do you follow?</legend> <p class="field-description">Some are better than others.</p> <div class="field-group" role="group"> <label class="checkbox"> <input type="checkbox" name="projects" value="the-smile"> <span class="label">The Smile</span> <span class="end-text">Thom Yorke, Jonny Greenwood, Tom Skinner</span> </label> <label class="checkbox"> <input type="checkbox" name="projects" value="atoms-for-peace"> <span class="label">Atoms for Peace</span> <span class="end-text">Thom Yorke, Flea, Nigel Godrich</span> </label> <label class="checkbox"> <input type="checkbox" name="projects" value="eob"> <span class="label">EOB</span> <span class="end-text">Ed O'Brien solo</span> </label> <label class="checkbox"> <input type="checkbox" name="projects" value="jonny-scores"> <span class="label">Film Scores</span> <span class="end-text">Film compositions by Jonny Greenwood</span> </label> <label class="checkbox"> <input type="checkbox" name="projects" value="selway-solo"> <span class="label">Philip Selway</span> <span class="end-text">Philip Selway solo albums</span> </label> </div> </fieldset></form>Row
Use the .row class to lay out fields horizontally.
<form class="form"> <fieldset class="fieldset"> <legend>Options</legend> <div class="field-group row"> <label class="checkbox"> <input type="checkbox" /> <span class="label">Option 1</span> </label> <label class="checkbox"> <input type="checkbox" /> <span class="label">Option 2</span> </label> <label class="checkbox"> <input type="checkbox" /> <span class="label">Option 3</span> </label> </div> </fieldset></form>Divider
Use a <hr /> to create a visual break between sections
of your form.
<form class="form"> <fieldset class="fieldset"> <legend>Post Content</legend> <div class="field-group" role="group"> <label class="text-field"> <span class="label">Title</span> <input type="text" placeholder="My new post" /> </label> </div> </fieldset>
<hr class="divider" />
<div class="field-group" role="group"> <button class="button filled">Publish</button> </div></form>Kitchen Sink
Everything all at once.
<form class="form" id="kitchen-sink-example-html"> <fieldset class="fieldset"> <legend>User Profile</legend> <p class="field-description">Please provide your basic contact details.</p> <div class="field-group" role="group"> <label class="text-field"> <span class="label">Full Name</span> <input type="text" placeholder="Jane Doe" required /> </label> <label class="text-field"> <span class="label">Email Address</span> <input type="email" placeholder="jane@example.com" required /> </label> <label class="select"> <span class="label">Role</span> <select> <button> <selectedcontent></selectedcontent> </button> <div class="list"> <option value="dev">Developer</option> <option value="design">Designer</option> <option value="manager">Manager</option> </div> </select> </label> </div> </fieldset>
<hr />
<fieldset class="fieldset"> <legend>Notifications</legend> <p class="field-description">Configure how you want to receive updates.</p> <div class="field-group" role="group"> <label class="switch"> <input type="checkbox" role="switch" name="email_notifs" checked /> <span class="label">Email Notifications</span> </label> <label class="switch"> <input type="checkbox" role="switch" name="sms_notifs" /> <span class="label">SMS Notifications</span> </label> </div> </fieldset>
<hr />
<fieldset class="fieldset"> <legend>Theme Preference</legend> <p class="field-description">Select your preferred visual style.</p> <div class="field-group"> <label class="radio"> <input type="radio" name="theme" value="light" checked /> <span class="label">Light Theme</span> </label> <label class="radio"> <input type="radio" name="theme" value="dark" /> <span class="label">Dark Theme</span> </label> <label class="radio"> <input type="radio" name="theme" value="system" /> <span class="label">System Default</span> </label> </div> </fieldset>
<hr />
<fieldset class="fieldset"> <legend>Experience Level</legend> <p class="field-description">How many years of experience do you have?</p> <div class="field-group" role="group"> <label class="range"> <span class="label">Professional Experience</span> <span class="start-text" >Drag the slider to match your total tenure.</span > <input type="range" min="0" max="20" step="1" value="5" /> </label> </div> </fieldset>
<hr />
<fieldset class="fieldset"> <legend>Additional Info</legend> <p class="field-description">Anything else we should know?</p> <div class="field-group" role="group"> <label class="textarea"> <span class="label">Biography</span> <textarea placeholder="Tell us about yourself..." rows="4"></textarea> </label> </div> </fieldset>
<hr />
<fieldset class="fieldset"> <legend>Legal</legend> <div class="field-group" role="group"> <label class="checkbox"> <input type="checkbox" name="terms" required /> <span class="label">I agree to the terms and conditions</span> <span class="end-text">Support this text</span> </label> </div> </fieldset>
<hr />
<div class="field-group" role="group"> <button class="button filled" type="submit">Send</button> <button class="button">Cancel</button> </div></form>Row
Everything all at once, but horizontally.
<form class="form" id="kitchen-sink-example-row-html"> <fieldset class="fieldset"> <legend>User Profile</legend> <p class="field-description">Please provide your basic contact details.</p> <div class="field-group" role="group"> <label class="text-field spread"> <span class="label">Full Name</span> <input type="text" placeholder="Jane Doe" required /> </label> <label class="text-field spread"> <span class="label">Email Address</span> <input type="email" placeholder="jane@example.com" required /> </label> <label class="select spread"> <span class="label">Role</span> <select> <button> <selectedcontent></selectedcontent> </button> <div class="list"> <option value="dev">Developer</option> <option value="design">Designer</option> <option value="manager">Manager</option> </div> </select> </label> </div> </fieldset>
<hr />
<fieldset class="fieldset"> <legend>Notifications</legend> <p class="field-description">Configure how you want to receive updates.</p> <div class="field-group" role="group"> <label class="switch spread"> <input type="checkbox" role="switch" name="email_notifs" checked /> <span class="label">Email Notifications</span> </label> <label class="switch spread"> <input type="checkbox" role="switch" name="sms_notifs" /> <span class="label">SMS Notifications</span> </label> </div> </fieldset>
<hr />
<fieldset class="fieldset"> <legend>Theme Preference</legend> <p class="field-description">Select your preferred visual style.</p> <div class="field-group row"> <label class="radio"> <input type="radio" name="theme" value="light" checked /> <span class="label">Light Theme</span> </label> <label class="radio"> <input type="radio" name="theme" value="dark" /> <span class="label">Dark Theme</span> </label> <label class="radio"> <input type="radio" name="theme" value="system" /> <span class="label">System Default</span> </label> </div> </fieldset>
<hr />
<fieldset class="fieldset"> <legend>Experience Level</legend> <p class="field-description">How many years of experience do you have?</p> <div class="field-group" role="group"> <label class="range spread"> <span class="label">Professional Experience</span> <span class="start-text" >Drag the slider to match your total tenure.</span > <input type="range" min="0" max="20" step="1" value="5" /> </label> </div> </fieldset>
<hr />
<fieldset class="fieldset"> <legend>Additional Info</legend> <p class="field-description">Anything else we should know?</p> <div class="field-group" role="group"> <label class="textarea spread"> <span class="label">Biography</span> <textarea placeholder="Tell us about yourself..." rows="4"></textarea> </label> </div> </fieldset>
<hr />
<fieldset class="fieldset"> <legend>Legal</legend> <div class="field-group" role="group"> <label class="checkbox spread"> <input type="checkbox" name="terms" required /> <span class="label">I agree to the terms and conditions</span> <span class="end-text">Support this text</span> </label> </div> </fieldset>
<hr />
<div class="field-group" role="group"> <button class="button filled" type="submit">Send</button> <button class="button">Cancel</button> </div></form>API
Form
| Type | Modifiers | Default | Description |
|---|---|---|---|
| Base | .form | - | The main form container. |
FieldSet
| Type | Modifiers | Default | Description |
|---|---|---|---|
| Base | .fieldset | - | The field set container. |
| Modifiers | [disabled] | - | Whether the field set is disabled. |
FieldLegend
| Type | Modifiers | Default | Description |
|---|---|---|---|
| Base | .legend, legend | - | The label for the field set. |
Field description
| Type | Modifiers | Default | Description |
|---|---|---|---|
| Base | .field-description | - | Field description for the field set. |
FieldGroup
| Type | Modifiers | Default | Description |
|---|---|---|---|
| Base | .field-group | - | Container for related input components. |
| Variants | .row, default | - | The orientation of the field group. |
Browser support
See also the full browser support guide.
Installation
This doesn't include all the styles for all form elements, just the scaffolding around them.
See also
@layer components.extended {
/* Form */ :where(.form) { display: grid; gap: var(--size-8);
hr { margin-block: 0; } }
/* Fieldset */ :where(.fieldset) { all: unset; border: 0; border-radius: 0; display: grid; gap: var(--size-1); margin: 0; min-inline-size: 0; padding: 0;
/* Legend */ :where(legend, .legend) { all: unset; color: var(--text-primary); font-weight: 600; margin-block-end: var(--size-3); padding: 0;
&:has(+ :where(.field-description)) { margin-block-end: 0; } }
/* Field description / supporting text */ :where(.field-description) { color: var(--text-muted); font-size: var(--font-size-05); line-height: var(--font-lineheight-3);
&:has(+ *) { margin-block-end: var(--size-3); } }
/* End text */ :where(.end-text) { color: var(--text-muted); font-size: var(--font-size-0); line-height: var(--font-lineheight-3); }
&:has(.text-field.row) { row-gap: var(--size-7); }
/* Disabled */ &[disabled] { opacity: 0.64; user-select: none;
input, label, .label { cursor: not-allowed; } }
/* Error / validation */ &[data-invalid] { :where(.end-text) { color: var(--primary); }
:where(.checkbox, .radio, .switch) { --palette-source: oklch(0.58 0.21 var(--hue-red));
:where(.end-text) { color: var(--primary); } }
:where(.switch) { input { border-radius: var(--radius-round); outline: 2px solid var(--primary); } } }
/* Required */ &:has(:invalid) { :where(legend, .legend) { padding-inline-end: 1ex; position: relative;
&::after { color: var(--red); content: "*"; inset: 0 -0.25ex auto auto; position: absolute; } } } }
/* Field group */ :where(.field-group) { display: flex; flex-direction: column; gap: var(--size-4);
/* If it only has checkboxes, radios, or switches */ &:has(> :where(.checkbox, .radio, .switch)):not(:has(> :not(.checkbox, .radio, .switch))) { gap: var(--size-2); }
/* If it only has buttons */ &:has(.button):not(:has(*:not(.button))) { align-items: center; flex-direction: row; gap: var(--size-2);
/* If it's not preceeded by an hr */ &:not(hr + &) { margin-block-start: var(--size-4); } }
&+& { margin-block-start: var(--size-5); }
/* Directions */ &.row { flex-direction: row; flex-wrap: wrap;
&:has(> :where(.checkbox, .radio, .switch)) { gap: var(--size-4); } } }}