Vue Form Field

Field

A layout wrapper for a form control, its label, description and validation feedback, built on CSS grid.

<CFormField> renders the .form-field wrapper, which gives a control the layout and spacing it needs alongside its label, description and validation feedback — so a form is spaced by the field itself rather than by margin utilities sprinkled over its parts.

vue
<template>
  <CFormField>
    <CFormLabel for="fieldText">Email address</CFormLabel>
    <CFormInput id="fieldText" type="email" placeholder="[email protected]" />
    <CFormText>We'll never share your email with anyone else.</CFormText>
  </CFormField>
</template>

<script setup>
import { CFormField, CFormInput, CFormLabel, CFormText } from '@coreui/vue'
</script>

How it works

  • Default layout is a single-column grid: everything stacks vertically with one gap. Use it for text inputs, selects, textareas, ranges, input groups and any of the PRO field components.
  • Two-column layout switches on through :has() when the input <CCheckbox>, <CRadio> or <CSwitch> renders (.check, .radio, .switch) is a direct child — the control pins to the first column, the label and description stack in the second. The deprecated .form-check-input triggers it too, so the markup the legacy <CFormCheck> and <CFormSwitch> render lays out the same way.
  • A field label (<CFormLabel>, rendering .form-label) spans both columns and sits above the control row.
  • Grouped controls — nest a <CFormField> per control inside an outer one to put several radios or checkboxes under a shared label with a shared description.

Examples

Select

vue
<template>
  <CFormField>
    <CFormLabel for="fieldSelect">Country</CFormLabel>
    <CFormSelect
      id="fieldSelect"
      :options="[
        { label: 'Choose one…' },
        { label: 'United States', value: '1' },
        { label: 'Canada', value: '2' },
        { label: 'United Kingdom', value: '3' },
      ]"
    />
  </CFormField>
</template>

<script setup>
import { CFormField, CFormLabel, CFormSelect } from '@coreui/vue'
</script>

Textarea

vue
<template>
  <CFormField>
    <CFormLabel for="fieldTextarea">Message</CFormLabel>
    <CFormTextarea id="fieldTextarea" :rows="3" />
    <CFormText>Be sure to include the relevant details.</CFormText>
  </CFormField>
</template>

<script setup>
import { CFormField, CFormLabel, CFormText, CFormTextarea } from '@coreui/vue'
</script>

Checkbox

vue
<template>
  <CFormField>
    <CCheckbox id="fieldCheck" label="Subscribe to the newsletter" />
    <CFormText>We send one email a month, and never share your address.</CFormText>
  </CFormField>
</template>

<script setup>
import { CCheckbox, CFormField, CFormText } from '@coreui/vue'
</script>

Grouped

Nest one <CFormField> per control inside an outer one, and give the group its own .form-label.

vue
<template>
  <CFormField>
    <span class="form-label">Delivery</span>
    <CFormField>
      <CRadio id="fieldRadio1" name="fieldRadio" label="Standard" checked />
      <CFormText>Three to five working days.</CFormText>
    </CFormField>
    <CFormField>
      <CRadio id="fieldRadio2" name="fieldRadio" label="Express" />
      <CFormText>Next working day, where available.</CFormText>
    </CFormField>
  </CFormField>
</template>

<script setup>
import { CFormField, CFormText, CRadio } from '@coreui/vue'
</script>

Switch

vue
<template>
  <CFormField>
    <CSwitch id="fieldSwitch" label="Email notifications" />
    <CFormText>Turn this off and we will only contact you about your account.</CFormText>
  </CFormField>
</template>

<script setup>
import { CFormField, CFormText, CSwitch } from '@coreui/vue'
</script>

Overhead label

When a check, radio, or switch needs a field title above it, add a .form-label. It sits on its own row above the control, while the control’s own label and description keep their places:

vue
<template>
  <CFormField>
    <span class="form-label">Terms and conditions</span>
    <CCheckbox id="fieldOverheadCheck" label="I agree to the terms" />
    <CFormText>Please read them before agreeing.</CFormText>
  </CFormField>
</template>

<script setup>
import { CCheckbox, CFormField, CFormText } from '@coreui/vue'
</script>

Validation

Feedback elements are children of the field like any other, so they inherit its gap and land under the control. Set validation-state on the form component and pass the message through feedback-valid / feedback-invalid.

vue
<template>
  <CFormField>
    <CFormLabel for="fieldValidation">Username</CFormLabel>
    <CFormInput
      id="fieldValidation"
      type="text"
      model-value="jan kowalski"
      validation-state="invalid"
      feedback-invalid="A username cannot contain spaces."
    />
  </CFormField>
</template>

<script setup>
import { CFormField, CFormInput, CFormLabel } from '@coreui/vue'
</script>

See validation for the full picture, including the server-side and browser-native flavours.