Skip to main content

Theme config

Theme mode

Color palette

Grays

Border radii/radiuses/radiopedes/you know
Border radius
Field border radius
Button border radius
All
Components
Guides
API
Recent

Components

Form

A way to build structured forms.

Full support Supported since v105. Full support Supported since v121. Full support Supported since v15.4.

Usage

---
import { Form } from "@opui/astro"
import { FieldSet } from "@opui/astro"
import { FieldLegend } from "@opui/astro"
import { FieldGroup } from "@opui/astro"
import { FieldDescription } from "@opui/astro"
---
<Form>
<FieldSet>
<FieldLegend><!-- --></FieldLegend>
<FieldDescription><!-- --></FieldDescription>
<FieldGroup>
<!-- -->
</FieldGroup>
<FieldGroup>
<!-- -->
</FieldGroup>
</FieldSet>
</Form>

Non-semantic elements

Sometimes you can't use semantic form elements like <fieldset> and <legend>. Use the as prop on FieldSet and FieldLegend to render non-semantic alternatives.

<Form as="div">
<FieldSet as="div">
<FieldLegend as="p">Using as prop</FieldLegend>
<FieldDescription> Renders as div and p elements. </FieldDescription>
</FieldSet>
</Form>

Fieldset

Used to show a relationship between form elements.

FieldLegend

to describe what it's about.
FieldDescription(optional)

to give extra context about the fieldset.
FieldGroup

groups related fields.
Favorite Pet

Please select your favorite type of pet.

---
import { FieldSet } from "@opui/astro"
import { FieldLegend } from "@opui/astro"
import { FieldDescription } from "@opui/astro"
import { FieldGroup } from "@opui/astro"
import { Radio } from "@opui/astro"
---
<FieldSet>
<FieldLegend>Favorite Pet</FieldLegend>
<FieldDescription>Please select your favorite type of pet.</FieldDescription>
<FieldGroup name="pet">
<Radio value="dog">Dog</Radio>
<Radio value="cat">Cat</Radio>
<Radio value="hamster">Hamster</Radio>
</FieldGroup>
</FieldSet>
<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 type="radio" name="pet" value="dog" /><span class="label"
>Dog</span
>
</label>
<label class="radio">
<input type="radio" name="pet" value="cat" /><span class="label"
>Cat</span
>
</label>
<label class="radio">
<input type="radio" name="pet" value="hamster" /><span class="label"
>Hamster</span
>
</label>
</div>
</fieldset>

Required

Pet info

We must know your pet's information.

---
import { FieldSet } from "@opui/astro"
import { FieldLegend } from "@opui/astro"
import { FieldDescription } from "@opui/astro"
import { FieldGroup } from "@opui/astro"
import { Textarea } from "@opui/astro"
import { TextField } from "@opui/astro"
---
<FieldSet>
<FieldLegend>Pet info</FieldLegend>
<FieldDescription>We must know your pet's information.</FieldDescription>
<FieldGroup name="bio">
<TextField label="Name" />
<Textarea required label="Life story" />
</FieldGroup>
</FieldSet>
<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>
<span class="field">
<input id="text-field-2" name="bio" type="text" />
</span>
</label>
<label class="textarea">
<span class="label">Life story</span>
<span class="field">
<textarea id="textarea-1" name="bio" required></textarea>
</span>
</label>
</div>
</fieldset>

Disabled

Turns out you can disable an entire fieldset.

Pet dating

You can't change these settings

---
import { FieldSet } from "@opui/astro"
import { FieldLegend } from "@opui/astro"
import { FieldDescription } from "@opui/astro"
import { FieldGroup } from "@opui/astro"
import { Checkbox } from "@opui/astro"
---
<FieldSet disabled>
<FieldLegend>Pet dating</FieldLegend>
<FieldDescription>You can't change these settings</FieldDescription>
<FieldGroup name="notifications">
<Checkbox value="horse-tinder" checked>Horse Tinder</Checkbox>
<Checkbox value="onlyhorsefans" checked>OnlyHorseFans</Checkbox>
</FieldGroup>
</FieldSet>
<fieldset disabled class="fieldset">
<legend>Pet dating</legend>
<p class="field-description">You can't change these settings</p>
<div class="field-group" role="group">
<script type="module">
function e(t = document) {
t.querySelectorAll(
'input[type="checkbox"][data-indeterminate]',
).forEach((n) => {
n.indeterminate = !0;
});
}
function a() {
(e(), document.addEventListener("astro:after-swap", () => e()));
}
a();
</script>
<label class="checkbox">
<input
type="checkbox"
checked
name="notifications"
value="horse-tinder"
/><span class="label">Horse Tinder</span>
</label>
<label class="checkbox">
<input
type="checkbox"
checked
name="notifications"
value="onlyhorsefans"
/><span class="label">OnlyHorseFans</span>
</label>
</div>
</fieldset>

