Fieldset
Group related form controls with legends, descriptions, and actions
Usage
import { Fieldset } from '@hareui/vue'<script setup lang="ts">import { Icon } from '@iconify/vue'import { Button, Fieldset, Form, Input, TextArea, TextField } from '@hareui/vue'function onSubmit(e: Event) { e.preventDefault() alert('Form submitted successfully!')}const validateName = (value: string | number) => String(value).length < 3 ? 'Name must be at least 3 characters' : nullconst validateBio = (value: string | number) => String(value).length < 10 ? 'Bio must be at least 10 characters' : null</script><template> <Form class="w-full max-w-96" @submit="onSubmit"> <Fieldset legend="Profile Settings" description="Update your profile information."> <TextField required name="name" label="Name" :validate="validateName"> <Input placeholder="John Doe" /> </TextField> <TextField required name="email" type="email" label="Email"> <Input placeholder="[email protected]" /> </TextField> <TextField required name="bio" label="Bio" description="Minimum 10 characters" :validate="validateBio"> <TextArea placeholder="Tell us about yourself..." /> </TextField> <template #actions> <Button type="submit"> <Icon icon="gravity-ui:floppy-disk" /> Save changes </Button> <Button type="reset" variant="secondary"> Cancel </Button> </template> </Fieldset> </Form></template>Anatomy
HeroUI's compound parts (Fieldset.Legend, Fieldset.Group, Fieldset.Actions) become props and named slots, rendered in a fixed order: legend, description, field group, then actions.
<Fieldset legend="…" description="…">
<template #legend /> <!-- or: replaces the legend text -->
<template #description /> <!-- or: replaces the description text -->
<!-- default slot = form fields, wrapped in the field group -->
<template #actions /> <!-- action buttons or helper text -->
</Fieldset>- Each part renders only when its prop or slot is provided.
disabledsets the nativedisabledattribute anddata-disabled="true", and disables HareUI controls inside (such asButtonandLink) the same way HeroUI's fieldset does.
ui keys: base, legend, description, fieldGroup, actions.
Examples
In Surface
When used inside a Surface component, use variant="secondary" on form controls (Input, TextArea, etc.) to apply the lower emphasis variant suitable for surface backgrounds.
<script setup lang="ts">import { Icon } from '@iconify/vue'import { Button, Fieldset, Form, Input, Surface, TextArea, TextField } from '@hareui/vue'function onSubmit(e: Event) { e.preventDefault() alert('Form submitted successfully!')}const validateName = (value: string | number) => String(value).length < 3 ? 'Name must be at least 3 characters' : nullconst validateBio = (value: string | number) => String(value).length < 10 ? 'Bio must be at least 10 characters' : null</script><template> <div class="flex items-center justify-center rounded-3xl bg-surface p-6"> <Surface class="w-full min-w-[380px]"> <Form @submit="onSubmit"> <Fieldset class="w-full" legend="Profile Settings" description="Update your profile information."> <TextField required name="name" label="Name" :validate="validateName"> <Input placeholder="John Doe" variant="secondary" /> </TextField> <TextField required name="email" type="email" label="Email"> <Input placeholder="[email protected]" variant="secondary" /> </TextField> <TextField required name="bio" label="Bio" description="Minimum 10 characters" :validate="validateBio"> <TextArea placeholder="Tell us about yourself..." variant="secondary" /> </TextField> <template #actions> <Button type="submit"> <Icon icon="gravity-ui:floppy-disk" /> Save changes </Button> <Button type="reset" variant="tertiary"> Cancel </Button> </template> </Fieldset> </Form> </Surface> </div></template>Customization
Tailwind CSS
<script setup lang="ts">import { Icon } from '@iconify/vue'import { Button, Fieldset, Form, Input, TextArea, TextField } from '@hareui/vue'function onSubmit(e: Event) { e.preventDefault() alert('Form submitted successfully!')}const validateName = (value: string | number) => String(value).length < 3 ? 'Name must be at least 3 characters' : nullconst validateBio = (value: string | number) => String(value).length < 10 ? 'Bio must be at least 10 characters' : nullconst shell = 'rounded-xl border border-border/70 bg-linear-to-b from-neutral-50/90 to-white p-4 ring-1 ring-black/5 dark:from-neutral-900/80 dark:to-neutral-900 dark:ring-white/10'const field = 'rounded-xl border border-border/80 bg-surface shadow-sm ring-1 ring-black/5 transition-[box-shadow,border-color] focus-visible:ring-2 focus-visible:ring-neutral-400/25 dark:ring-white/10 dark:focus-visible:ring-neutral-500/30'</script><template> <Form class="w-full max-w-96" @submit="onSubmit"> <Fieldset :class="shell" legend="Profile Settings" description="Update your profile information." :ui="{ legend: 'font-medium text-neutral-800 dark:text-neutral-100', description: 'text-neutral-600 dark:text-neutral-400' }" > <TextField required name="name" label="Name" :validate="validateName"> <Input :class="field" placeholder="John Doe" /> </TextField> <TextField required name="email" type="email" label="Email"> <Input :class="field" placeholder="[email protected]" /> </TextField> <TextField required name="bio" label="Bio" description="Minimum 10 characters" :validate="validateBio"> <TextArea :class="field" placeholder="Tell us about yourself..." /> </TextField> <template #actions> <Button type="submit"> <Icon icon="gravity-ui:floppy-disk" /> Save changes </Button> <Button type="reset" variant="secondary"> Cancel </Button> </template> </Fieldset> </Form></template>Global theme override
Override the fieldset theme app-wide with createHareUI:
app.use(createHareUI({
ui: {
fieldset: {
slots: {
base: 'gap-5 rounded-xl border border-border/60 bg-surface p-6 shadow-field',
legend: 'text-lg font-semibold',
fieldGroup: 'gap-3 md:grid md:grid-cols-2',
actions: 'flex justify-end gap-2 pt-2',
},
},
},
}))Styling Reference
Each rendered element carries the same data-slot string as HeroUI, so selectors translate 1:1.
ui key | data-slot | Description |
|---|---|---|
base | fieldset | Root container |
legend | fieldset-legend | Legend element |
description | description | Description below the legend |
fieldGroup | fieldset-field-group | Wrapper for grouped fields |
actions | fieldset-actions | Action bar below the fields |
API Reference
Props
| Prop | Type | Default | Description |
|---|---|---|---|
as | AsTag | Component | "fieldset" | The element or component to render as. |
legend | string | - | The legend text. |
description | string | - | Help text rendered below the legend. |
disabled | boolean | false | Disables every control inside, like a native <fieldset disabled>, including div-based ones. |
ui | ComponentSlots<{ slots: { base: string; legend: string; description: string; fieldGroup: string; actions: string; }; }> | - | Per-slot class overrides. |
Slots
| Slot | Props | Description |
|---|---|---|
legend | any | The legend content. Replaces the legend prop. |
description | any | The description content. Replaces the description prop. |
default | any | Form fields, rendered inside the field group. |
actions | any | Action buttons or helper text below the fields. |





