Fieldset
Native <fieldset> group with legend, description, and error wiring.
| Package | @vizejs/ui/fieldset |
| Maturity | stable |
| Own the source | vize lib pull fieldset |
| Requires | context, field-wiring, id |
| Aliases | fieldset, field group, legend, radio group wrapper, form section |
| Covers | HTML fieldset/legend, WAI-ARIA group, React Aria Fieldset |
Minimal setup
Use a Vue 3.5+ project with Vue SFC compilation configured (see Vite+ integration).
vp install @vizejs/ui
Add the public import below to <script setup lang="ts">. Components provide behavior without styles; the preview uses optional Paper styles.
import { Fieldset, FieldsetLegend, FieldsetDescription, FieldsetErrorMessage } from "@vizejs/ui/fieldset";
Or copy the source into your project with vize lib pull fieldset (see Source Distribution).
Try it
This is the basic example maintained with the component source, using the public package imports. The preview adds the optional Paper styles.
Open the interactive example · Styling these components
Copy the example
<!-- Radio group in a native fieldset whose legend, description, and group error are wired together. -->
<script setup lang="ts">
import { computed, ref } from "vue";
import {
Fieldset,
FieldsetDescription,
FieldsetErrorMessage,
FieldsetLegend,
} from "@vizejs/ui/fieldset";
const contact = ref("");
const errors = computed(() =>
contact.value === ""
? [{ name: "contact", message: "Choose how we should contact you.", path: ["contact"] }]
: [],
);
</script>
<template>
<Fieldset name="contact" :errors has-description>
<FieldsetLegend>Preferred contact method</FieldsetLegend>
<FieldsetDescription>We only use this for order updates.</FieldsetDescription>
<label><input v-model="contact" type="radio" name="contact" value="email" /> Email</label>
<label><input v-model="contact" type="radio" name="contact" value="phone" /> Phone</label>
<label><input v-model="contact" type="radio" name="contact" value="post" /> Post</label>
<FieldsetErrorMessage />
</Fieldset>
</template>
API
Fieldset
Source: src/families/form/fieldset/fieldset.vue
Props
| Prop | Type | Default | Description |
|---|---|---|---|
id |
string | null |
undefined |
Fieldset id. null and undefined select a deterministic fallback. |
name |
string |
undefined |
Group name matched against errors[].name (for example "address"), also set as the native fieldset name. |
form |
string |
undefined |
Id of a form owner outside the component tree. |
errors |
readonly FormFieldError[] |
[] |
Normalized form errors; entries whose name equals name mark the group invalid. |
invalid |
boolean |
undefined |
Consumer-owned invalid override. undefined derives it from matching errors. |
disabled |
boolean |
false |
Natively disable the fieldset and every descendant form control. |
hasDescription |
boolean |
false |
Whether a FieldsetDescription is rendered and joins aria-describedby. |
hasErrorMessage |
boolean |
true |
Whether a FieldsetErrorMessage is rendered while invalid and joins aria-describedby. |
Events
| Event | Payload | Description |
|---|---|---|
invalid-change |
[invalid: boolean, errors: readonly FormFieldError[]] |
Fired after the derived invalid state changes, with the matching errors. |
Slots
| Slot | Slot props | Description |
|---|---|---|
default |
FieldsetSlotState |
Renders the legend, description, fields, and error message with group state. |
Exposed
| Member | Type | Description |
|---|---|---|
element |
Readonly<ShallowRef<HTMLElement | null>> |
Template ref to the rendered root element. |
invalid |
— | |
id |
— |
FieldsetLegend
Source: src/families/form/fieldset/fieldset-legend.vue
Slots
| Slot | Slot props | Description |
|---|---|---|
default |
Record<string, never> |
Legend text that names the group; render it as the first child of the Fieldset. |
FieldsetDescription
Source: src/families/form/fieldset/fieldset-description.vue
Props
| Prop | Type | Default | Description |
|---|---|---|---|
as |
PrimitiveAs |
"p" |
Native element, custom element, or component to render. |
Slots
| Slot | Slot props | Description |
|---|---|---|
default |
Record<string, never> |
Group-level help text; set hasDescription on the Fieldset so it is referenced. |
FieldsetErrorMessage
Source: src/families/form/fieldset/fieldset-error-message.vue
Props
| Prop | Type | Default | Description |
|---|---|---|---|
as |
PrimitiveAs |
"p" |
Native element, custom element, or component to render. |
forceMount |
boolean |
false |
Keep the element in the DOM while the group is valid. |
Slots
| Slot | Slot props | Description |
|---|---|---|
default |
FieldsetErrorMessageSlotState |
Group validation text; defaults to the first matching error message. |
Behavior
Normative state x input -> outcome table for fieldset.vue,
fieldset-legend.vue, fieldset-description.vue, and
fieldset-error-message.vue (@vizejs/ui/fieldset). The group is a native
<fieldset> named by its <legend>; ids come from the shared field-wiring
foundation. Every row is proven by the named test in fieldset.test.ts or
fieldset-ssr.test.ts; compile-only assertions live in fieldset.types.test-d.ts.
| # | State | Input | Outcome | Proven by |
|---|---|---|---|---|
| FS1 | valid, described | render | native <fieldset> with id and name, first-child <legend>, description id joined into aria-describedby, no error |
renders a native fieldset named by its legend and described by its description |
| FS2 | matching form error | errors with the group name |
group becomes invalid, error message renders with the derived id and joins aria-describedby; emits invalid-change |
matching form errors mark the group invalid and reference the error message |
| FS3 | override / disabled | invalid, forceMount, disabled |
invalid overrides errors; forceMount keeps the message; disabled is the native attribute that disables descendants |
invalid override, forceMount, and native disabled propagation |
| FS4 | part without provider | setup | throws the stable VIZE_UI_CONTEXT_MISSING: Fieldset diagnostic |
parts require a Fieldset provider |
| FS5 | SSR / hydration | isolated requests | byte-identical markup with deterministic ids and relations; hydration without diagnostics | renders byte-identical fieldset markup and hydrates without mismatches |
Public extension contract
| Surface | Contract |
|---|---|
| Parts | root (fieldset), legend, description, error-message. |
| Data attributes | data-vize-ui, root data-state (valid/invalid/disabled), data-invalid on root and legend. |
| Ids | <id>-description and <id>-error, matching useFieldWiring and useFormFieldProps conventions. |
The subpath is tree-shakable and ships no CSS; those package contracts are
pinned by distribution.test.ts, check:size, and check:tree-shaking.