Skip to main content

FormGroup

Info:Form html svelte astro Success: coverage 14/14

A label / description / error scaffold that wraps any slotted control and wires the accessibility plumbing.

Live demo

live · @xoji/astro

FormGroup

Wrapping any control

Shown next to your contributions.
Who can find this project.

Validation

That slug is already taken.
Billed monthly per seat.

Sizes

size=sm
size=md
size=lg

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.

Wrap a Select, Textarea, Checkbox, or Radio to give it the same labelled, described, error-aware shell; FormGroup owns no input itself.
For a single-line text input that wants prefix/suffix adornments and a clear button, reach for Field instead; FormGroup is the generic wrapper for everything else.
Pass for with the slotted control's id for explicit wiring, or omit it and let the group assign an id automatically.
Drive invalid / error from your form library's per-field validation state.

Props

7 props, straight from the manifest.

PropTypeDefaultBindingsDescription
label string
html svelte astro
The control's label. When absent, the binding warns and falls back to labelling the control via `aria-labelledby`.
description string
html svelte astro
Helper text rendered below the label and linked into the control's `aria-describedby`.
error string
html svelte astro
Validation message shown only while `invalid`; linked into the control's `aria-describedby`.
size Size
sm md lg
md
html svelte astro
Tightens or relaxes the stack spacing and label / helper text size.
invalid boolean false
html svelte astro
Marks the group invalid: reveals the error, tints the label, and sets `aria-invalid` on the control.
required boolean false
html svelte astro
Appends the required indicator and sets `aria-required` on the control.
for string
html svelte astro
The id of the slotted control to associate. When omitted, the group assigns the control an id automatically.

Appearance

Variants

default

.xoji-form-group

The resting scaffold: label, optional description, control, no error.

invalid

.xoji-form-group--invalid

The error message is shown, the label takes the danger ink, and the control is marked aria-invalid.

Sizes

sm

.xoji-form-group--sm

Compact stack and smaller helper text.

md

default
.xoji-form-group

Default.

lg

.xoji-form-group--lg

Roomier stack and larger helper text.

States

invalid

.xoji-form-group--invalid

Error region revealed, label tinted danger, control flagged aria-invalid.

required

.xoji-form-group__required

Required indicator appended to the label, control flagged aria-required.

Anatomy

The named parts that make up the component, with their selectors.

group

.xoji-form-group

The vertical stack wrapping the label, description, control, and error.

--font-sans --space-1

label

.xoji-form-group__label

The control's label, associated with the slotted control via for / aria-labelledby.

--text-sm --weight-medium --fg-1 --leading-normal --space-1

required-indicator

.xoji-form-group__required

The asterisk appended to the label when the group is required.

--danger --weight-semibold

description

.xoji-form-group__description

Optional helper text below the label, referenced by the control's aria-describedby.

--text-sm --leading-normal --fg-2

control

.xoji-form-group__control

The slot region that holds whatever control the author drops in.

--space-1

error

.xoji-form-group__error

The validation message shown when invalid, also referenced by aria-describedby.

--text-sm --leading-normal --danger --space-1

Tokens & coverage

What the component consumes, checked live against what the algorithm produces.

Success:fully covered 14/14 consumed tokens produced default register: 276 tokens

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

default
html svelte astro

The form control to scaffold: a Select, Textarea, Checkbox, Radio, or native input.

Accessibility

Associates the rendered <label> with the slotted control via for (or aria-labelledby when the control has no id of its own).
Builds the control's aria-describedby from whichever of the description and error are currently showing.
Reflects invalid as aria-invalid and required as aria-required onto the slotted control.
The error region is an role="alert" live region so a newly-shown validation message is announced.
Warns at runtime when no label is provided, since the slotted control may then lack an accessible name.
Purely presentational chrome; all semantics live on the native control you slot in, never on the wrapper.

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>