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

<script setup lang="ts">
import {
FieldDescription,
FieldGroup,
FieldLegend,
FieldSet,
Form,
} from "opui-css/vue"
</script>
<template>
<Form>
<FieldSet>
<FieldLegend><!-- --></FieldLegend>
<FieldDescription><!-- --></FieldDescription>
<FieldGroup>
<!-- -->
</FieldGroup>
<FieldGroup>
<!-- -->
</FieldGroup>
</FieldSet>
</Form>
</template>

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.

<script setup lang="ts">
import { FieldDescription, FieldLegend, FieldSet, Form } from "opui-css/vue"
</script>
<template>
<Form as="div">
<FieldSet as="div">
<FieldLegend as="p">Using as prop</FieldLegend>
<FieldDescription> Renders as div and p elements. </FieldDescription>
</FieldSet>
</Form>
</template>

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.

<script setup lang="ts">
import {
FieldDescription,
FieldGroup,
FieldLegend,
FieldSet,
Radio,
} from "opui-css/vue"
</script>
<template>
<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>
</template>
<fieldset class="ui-fieldset">
<!--[-->
<legend class=""><!--[-->Favorite Pet<!--]--></legend>
<p class="ui-field-description">
<!--[-->Please select your favorite type of pet.<!--]-->
</p>
<div class="ui-field-group" role="group">
<!--[--><label class="ui-radio"
><input type="radio" value="dog" aria-describedby="s0-0" /><span
class="ui-label"
><!--[-->Dog<!--]--></span
><!----></label
><label class="ui-radio"
><input type="radio" value="cat" aria-describedby="s0-1" /><span
class="ui-label"
><!--[-->Cat<!--]--></span
><!----></label
><label class="ui-radio"
><input type="radio" value="hamster" aria-describedby="s0-2" /><span
class="ui-label"
><!--[-->Hamster<!--]--></span
><!----></label
><!--]-->
</div>
<!--]-->
</fieldset>

Required

Pet info

We must know your pet's information.