Field Legend

Use FieldLegend (or <legend>) to describe the fieldset.

Legend
---
import { FieldSet } from "@opui/astro"
import { FieldLegend } from "@opui/astro"
---
<FieldSet>
<FieldLegend>Legend</FieldLegend>
</FieldSet>
<fieldset class="fieldset"><legend>Legend</legend></fieldset>

Field Description

Use FieldDescription (or .field-description) to give extra context about the fieldset.

Legend

This is a field description.

---
import { FieldSet } from "@opui/astro"
import { FieldLegend } from "@opui/astro"
import { FieldDescription } from "@opui/astro"
---
<FieldSet>
<FieldLegend>Legend</FieldLegend>
<FieldDescription>This is a field description.</FieldDescription>
</FieldSet>
<fieldset class="fieldset">
<legend>Legend</legend>
<p class="field-description">This is a field description.</p>
</fieldset>

Field Group

Use FieldGroup to wrap related fields. It provides a shared name to all nested inputs.

Choose your favorite Radiohead album

There are no wrong answers.

Which side projects do you follow?

Some are better than others.

---
import { Checkbox } from "@opui/astro"
import { FieldDescription } from "@opui/astro"
import { FieldGroup } from "@opui/astro"
import { FieldLegend } from "@opui/astro"
import { FieldSet } from "@opui/astro"
import { Form } from "@opui/astro"
import { Radio } from "@opui/astro"
---
<Form>
<FieldSet>
<FieldLegend>Choose your favorite Radiohead album</FieldLegend>
<FieldDescription>There are no wrong answers.</FieldDescription>
<FieldGroup name="albums">
<Radio value="ok-computer">OK Computer</Radio>
<Radio value="kid-a">Kid A</Radio>
<Radio value="in-rainbows">In Rainbows</Radio>
<Radio value="king-of-limbs">The King of Limbs</Radio>
</FieldGroup>
</FieldSet>
<FieldSet>
<FieldLegend>Which side projects do you follow?</FieldLegend>
<FieldDescription>Some are better than others.</FieldDescription>
<FieldGroup name="projects">
<Checkbox value="the-smile">
The Smile
<Fragment slot="end-text"
>Thom Yorke, Jonny Greenwood, Tom Skinner</Fragment
>
</Checkbox>
<Checkbox value="atoms-for-peace">
Atoms for Peace
<Fragment slot="end-text">Thom Yorke, Flea, Nigel Godrich</Fragment>
</Checkbox>
<Checkbox value="eob">
EOB
<Fragment slot="end-text">Ed O'Brien solo</Fragment>
</Checkbox>
<Checkbox value="jonny-scores">
Film Scores
<Fragment slot="end-text">Film compositions by Jonny Greenwood</Fragment
>
</Checkbox>
<Checkbox value="selway-solo">
Philip Selway
<Fragment slot="end-text">Philip Selway solo albums</Fragment>
</Checkbox>
</FieldGroup>
</FieldSet>
</Form>
<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="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"
aria-describedby="end-text-1"
/><span class="label"> The Smile </span>
<span id="end-text-1" class="end-text"
>Thom Yorke, Jonny Greenwood, Tom Skinner</span
>
</label>
<label class="checkbox">
<input
type="checkbox"
name="projects"
value="atoms-for-peace"
aria-describedby="end-text-2"
/><span class="label"> Atoms for Peace </span>
<span id="end-text-2" class="end-text"
>Thom Yorke, Flea, Nigel Godrich</span
>
</label>
<label class="checkbox">
<input
type="checkbox"
name="projects"
value="eob"
aria-describedby="end-text-3"
/><span class="label"> EOB </span>
<span id="end-text-3" class="end-text">Ed O'Brien solo</span>
</label>
<label class="checkbox">
<input
type="checkbox"
name="projects"
value="jonny-scores"
aria-describedby="end-text-4"
/><span class="label"> Film Scores </span>
<span id="end-text-4" class="end-text"
>Film compositions by Jonny Greenwood</span
>
</label>
<label class="checkbox">
<input
type="checkbox"
name="projects"
value="selway-solo"
aria-describedby="end-text-5"
/><span class="label"> Philip Selway </span>
<span id="end-text-5" class="end-text">Philip Selway solo albums</span>
</label>
</div>
</fieldset>
</form>

