Skip to content

FormGroup

Field wrapper adding a label, description, hint, required marker and error message around any control. FormFields uses it internally; on its own it is how you build a hand-laid-out form.

Composition

Labels a single control. For how it relates to FormFields and InputWrapper, see Composing Forms.

Import

typescript
import { FormGroup } from 'vuiii'

Basic Usage

vue
<FormGroup label="Email">
  <template #default="{ id }">
    <Input :id="id" v-model="email" type="email" />
  </template>
</FormGroup>

Pass the slot id through

FormGroup generates an id and points its <label for> at it, then hands it to the default slot. Forward it to your control to keep the label clickable and the field properly announced. Skipping it still renders, but the label is no longer tied to anything.

Props

PropTypeDefaultDescription
labelstring-Label text
forstring-Explicit id to label, instead of the generated one
requiredbooleanfalseShows the required marker next to the label
descriptionstring-Explanatory text between the label and the control
hintstring-Secondary text below the control
errorstring | boolean-Error message; true marks the field invalid with no message

Slots

SlotDescription
defaultThe control. Props: { id }
labelReplaces the label text
descriptionReplaces the description text
hintReplaces the hint text

Description and Hint

description explains the field before it is filled in; hint sits below the control for a constraint or format note.

Choose a strong password for your account
Must be at least 8 characters
vue
<FormGroup
  label="Password"
  description="Choose a strong password for your account"
  hint="Must be at least 8 characters"
>
  <template #default="{ id }">
    <Input :id="id" v-model="password" type="password" />
  </template>
</FormGroup>

Required and Errors

error renders the message and marks the group invalid. Set invalid on the control too, so the input itself picks up the error styling.

*
This username is already taken
vue
<FormGroup label="Username" required :error="errors.username">
  <template #default="{ id }">
    <Input :id="id" v-model="username" :invalid="!!errors.username" />
  </template>
</FormGroup>

With useValidation the per-field result feeds both directly:

vue
<FormGroup label="Username" :error="validatedFields.username?.errorMessage">
  <template #default="{ id }">
    <Input :id="id" v-model="form.username" :invalid="validatedFields.username?.isInvalid" />
  </template>
</FormGroup>

Custom Label

The label slot takes over the label content — useful for a help tooltip or a badge next to the text.

vue
<FormGroup>
  <template #label>
    Email
    <Tooltip title="We will never share your email">
      <Icon name="exclamation" size="small" />
    </Tooltip>
  </template>
  <template #default="{ id }">
    <Input :id="id" v-model="email" />
  </template>
</FormGroup>

Any Control

FormGroup makes no assumptions about what it wraps — VUIII inputs, native elements, or your own components all work.

Markdown is supported
vue
<FormGroup label="Bio" hint="Markdown is supported">
  <template #default="{ id }">
    <Textarea :id="id" v-model="bio" rows="3" />
  </template>
</FormGroup>

Storybook

For interactive examples with all variants, see FormGroup in Storybook.

Released under the MIT License.