<script setup lang="ts">
import {
FieldDescription,
FieldGroup,
FieldLegend,
FieldSet,
Textarea,
TextField,
} from "opui-css/vue"
</script>
<template>
<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>
</template>
<fieldset class="ui-fieldset">
<!--[-->
<legend class=""><!--[-->Pet info<!--]--></legend>
<p class="ui-field-description">
<!--[-->We must know your pet's information.<!--]-->
</p>
<div class="ui-field-group" role="group">
<!--[--><label class="ui-text-field"
><span class="ui-label"><!--[-->Name<!--]--></span
><!----><span class="ui-field"
><input id="s1-0" type="text" /><!----><!----><!----><!----></span
><!----><!--[--><!--]--></label
><label class="ui-textarea"
><span class="ui-label"><!--[-->Life story<!--]--></span
><!----><span class="ui-field">
<textarea id="s1-1" required></textarea
><!----><!----><!----><!----></span
><!----><!--[--><!--]--></label
><!--]-->
</div>
<!--]-->
</fieldset>

Disabled

Turns out you can disable an entire fieldset.

Pet dating

You can't change these settings

<script setup lang="ts">
import {
Checkbox,
FieldDescription,
FieldGroup,
FieldLegend,
FieldSet,
} from "opui-css/vue"
</script>
<template>
<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>
</template>
<fieldset class="ui-fieldset" disabled>
<!--[-->
<legend class=""><!--[-->Pet dating<!--]--></legend>
<p class="ui-field-description">
<!--[-->You can't change these settings<!--]-->
</p>
<div class="ui-field-group" role="group">
<!--[--><label class="ui-checkbox"
><input type="checkbox" value="horse-tinder" /><span class="ui-label"
><!--[-->Horse Tinder<!--]--></span
><!----></label
><label class="ui-checkbox"
><input type="checkbox" value="onlyhorsefans" /><span class="ui-label"
><!--[-->OnlyHorseFans<!--]--></span
><!----></label
><!--]-->
</div>
<!--]-->
</fieldset>

Field Legend

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

Legend
<script setup lang="ts">
import { FieldLegend, FieldSet } from "opui-css/vue"
</script>
<template>
<FieldSet>
<FieldLegend>Legend</FieldLegend>
</FieldSet>
</template>
<fieldset class="ui-fieldset">
<!--[-->
<legend class=""><!--[-->Legend<!--]--></legend>
<!--]-->
</fieldset>

Field Description

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

Legend

This is a field description.

<script setup lang="ts">
import { FieldDescription, FieldLegend, FieldSet } from "opui-css/vue"
</script>
<template>
<FieldSet>
<FieldLegend>Legend</FieldLegend>
<FieldDescription>This is a field description.</FieldDescription>
</FieldSet>
</template>
<fieldset class="ui-fieldset">
<!--[-->
<legend class=""><!--[-->Legend<!--]--></legend>
<p class="ui-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.

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

Row

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

Options
<script setup lang="ts">
import { Checkbox, FieldGroup, FieldLegend, FieldSet, Form } from "opui-css/vue"
</script>
<template>
<Form>
<FieldSet>
<FieldLegend>Options</FieldLegend>
<FieldGroup direction="row">
<Checkbox>Option 1</Checkbox>
<Checkbox>Option 2</Checkbox>
<Checkbox>Option 3</Checkbox>
</FieldGroup>
</FieldSet>
</Form>
</template>
<form class="ui-form">
<!--[-->
<fieldset class="ui-fieldset">
<!--[-->
<legend class=""><!--[-->Options<!--]--></legend>
<div class="ui-field-group ui-row" role="group">
<!--[--><label class="ui-checkbox"
><input type="checkbox" /><span class="ui-label"
><!--[-->Option 1<!--]--></span
><!----></label
><label class="ui-checkbox"
><input type="checkbox" /><span class="ui-label"
><!--[-->Option 2<!--]--></span
><!----></label
><label class="ui-checkbox"
><input type="checkbox" /><span class="ui-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

<script setup lang="ts">
import {
Button,
Divider,
FieldGroup,
FieldLegend,
FieldSet,
Form,
TextField,
} from "opui-css/vue"
</script>
<template>
<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>
</template>
<form class="ui-form">
<!--[-->
<fieldset class="ui-fieldset">
<!--[-->
<legend class=""><!--[-->Post Content<!--]--></legend>
<div class="ui-field-group" role="group">
<!--[--><label class="ui-text-field"
><span class="ui-label"><!--[-->Title<!--]--></span
><!----><span class="ui-field"
><input
id="s7-0"
type="text"
placeholder="My new post"
/><!----><!----><!----><!----></span
><!----><!--[--><!--]--></label
><!--]-->
</div>
<!--]-->
</fieldset>
<hr class="ui-divider" />
<div class="ui-field-group" role="group">
<!--[--><button class="ui-button ui-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

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

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

API

Form

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(.ui-form) {
display: grid;
gap: var(--size-8);
hr {
margin-block: 0;
}
}
/* Fieldset */
:where(.ui-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, .ui-legend) {
all: unset;
color: var(--text-primary);
font-weight: 600;
margin-block-end: var(--size-3);
padding: 0;
&:has(+ :where(.ui-field-description)) {
margin-block-end: 0;
}
}
/* Field description / supporting text */
:where(.ui-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(.ui-end-text) {
color: var(--text-muted);
font-size: var(--font-size-0);
line-height: var(--font-lineheight-3);
}
&:has(.ui-text-field.ui-row) {
row-gap: var(--size-7);
}
/* Disabled */
&[disabled] {
opacity: 0.64;
user-select: none;
input,
label,
.ui-label {
cursor: not-allowed;
}
}
/* Error / validation */
&[data-invalid] {
:where(.ui-end-text) {
color: var(--critical);
}
:where(.ui-checkbox, .ui-radio, .ui-switch) {
--primary: var(--critical);
:where(.ui-end-text) {
color: var(--critical);
}
}
:where(.ui-switch) {
input {
border-radius: var(--radius-round);
outline: 2px solid var(--critical);
}
}
}
/* Required */
&:has(:invalid) {
:where(legend, .ui-legend) {
padding-inline-end: 1ex;
position: relative;
&::after {
color: var(--red);
content: "*";
inset: 0 -0.25ex auto auto;
position: absolute;
}
}
}
}
/* Field group */
:where(.ui-field-group) {
display: flex;
flex-direction: column;
gap: var(--size-4);
/* If it only has checkboxes, radios, or switches */
&:has(> :where(.ui-checkbox, .ui-radio, .ui-switch)):not(
:has(> :not(.ui-checkbox, .ui-radio, .ui-switch))
) {
gap: var(--size-2);
}
/* If it only has buttons */
&:has(.ui-button):not(:has(*:not(.ui-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 */
&.ui-row {
flex-direction: row;
flex-wrap: wrap;
&:has(> :where(.ui-checkbox, .ui-radio, .ui-switch)) {
gap: var(--size-4);
}
}
}
}