Row

Use the direction="row" prop to lay out fields horizontally.

Options
---
import { Form } from "@opui/astro"
import { FieldSet } from "@opui/astro"
import { FieldLegend } from "@opui/astro"
import { FieldGroup } from "@opui/astro"
import { Checkbox } from "@opui/astro"
---
<Form>
<FieldSet>
<FieldLegend>Options</FieldLegend>
<FieldGroup direction="row">
<Checkbox>Option 1</Checkbox>
<Checkbox>Option 2</Checkbox>
<Checkbox>Option 3</Checkbox>
</FieldGroup>
</FieldSet>
</Form>
<form class="form">
<fieldset class="fieldset">
<legend>Options</legend>
<div class="field-group row" role="group">
<label class="checkbox">
<input type="checkbox" name="projects" /><span class="label"
>Option 1</span
>
</label>
<label class="checkbox">
<input type="checkbox" name="projects" /><span class="label"
>Option 2</span
>
</label>
<label class="checkbox">
<input type="checkbox" name="projects" /><span class="label"
>Option 3</span
>
</label>
</div>
</fieldset>
</form>

Divider

Use the Divider component to create a visual break between sections of your form.

Post Content

---
import { Form } from "@opui/astro"
import { FieldSet } from "@opui/astro"
import { FieldLegend } from "@opui/astro"
import { FieldGroup } from "@opui/astro"
import { TextField } from "@opui/astro"
import { Button } from "@opui/astro"
import { Divider } from "@opui/astro"
---
<Form>
<FieldSet>
<FieldLegend>Post Content</FieldLegend>
<FieldGroup>
<TextField label="Title" placeholder="My new post" />
</FieldGroup>
</FieldSet>
<Divider />
<FieldGroup>
<Button variant="filled">Publish</Button>
</FieldGroup>
</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>
<span class="field">
<input
id="text-field-3"
name="projects"
placeholder="My new post"
type="text"
/>
</span>
</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.

User Profile

Please provide your basic contact details.


Notifications

Configure how you want to receive updates.


Theme Preference

Select your preferred visual style.


Experience Level

How many years of experience do you have?


Additional Info

Anything else we should know?


Legal

