FormGroup
A label / description / error scaffold that wraps any slotted control and wires the accessibility plumbing.
Live demo
FormGroup is the presentational scaffolding around a form control you bring yourself: a Select, Textarea, Checkbox, Radio, or a bare native input. It renders the label, an optional description, and an error region, and wires the accessibility plumbing: it associates the label with the slotted control, builds aria-describedby from whichever of the description and error are showing, and reflects invalid / required onto the control as aria-invalid / aria-required.
Unlike Field, it owns no input of its own; it is the reusable wrapper that gives every other control the same labelled, described, error-aware shell. Two variants (default, invalid) and the shared three-step size scale keep it in lockstep with the rest of the form family.
When to use
How this component composes with the rest of the set.
Props
7 props, straight from the manifest.
| Prop | Type | Default | Bindings | Description |
|---|---|---|---|---|
Appearance
Variants
default
The resting scaffold: label, optional description, control, no error.
invalid
The error message is shown, the label takes the danger ink, and the control is marked aria-invalid.
Sizes
sm
Compact stack and smaller helper text.
md
Default.
lg
Roomier stack and larger helper text.
States
invalid
Error region revealed, label tinted danger, control flagged aria-invalid.
required
Required indicator appended to the label, control flagged aria-required.
Anatomy
The named parts that make up the component, with their selectors.
group
The vertical stack wrapping the label, description, control, and error.
label
The control's label, associated with the slotted control via for / aria-labelledby.
required-indicator
The asterisk appended to the label when the group is required.
description
Optional helper text below the label, referenced by the control's aria-describedby.
control
The slot region that holds whatever control the author drops in.
error
The validation message shown when invalid, also referenced by aria-describedby.
Tokens & coverage
What the component consumes, checked live against what the algorithm produces.
Live coverage check against the xoji-default register
(derive(xojiDefault, { anchors }) →
coverComponent(manifest, register)). Every token this component
consumes must be a key the algorithm produces.
--danger
--danger-text
--fg-1
--fg-2
--font-sans
--leading-normal
--space-0
--space-1
--space-2
--text-body
--text-sm
--text-xs
--weight-medium
--weight-semibold
Slots
The form control to scaffold: a Select, Textarea, Checkbox, Radio, or native input.
Accessibility
Code
Scaffolding controls
FormGroup wraps a Select, a textarea, and a native input, labelling, describing, and error-wiring each.
<xoji-form-group label="Theme" description="Applies across the whole workspace." for="theme">
<xoji-select id="theme" name="theme">
<option value="auto">Match system</option>
<option value="light">Light</option>
<option value="dark">Dark</option>
</xoji-select>
</xoji-form-group>
<xoji-form-group label="Bio" description="A short line shown on your profile.">
<textarea rows="3"></textarea>
</xoji-form-group>
<xoji-form-group label="Email" required invalid error="That address is already in use." for="email">
<input type="email" id="email" name="email" />
</xoji-form-group>
<script lang="ts">
import { FormGroup, Select } from "@xoji/svelte";
let theme = $state("auto");
</script>
<FormGroup label="Theme" description="Applies across the whole workspace." for="theme">
<Select id="theme" name="theme" bind:value={theme}>
<option value="auto">Match system</option>
<option value="light">Light</option>
<option value="dark">Dark</option>
</Select>
</FormGroup>
<FormGroup label="Email" required invalid error="That address is already in use." for="email">
<input type="email" id="email" name="email" />
</FormGroup>
---
import { FormGroup, Select } from "@xoji/astro";
---
<FormGroup label="Theme" description="Applies across the whole workspace." for="theme">
<Select id="theme" name="theme">
<option value="auto">Match system</option>
<option value="light">Light</option>
<option value="dark">Dark</option>
</Select>
</FormGroup>
<FormGroup label="Email" required invalid error="That address is already in use." for="email">
<input type="email" id="email" name="email" />
</FormGroup>