---
import { Form } from "@opui/astro"
import { FieldSet } from "@opui/astro"
import { FieldLegend } from "@opui/astro"
import { FieldDescription } from "@opui/astro"
import { FieldGroup } from "@opui/astro"
import { TextField } from "@opui/astro"
import { Select } from "@opui/astro"
import { Switch } from "@opui/astro"
import { Radio } from "@opui/astro"
import { Textarea } from "@opui/astro"
import { Checkbox } from "@opui/astro"
import { Range } from "@opui/astro"
import { Button } from "@opui/astro"
import { Divider } from "@opui/astro"
---
<Form id="kitchen-sink-example">
<FieldSet>
<FieldLegend>User Profile</FieldLegend>
<FieldDescription>
Please provide your basic contact details.
</FieldDescription>
<FieldGroup>
<TextField label="Full Name" placeholder="Jane Doe" required />
<TextField
label="Email Address"
type="email"
placeholder="jane@example.com"
required
/>
<Select
label="Role"
items={[
{ text: "Developer", value: "dev" },
{ text: "Designer", value: "design" },
{ text: "Manager", value: "manager" },
]}
/>
</FieldGroup>
</FieldSet>
<Divider />
<FieldSet>
<FieldLegend>Notifications</FieldLegend>
<FieldDescription>
Configure how you want to receive updates.
</FieldDescription>
<FieldGroup name="notifications">
<Switch name="email_notifs" checked>Email Notifications</Switch>
<Switch name="sms_notifs">SMS Notifications</Switch>
</FieldGroup>
</FieldSet>
<Divider />
<FieldSet>
<FieldLegend>Theme Preference</FieldLegend>
<FieldDescription>Select your preferred visual style.</FieldDescription>
<FieldGroup name="theme">
<Radio value="light" checked>Light Theme</Radio>
<Radio value="dark">Dark Theme</Radio>
<Radio value="system">System Default</Radio>
</FieldGroup>
</FieldSet>
<Divider />
<FieldSet>
<FieldLegend>Experience Level</FieldLegend>
<FieldDescription
>How many years of experience do you have?</FieldDescription
>
<FieldGroup>
<Range
label="Professional Experience"
min="0"
max="20"
step="1"
value="5"
startText="Drag the slider to match your total tenure."
/>
</FieldGroup>
</FieldSet>
<Divider />
<FieldSet>
<FieldLegend>Additional Info</FieldLegend>
<FieldDescription>Anything else we should know?</FieldDescription>
<FieldGroup name="details">
<Textarea
label="Biography"
placeholder="Tell us about yourself..."
rows={4}
/>
</FieldGroup>
</FieldSet>
<Divider />
<FieldSet>
<FieldLegend>Legal</FieldLegend>
<FieldGroup name="legal">
<Checkbox name="terms" required>
I agree to the terms and conditions
<Fragment slot="end-text">Support this text</Fragment>
</Checkbox>
</FieldGroup>
</FieldSet>
<Divider />
<FieldGroup>
<Button variant="filled" type="submit">Send</Button>
<Button>Cancel</Button>
</FieldGroup>
</Form>
<form id="kitchen-sink-example" class="form"> <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> <span class="field"> <input id="text-field-4" name="projects" placeholder="Jane Doe" required type="text"> </span> </label> <label class="text-field"> <span class="label">Email Address</span> <span class="field"> <input id="text-field-5" name="projects" placeholder="jane@example.com" required type="email"> </span> </label> <label class="select"> <span class="label" id="select-label-3">Role</span> <span class="field"> <select aria-labelledby="select-label-3" id="select-3" name="projects"> <button> <selectedcontent> </button> <div class="list"> <option value="dev">Developer</option><option value="design">Designer</option><option value="manager">Manager</option> </div> </select> </span> </label> </div> </fieldset> <hr class="divider"> <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" checked name="email_notifs"><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 class="divider"> <fieldset class="fieldset"><legend>Theme Preference</legend><p class="field-description">Select your preferred visual style.</p> <div class="field-group" role="group"> <label class="radio"> <input type="radio" checked name="theme" value="light"><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 class="divider"> <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"><script type="module">for(const n of document.querySelectorAll(".range")){const t=n.querySelector('input[type="range"]'),e=n.querySelector(":scope > output.value");if(!t||!e)continue;const o=e.dataset.suffix??"",u=()=>{e.textContent=`${t.value}${o}`};t.addEventListener("input",u),u()}</script> <label class="range"> <span class="label" id="range-label-6">Professional Experience</span> <span class="start-text" id="range-start-1"> Drag the slider to match your total tenure. </span> <input aria-describedby="range-start-1" aria-labelledby="range-label-6" id="range-6" max="20" min="0" step="1" type="range" value="5"> </label> </div> </fieldset> <hr class="divider"> <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> <span class="field"> <textarea id="textarea-2" name="details" placeholder="Tell us about yourself..." rows="4"></textarea> </span> </label> </div> </fieldset> <hr class="divider"> <fieldset class="fieldset"><legend>Legal</legend> <div class="field-group" role="group"> <label class="checkbox"> <input type="checkbox" name="terms" required aria-describedby="end-text-6"><span class="label">
I agree to the terms and conditions
</span> <span id="end-text-6" class="end-text">Support this text</span> </label> </div> </fieldset> <hr class="divider"> <div class="field-group" role="group"><button type="submit" class="button filled">Send</button><button class="button">Cancel</button> </div> </form>

Row

Everything all at once, but horizontally.

User Profile

Please provide your basic contact details.


Notifications

Configure how you want to receive updates.


Theme Preference

Select your preferred visual style.


Experience Level

How many years of experience do you have?


Additional Info

Anything else we should know?


Legal

---
import {
Button,
Checkbox,
Divider,
FieldDescription,
FieldGroup,
FieldLegend,
FieldSet,
Form,
Radio,
Range,
Select,
Switch,
TextField,
Textarea,
} from "@opui/astro"
---
<Form id="kitchen-sink-example-row">
<FieldSet>
<FieldLegend>User Profile</FieldLegend>
<FieldDescription>
Please provide your basic contact details.
</FieldDescription>
<FieldGroup>
<TextField placeholder="Jane Doe" required spread>
<Fragment slot="label">Full Name</Fragment>
</TextField>
<TextField type="email" placeholder="jane@example.com" required spread>
<Fragment slot="label">Email Address</Fragment>
</TextField>
<Select
items={[
{ text: "Developer", value: "dev" },
{ text: "Designer", value: "design" },
{ text: "Manager", value: "manager" },
]}
spread
>
<Fragment slot="label">Role</Fragment>
</Select>
</FieldGroup>
</FieldSet>
<Divider />
<FieldSet>
<FieldLegend>Notifications</FieldLegend>
<FieldDescription>
Configure how you want to receive updates.
</FieldDescription>
<FieldGroup name="notifications">
<Switch name="email_notifs" checked spread>Email Notifications</Switch>
<Switch name="sms_notifs" spread>SMS Notifications</Switch>
</FieldGroup>
</FieldSet>
<Divider />
<FieldSet>
<FieldLegend>Theme Preference</FieldLegend>
<FieldDescription>Select your preferred visual style.</FieldDescription>
<FieldGroup direction="row" name="theme">
<Radio value="light" checked>Light Theme</Radio>
<Radio value="dark">Dark Theme</Radio>
<Radio value="system">System Default</Radio>
</FieldGroup>
</FieldSet>
<Divider />
<FieldSet>
<FieldLegend>Experience Level</FieldLegend>
<FieldDescription
>How many years of experience do you have?</FieldDescription
>
<FieldGroup>
<Range min="0" max="20" step="1" value="5" spread>
Professional Experience
<Fragment slot="start-text"
>Drag the slider to match your total tenure.</Fragment
>
</Range>
</FieldGroup>
</FieldSet>
<Divider />
<FieldSet>
<FieldLegend>Additional Info</FieldLegend>
<FieldDescription>Anything else we should know?</FieldDescription>
<FieldGroup name="details">
<Textarea placeholder="Tell us about yourself..." rows={4} spread>
<Fragment slot="label">Biography</Fragment>
</Textarea>
</FieldGroup>
</FieldSet>
<Divider />
<FieldSet>
<FieldLegend>Legal</FieldLegend>
<FieldGroup name="legal">
<Checkbox name="terms" required spread>
I agree to the terms and conditions
<Fragment slot="end-text">Support this text</Fragment>
</Checkbox>
</FieldGroup>
</FieldSet>
<Divider />
<FieldGroup>
<Button variant="filled" type="submit">Send</Button>
<Button>Cancel</Button>
</FieldGroup>
</Form>
<form id="kitchen-sink-example-row" class="form"> <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> <span class="field"> <input id="text-field-6" name="legal" placeholder="Jane Doe" required type="text"> </span> </label> <label class="text-field spread"> <span class="label">Email Address</span> <span class="field"> <input id="text-field-7" name="legal" placeholder="jane@example.com" required type="email"> </span> </label> <label class="select spread"> <span class="label" id="select-label-4">Role</span> <span class="field"> <select id="select-4" name="legal"> <button> <selectedcontent> </button> <div class="list"> <option value="dev">Developer</option><option value="design">Designer</option><option value="manager">Manager</option> </div> </select> </span> </label> </div> </fieldset> <hr class="divider"> <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" checked name="email_notifs"><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 class="divider"> <fieldset class="fieldset"><legend>Theme Preference</legend><p class="field-description">Select your preferred visual style.</p> <div class="field-group row" role="group"> <label class="radio"> <input type="radio" checked name="theme" value="light"><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 class="divider"> <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" id="range-label-7">
Professional Experience
</span> <span class="start-text" id="range-start-2"> Drag the slider to match your total tenure. </span> <input aria-describedby="range-start-2" aria-labelledby="range-label-7" id="range-7" max="20" min="0" step="1" type="range" value="5"> </label> </div> </fieldset> <hr class="divider"> <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> <span class="field"> <textarea id="textarea-3" name="details" placeholder="Tell us about yourself..." rows="4"></textarea> </span> </label> </div> </fieldset> <hr class="divider"> <fieldset class="fieldset"><legend>Legal</legend> <div class="field-group" role="group"> <label class="checkbox spread"> <input type="checkbox" name="terms" required aria-describedby="end-text-7"><span class="label">
I agree to the terms and conditions
</span> <span id="end-text-7" class="end-text">Support this text</span> </label> </div> </fieldset> <hr class="divider"> <div class="field-group" role="group"><button type="submit" class="button filled">Send</button><button class="button">Cancel</button> </div> </form>

API

Form

Prop Type Default Description
as string "form" The HTML element to render.

FieldSet

Prop Type Default Description
as "fieldset", "div" "fieldset" The HTML element to render.
disabled boolean - Whether the field set is disabled.

FieldLegend

Prop Type Default Description
as "legend", "p", "div", "span" "legend" The HTML element to render.

FieldDescription

Prop Type Default Description
- [key: string]: any - Field description for the field set. Accepts standard HTML attributes.

FieldGroup

Prop Type Default Description
name string - Shared name for nested input components.
direction "row", "column" - The orientation of the field group.

Browser support

Full support Supported since v105. Full support Supported since v121. Full support Supported since v15.4.

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