---
name: number-field
title: Number Field
url: https://ui.frontic.com/components/ui/number-field.md
tier: ui
install: npx @frontic/ui add number-field
files:
  - components/ui/number-field/NumberField.vue
  - components/ui/number-field/NumberFieldContent.vue
  - components/ui/number-field/NumberFieldDecrement.vue
  - components/ui/number-field/NumberFieldIncrement.vue
  - components/ui/number-field/NumberFieldInput.vue
  - components/ui/number-field/index.ts
registryDependencies:
  - use-field-control
dependencies:
  - "@lucide/vue"
  - "@vueuse/core"
  - reka-ui
---

# Number Field

Lets the shopper type a number or step it up and down with buttons at either end, within a minimum and maximum, such as a quantity. Fills its Field like other controls; never narrower than its two buttons and three digits.

## Install

```sh
npx @frontic/ui add number-field
```

Built from: [Use Field Control](https://ui.frontic.com/composables/use-field-control.md)

Used by: [Product Options](https://ui.frontic.com/components/sections/product-options.md), [Cart Item Compact](https://ui.frontic.com/components/templates/cart-item-compact.md)

npm packages: `@lucide/vue`, `@vueuse/core`, `reka-ui`

## Examples

```vue
<script setup lang="ts">
import { Field, FieldDescription, FieldLabel } from '@/components/ui/field'
import { NumberField, NumberFieldContent, NumberFieldDecrement, NumberFieldIncrement, NumberFieldInput } from '@/components/ui/number-field'
</script>

<template>
  <Field>
    <FieldLabel>Quantity</FieldLabel>
    <NumberField :default-value="1" :min="1" :max="10">
      <NumberFieldContent>
        <NumberFieldDecrement />
        <NumberFieldInput />
        <NumberFieldIncrement />
      </NumberFieldContent>
    </NumberField>
    <FieldDescription>Up to 10 per order.</FieldDescription>
  </Field>
</template>
```

The example also uses `field`, which `add number-field` leaves out: `npx @frontic/ui add field`.

## Anatomy

```vue
<NumberField>
  <NumberFieldContent>
    <NumberFieldDecrement />
    <NumberFieldInput />
    <NumberFieldIncrement />
  </NumberFieldContent>
</NumberField>
```

## API reference

### NumberField

Groups all parts of the number field. Renders a `<div>`.

`data-slot="number-field"` · `NumberField.vue`

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `defaultValue` | `number` |  | The number the field starts with when uncontrolled. |
| `modelValue` | `number \| null`: `null \| number` |  | The number, bound with `v-model`. |
| `min` | `number` |  | The smallest value allowed for the input. |
| `max` | `number` |  | The largest value allowed for the input. |
| `step` | `number` | `1` | The amount that the input value changes with each increment or decrement "tick". |
| `stepSnapping` | `boolean` | `true` | When `false`, prevents the value from snapping to the nearest increment of the step value |
| `allowInvalid` | `boolean` | `false` | When `true`, a typed value is kept as-is even if invalid (out of `min`/`max` range or off the step grid); step interactions still clamp and snap. The field does not flag the value as invalid (no `aria-invalid`/`data-invalid`), so validating and surfacing the error is up to the consumer. |
| `focusOnChange` | `boolean` | `true` | When `true`, the input will be focused when the value changes. |
| `formatOptions` | `Intl.NumberFormatOptions` |  | Formatting options for the value displayed in the number field. This also affects what characters are allowed to be typed by the user. |
| `locale` | `string` |  | The locale to use for formatting and currencies |
| `disabled` | `boolean` | `false` | When `true`, prevents the user from interacting with the Number Field. |
| `readonly` | `boolean` | `false` | When `true`, the Number Field is read-only. |
| `disableWheelChange` | `boolean` | `false` | When `true`, prevents the value from changing on wheel scroll. |
| `invertWheelChange` | `boolean` | `false` | When `true`, inverts the direction of the wheel change. |
| `id` | `string` |  | Id of the element |
| `startingValue` | `number` |  | The value the first increment or decrement sets when the field is empty. It is clamped to `min`/`max` but not snapped to `step`. Defaults to `min`, or `0` when `min` is not set. |
| `asChild` | `boolean` | `false` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://www.reka-ui.com/docs/guides/composition) guide for more details. |
| `as` | `AsTag \| Component`: `ComponentOptions<any, any, any, ComputedOptions, MethodOptions, any, any, any, string, {}, {}, string, {}, {}, {}, string, ComponentProvideOptions> \| (props: any, ctx: Omit<{ attrs: Attrs; slots: Readonly<InternalSlots>; emit: (event: string, ...args: any[]) => void; expose: <Exposed extends Record<string, any> = Record<string, any>>(exposed?: Exposed \| undefined) => void; }, 'expose'>): any \| ComponentPublicInstanceConstructor<any, any, any, any, ComputedOptions, MethodOptions> \| 'a' \| 'button' \| 'div' \| 'form' \| 'h2' \| 'h3' \| 'img' \| 'input' \| 'label' \| 'li' \| 'nav' \| 'ol' \| 'p' \| 'span' \| 'svg' \| 'ul' \| 'template' \| {} & string` | `'div'` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `name` | `string` |  | The name of the field. Submitted with its owning form as part of a name/value pair. |
| `required` | `boolean` | `false` | When `true`, indicates that the user must set the value before the owning form can be submitted. |
| `class` | `ClassValue` |  | Classes added to the part's own element, after its recipe classes. |

| Event | Payload | Description |
| --- | --- | --- |
| `update:modelValue` | `val: number \| undefined` | Fires with the new value when `modelValue` changes; `v-model` binds it. |

| Slot | Slot props | Description |
| --- | --- | --- |
| `default` | `{ modelValue: number \| undefined; textValue: string; readonly: boolean; }` | Holds the field's input and buttons; gets the current number, its formatted text and whether the field is read-only. |

| Data attribute | Values | Description |
| --- | --- | --- |
| `data-disabled` |  | Present while the part is disabled. |
| `data-readonly` |  | Present while the part is read-only. |

### NumberFieldContent

Groups the number input with its decrement and increment buttons. Renders a `<div>`.

`data-slot="number-field-content"` · `NumberFieldContent.vue`

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `asChild` | `boolean` | `false` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://www.reka-ui.com/docs/guides/composition) guide for more details. |
| `as` | `AsTag \| Component`: `ComponentOptions<any, any, any, ComputedOptions, MethodOptions, any, any, any, string, {}, {}, string, {}, {}, {}, string, ComponentProvideOptions> \| (props: any, ctx: Omit<{ attrs: Attrs; slots: Readonly<InternalSlots>; emit: (event: string, ...args: any[]) => void; expose: <Exposed extends Record<string, any> = Record<string, any>>(exposed?: Exposed \| undefined) => void; }, 'expose'>): any \| ComponentPublicInstanceConstructor<any, any, any, any, ComputedOptions, MethodOptions> \| 'a' \| 'button' \| 'div' \| 'form' \| 'h2' \| 'h3' \| 'img' \| 'input' \| 'label' \| 'li' \| 'nav' \| 'ol' \| 'p' \| 'span' \| 'svg' \| 'ul' \| 'template' \| {} & string` | `'div'` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `class` | `ClassValue` |  | Classes added to the part's own element, after its recipe classes. |

### NumberFieldDecrement

Lowers the value of the number field by one step. Renders a `<button>`.

`data-slot="number-field-decrement"` · `NumberFieldDecrement.vue`

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `disabled` | `boolean` | `false` | Disables the button that lowers the value. |
| `asChild` | `boolean` | `false` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://www.reka-ui.com/docs/guides/composition) guide for more details. |
| `as` | `AsTag \| Component`: `ComponentOptions<any, any, any, ComputedOptions, MethodOptions, any, any, any, string, {}, {}, string, {}, {}, {}, string, ComponentProvideOptions> \| (props: any, ctx: Omit<{ attrs: Attrs; slots: Readonly<InternalSlots>; emit: (event: string, ...args: any[]) => void; expose: <Exposed extends Record<string, any> = Record<string, any>>(exposed?: Exposed \| undefined) => void; }, 'expose'>): any \| ComponentPublicInstanceConstructor<any, any, any, any, ComputedOptions, MethodOptions> \| 'a' \| 'button' \| 'div' \| 'form' \| 'h2' \| 'h3' \| 'img' \| 'input' \| 'label' \| 'li' \| 'nav' \| 'ol' \| 'p' \| 'span' \| 'svg' \| 'ul' \| 'template' \| {} & string` | `'button'` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `class` | `ClassValue` |  | Classes added to the part's own element, after its recipe classes. |

| Data attribute | Values | Description |
| --- | --- | --- |
| `data-disabled` |  | Present while the part is disabled. |
| `data-pressed` |  | Present while the button is held down. |

### NumberFieldIncrement

Raises the value of the number field by one step. Renders a `<button>`.

`data-slot="number-field-increment"` · `NumberFieldIncrement.vue`

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `disabled` | `boolean` | `false` | Disables the button that raises the value. |
| `asChild` | `boolean` | `false` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://www.reka-ui.com/docs/guides/composition) guide for more details. |
| `as` | `AsTag \| Component`: `ComponentOptions<any, any, any, ComputedOptions, MethodOptions, any, any, any, string, {}, {}, string, {}, {}, {}, string, ComponentProvideOptions> \| (props: any, ctx: Omit<{ attrs: Attrs; slots: Readonly<InternalSlots>; emit: (event: string, ...args: any[]) => void; expose: <Exposed extends Record<string, any> = Record<string, any>>(exposed?: Exposed \| undefined) => void; }, 'expose'>): any \| ComponentPublicInstanceConstructor<any, any, any, any, ComputedOptions, MethodOptions> \| 'a' \| 'button' \| 'div' \| 'form' \| 'h2' \| 'h3' \| 'img' \| 'input' \| 'label' \| 'li' \| 'nav' \| 'ol' \| 'p' \| 'span' \| 'svg' \| 'ul' \| 'template' \| {} & string` | `'button'` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `class` | `ClassValue` |  | Classes added to the part's own element, after its recipe classes. |

| Data attribute | Values | Description |
| --- | --- | --- |
| `data-disabled` |  | Present while the part is disabled. |
| `data-pressed` |  | Present while the button is held down. |

### NumberFieldInput

Lets the user type a number into the number field. Renders a `<input>`.

`data-slot="number-field-input"` · `NumberFieldInput.vue`

Styling: `number-field-input`, which extends [`control`](https://ui.frontic.com/DESIGN.md#control) and [`control-line`](https://ui.frontic.com/DESIGN.md#control-line). Change them there and every part that extends them follows.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `asChild` | `boolean` | `false` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://www.reka-ui.com/docs/guides/composition) guide for more details. |
| `as` | `AsTag \| Component`: `ComponentOptions<any, any, any, ComputedOptions, MethodOptions, any, any, any, string, {}, {}, string, {}, {}, {}, string, ComponentProvideOptions> \| (props: any, ctx: Omit<{ attrs: Attrs; slots: Readonly<InternalSlots>; emit: (event: string, ...args: any[]) => void; expose: <Exposed extends Record<string, any> = Record<string, any>>(exposed?: Exposed \| undefined) => void; }, 'expose'>): any \| ComponentPublicInstanceConstructor<any, any, any, any, ComputedOptions, MethodOptions> \| 'a' \| 'button' \| 'div' \| 'form' \| 'h2' \| 'h3' \| 'img' \| 'input' \| 'label' \| 'li' \| 'nav' \| 'ol' \| 'p' \| 'span' \| 'svg' \| 'ul' \| 'template' \| {} & string` | `'input'` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `class` | `ClassValue` |  | Classes added to the part's own element, after its recipe classes. |

| Data attribute | Values | Description |
| --- | --- | --- |
| `data-disabled` |  | Present while the part is disabled. |
| `data-readonly` |  | Present while the part is read-only. |

## Styling

| Part | Recipe |
| --- | --- |
| `content` | [`number-field-content`](https://ui.frontic.com/DESIGN.md#number-field-content) |
| `default` | [`number-field`](https://ui.frontic.com/DESIGN.md#number-field) |
| `input` | [`number-field-input`](https://ui.frontic.com/DESIGN.md#number-field-input) |
| `step` | [`number-field-step`](https://ui.frontic.com/DESIGN.md#number-field-step) |
| `disabled` | [`disabled`](https://ui.frontic.com/DESIGN.md#disabled) |

States with a look of their own: focus, disabled and invalid.

## Source

`components/ui/number-field/NumberField.vue`

```vue
<script lang="ts">
/** Groups all parts of the number field. */
export default {}
</script>

<script setup lang="ts">
import type { NumberFieldRootEmits, NumberFieldRootProps } from 'reka-ui'
import type { HTMLAttributes } from 'vue'
import { reactiveOmit } from '@vueuse/core'
import { NumberFieldRoot, useForwardPropsEmits } from 'reka-ui'
import { useTemplateRef } from 'vue'
import { useFieldControl } from '@library/composables/use-field-control'

const props = defineProps<NumberFieldRootProps & { class?: HTMLAttributes['class'] }>()
const emits = defineEmits<NumberFieldRootEmits>()

const delegatedProps = reactiveOmit(props, 'class')

const forwarded = useForwardPropsEmits(delegatedProps, emits)

defineSlots<{
  /** Holds the field's input and buttons; gets the current number, its formatted text and whether the field is read-only. */
  default?: (props: { modelValue: number | undefined; textValue: string; readonly: boolean }) => unknown
}>()

// Delete once Reka's NumberField reads the Field itself.
const { joined, report } = useFieldControl({
  props,
  forwarded,
  root: useTemplateRef<{ $el: HTMLElement }>('root'),
  element: (root) => root?.querySelector('input'),
  id: () => props.id,
  focus: 'none',
  aria: 'none',
  state: false,
})
</script>

<template>
  <NumberFieldRoot ref="root" v-slot="slotProps" v-bind="joined" data-slot="number-field" :class="['fui-number-field', props.class]" @update:model-value="report">
    <slot v-bind="slotProps" />
  </NumberFieldRoot>
</template>
```

`components/ui/number-field/NumberFieldContent.vue`

```vue
<script lang="ts">
/** Groups the number input with its decrement and increment buttons. */
export default {}
</script>

<script setup lang="ts">
import type { PrimitiveProps } from 'reka-ui'
import { Primitive } from 'reka-ui'
import type { HTMLAttributes } from 'vue'

const props = withDefaults(
  defineProps<
    PrimitiveProps & {
      class?: HTMLAttributes['class']
    }
  >(),
  { as: 'div' },
)
</script>

<template>
  <Primitive :as="props.as" :as-child="props.asChild" data-slot="number-field-content" :class="['fui-number-field-content relative', props.class]">
    <slot />
  </Primitive>
</template>
```

`components/ui/number-field/NumberFieldDecrement.vue`

```vue
<script lang="ts">
/** Lowers the value of the number field by one step. */
export default {}
</script>

<script setup lang="ts">
import { MinusIcon } from '@lucide/vue'

import type { NumberFieldDecrementProps } from 'reka-ui'
import type { HTMLAttributes } from 'vue'
import { reactiveOmit } from '@vueuse/core'
import { NumberFieldDecrement, useForwardProps } from 'reka-ui'

const props = defineProps<NumberFieldDecrementProps & { class?: HTMLAttributes['class'] }>()

const delegatedProps = reactiveOmit(props, 'class')

const forwarded = useForwardProps(delegatedProps)
</script>

<template>
  <NumberFieldDecrement
    data-slot="number-field-decrement"
    v-bind="forwarded"
    :class="['absolute top-1/2 inset-s-0 -translate-y-1/2 fui-number-field-step disabled:cursor-not-allowed disabled:fui-disabled', props.class]"
  >
    <slot>
      <MinusIcon data-icon />
    </slot>
  </NumberFieldDecrement>
</template>
```

`components/ui/number-field/NumberFieldIncrement.vue`

```vue
<script lang="ts">
/** Raises the value of the number field by one step. */
export default {}
</script>

<script setup lang="ts">
import { PlusIcon } from '@lucide/vue'

import type { NumberFieldIncrementProps } from 'reka-ui'
import type { HTMLAttributes } from 'vue'
import { reactiveOmit } from '@vueuse/core'
import { NumberFieldIncrement, useForwardProps } from 'reka-ui'

const props = defineProps<NumberFieldIncrementProps & { class?: HTMLAttributes['class'] }>()

const delegatedProps = reactiveOmit(props, 'class')

const forwarded = useForwardProps(delegatedProps)
</script>

<template>
  <NumberFieldIncrement
    data-slot="number-field-increment"
    v-bind="forwarded"
    :class="['absolute top-1/2 inset-e-0 -translate-y-1/2 fui-number-field-step disabled:cursor-not-allowed disabled:fui-disabled', props.class]"
  >
    <slot>
      <PlusIcon data-icon />
    </slot>
  </NumberFieldIncrement>
</template>
```

`components/ui/number-field/NumberFieldInput.vue`

```vue
<script lang="ts">
/** Lets the user type a number into the number field. */
export default {}
</script>

<script setup lang="ts">
import type { NumberFieldInputProps } from 'reka-ui'
import type { HTMLAttributes } from 'vue'
import { reactiveOmit } from '@vueuse/core'
import { injectFieldRootContext, NumberFieldInput, useForwardProps } from 'reka-ui'
import { computed } from 'vue'

const props = defineProps<NumberFieldInputProps & { class?: HTMLAttributes['class'] }>()

const forwarded = useForwardProps(reactiveOmit(props, 'class'))

// Takes the Field's label, description and state, as Reka's Checkbox does. Delete once Reka's NumberField reads the Field itself.
const field = injectFieldRootContext(null)
const fieldAttrs = computed(() =>
  field
    ? {
        ...field.dataAttributes.value,
        'aria-labelledby': field.labelId.value,
        'aria-describedby': field.describedBy.value,
        'aria-invalid': (field.invalid.value && !field.disabled.value) || undefined,
        onFocus: () => field.handleControlFocus(),
        onBlur: () => field.handleControlBlur(),
      }
    : {},
)
</script>

<template>
  <NumberFieldInput
    v-bind="{ ...fieldAttrs, ...forwarded }"
    data-slot="number-field-input"
    :class="['fui-number-field-input outline-none transition-colors disabled:pointer-events-none disabled:cursor-not-allowed disabled:fui-disabled', props.class]"
  />
</template>
```

## API of the items the example uses

### Field

[Full docs](https://ui.frontic.com/components/ui/field.md) · `npx @frontic/ui add field`

#### Field

Groups a label, an input, a description and an error of one form field, and validates its input.

`data-slot="field"` · `Field.vue`

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `name` | `string` |  | The name of the field. Submitted with its owning form as part of a name/value pair, and used to match server `errors` on a `FormRoot`. Takes precedence over the `name` of the control. |
| `disabled` | `boolean` | `false` | When `true`, prevents the user from interacting with the field's control. Takes precedence over the `disabled` of the control. |
| `required` | `boolean` | `false` | When `true`, indicates that the user must set the value before the owning form can be submitted. |
| `invalid` | `boolean` |  | When `true`, marks the field invalid regardless of its own validation. Useful when the field state is controlled by an external library. |
| `dirty` | `boolean` |  | Whether the field's value has changed from its initial value. Useful when the field state is controlled by an external library. |
| `touched` | `boolean` |  | Whether the field has been touched (its control blurred). Useful when the field state is controlled by an external library. |
| `validate` | `FieldValidateFn`: `(value: unknown, formValues: Record<string, unknown>): FieldValidateResult \| Promise<FieldValidateResult>` |  | Custom validation function. Return an error message (or array of messages) when invalid, or `null`/`undefined` when valid. Receives the control's value and the values of every named field in the owning form.<br><br>Can be async, but an async `validate` does not prevent form submission when `validationMode` is `onSubmit`. |
| `validationMode` | `FieldValidationMode`: `'onBlur' \| 'onChange' \| 'onSubmit'` | `'onSubmit'` | When the field (re-)runs validation. Takes precedence over the `validationMode` of an ancestor `FormRoot`.<br>- `onSubmit`: when the form is submitted, then on every change after that.<br>- `onBlur`: when the control loses focus.<br>- `onChange`: on every change to the control's value. |
| `validationDebounceTime` | `number` |  | How long to wait (in ms) between `validate` calls when validating on change. |
| `asChild` | `boolean` | `false` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://www.reka-ui.com/docs/guides/composition) guide for more details. |
| `as` | `AsTag \| Component`: `ComponentOptions<any, any, any, ComputedOptions, MethodOptions, any, any, any, string, {}, {}, string, {}, {}, {}, string, ComponentProvideOptions> \| (props: any, ctx: Omit<{ attrs: Attrs; slots: Readonly<InternalSlots>; emit: (event: string, ...args: any[]) => void; expose: <Exposed extends Record<string, any> = Record<string, any>>(exposed?: Exposed \| undefined) => void; }, 'expose'>): any \| ComponentPublicInstanceConstructor<any, any, any, any, ComputedOptions, MethodOptions> \| 'a' \| 'button' \| 'div' \| 'form' \| 'h2' \| 'h3' \| 'img' \| 'input' \| 'label' \| 'li' \| 'nav' \| 'ol' \| 'p' \| 'span' \| 'svg' \| 'ul' \| 'template' \| {} & string` |  | The element or component this component should render as. Can be overwritten by `asChild`. |
| `class` | `ClassValue` |  | Classes added to the part's own element, after its recipe classes. |
| `orientation` | `FieldOrientation`: `'vertical' \| 'horizontal' \| 'responsive'` | `'vertical'` | Label above the control, beside it, or `responsive`: beside it once the field group is wide enough. |

| Slot | Slot props | Description |
| --- | --- | --- |
| `default` | `{ invalid: boolean; errors: string[]; }` | The label, control, description and error; gets `invalid` and the current `errors`. |

| Data attribute | Values | Description |
| --- | --- | --- |
| `data-horizontal` |  | Present when the part is laid out horizontally. |
| `data-orientation` | `'vertical' \| 'horizontal' \| 'responsive'` | Carries the `orientation` prop. |

#### FieldContent

Groups the label and description that sit beside the control of a field. Renders a `<div>`.

`data-slot="field-content"` · `FieldContent.vue`

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `asChild` | `boolean` | `false` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://www.reka-ui.com/docs/guides/composition) guide for more details. |
| `as` | `AsTag \| Component`: `ComponentOptions<any, any, any, ComputedOptions, MethodOptions, any, any, any, string, {}, {}, string, {}, {}, {}, string, ComponentProvideOptions> \| (props: any, ctx: Omit<{ attrs: Attrs; slots: Readonly<InternalSlots>; emit: (event: string, ...args: any[]) => void; expose: <Exposed extends Record<string, any> = Record<string, any>>(exposed?: Exposed \| undefined) => void; }, 'expose'>): any \| ComponentPublicInstanceConstructor<any, any, any, any, ComputedOptions, MethodOptions> \| 'a' \| 'button' \| 'div' \| 'form' \| 'h2' \| 'h3' \| 'img' \| 'input' \| 'label' \| 'li' \| 'nav' \| 'ol' \| 'p' \| 'span' \| 'svg' \| 'ul' \| 'template' \| {} & string` | `'div'` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `class` | `ClassValue` |  | Classes added to the part's own element, after its recipe classes. |

#### FieldDescription

Gives help text for a field, such as what to enter.

`data-slot="field-description"` · `FieldDescription.vue`

Styling: `field-description`, which extends [`hint`](https://ui.frontic.com/DESIGN.md#hint) and [`link-primary`](https://ui.frontic.com/DESIGN.md#link-primary). Change them there and every part that extends them follows.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `id` | `string` |  | Id of the element. Auto-generated when not provided. |
| `asChild` | `boolean` | `false` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://www.reka-ui.com/docs/guides/composition) guide for more details. |
| `as` | `AsTag \| Component`: `ComponentOptions<any, any, any, ComputedOptions, MethodOptions, any, any, any, string, {}, {}, string, {}, {}, {}, string, ComponentProvideOptions> \| (props: any, ctx: Omit<{ attrs: Attrs; slots: Readonly<InternalSlots>; emit: (event: string, ...args: any[]) => void; expose: <Exposed extends Record<string, any> = Record<string, any>>(exposed?: Exposed \| undefined) => void; }, 'expose'>): any \| ComponentPublicInstanceConstructor<any, any, any, any, ComputedOptions, MethodOptions> \| 'a' \| 'button' \| 'div' \| 'form' \| 'h2' \| 'h3' \| 'img' \| 'input' \| 'label' \| 'li' \| 'nav' \| 'ol' \| 'p' \| 'span' \| 'svg' \| 'ul' \| 'template' \| {} & string` |  | The element or component this component should render as. Can be overwritten by `asChild`. |
| `class` | `ClassValue` |  | Classes added to the part's own element, after its recipe classes. |

#### FieldError

Shows why the input of a field is invalid, from its own validation, from the server or from a form library.

`data-slot="field-error"` · `FieldError.vue`

Styling: `field-error`, which extends [`error`](https://ui.frontic.com/DESIGN.md#error). Change it there and every part that extends it follows.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `id` | `string` |  | Id of the element. Auto-generated when not provided. |
| `match` | `boolean \| keyof ValidityState`: `boolean \| 'badInput' \| 'customError' \| 'patternMismatch' \| 'rangeOverflow' \| 'rangeUnderflow' \| 'stepMismatch' \| 'tooLong' \| 'tooShort' \| 'typeMismatch' \| 'valid' \| 'valueMissing'` |  | Restricts when this error renders:<br>- a `ValidityState` key (e.g. `"valueMissing"`) — renders when that constraint fails.<br>- `true` — always renders, letting an external library control visibility.<br>- omitted — renders whenever the field is invalid. |
| `forceMount` | `boolean` | `false` | Used to force mounting when more control is needed. Useful when controlling animation with Vue animation libraries. |
| `asChild` | `boolean` | `false` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://www.reka-ui.com/docs/guides/composition) guide for more details. |
| `as` | `AsTag \| Component`: `ComponentOptions<any, any, any, ComputedOptions, MethodOptions, any, any, any, string, {}, {}, string, {}, {}, {}, string, ComponentProvideOptions> \| (props: any, ctx: Omit<{ attrs: Attrs; slots: Readonly<InternalSlots>; emit: (event: string, ...args: any[]) => void; expose: <Exposed extends Record<string, any> = Record<string, any>>(exposed?: Exposed \| undefined) => void; }, 'expose'>): any \| ComponentPublicInstanceConstructor<any, any, any, any, ComputedOptions, MethodOptions> \| 'a' \| 'button' \| 'div' \| 'form' \| 'h2' \| 'h3' \| 'img' \| 'input' \| 'label' \| 'li' \| 'nav' \| 'ol' \| 'p' \| 'span' \| 'svg' \| 'ul' \| 'template' \| {} & string` |  | The element or component this component should render as. Can be overwritten by `asChild`. |
| `class` | `ClassValue` |  | Classes added to the part's own element, after its recipe classes. |
| `errors` | `(string \| { message: string \| undefined; } \| undefined)[]` |  | Messages from outside the Field, such as vee-validate's or TanStack Form's; shown instead of the Field's own, duplicates dropped. |

| Slot | Slot props | Description |
| --- | --- | --- |
| `default` | `{ errors: string[]; }` | Replaces the messages; gets the current `errors`. |

#### FieldGroup

Stacks several fields of a form together. Renders a `<div>`.

`data-slot="field-group"` · `FieldGroup.vue`

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `asChild` | `boolean` | `false` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://www.reka-ui.com/docs/guides/composition) guide for more details. |
| `as` | `AsTag \| Component`: `ComponentOptions<any, any, any, ComputedOptions, MethodOptions, any, any, any, string, {}, {}, string, {}, {}, {}, string, ComponentProvideOptions> \| (props: any, ctx: Omit<{ attrs: Attrs; slots: Readonly<InternalSlots>; emit: (event: string, ...args: any[]) => void; expose: <Exposed extends Record<string, any> = Record<string, any>>(exposed?: Exposed \| undefined) => void; }, 'expose'>): any \| ComponentPublicInstanceConstructor<any, any, any, any, ComputedOptions, MethodOptions> \| 'a' \| 'button' \| 'div' \| 'form' \| 'h2' \| 'h3' \| 'img' \| 'input' \| 'label' \| 'li' \| 'nav' \| 'ol' \| 'p' \| 'span' \| 'svg' \| 'ul' \| 'template' \| {} & string` | `'div'` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `class` | `ClassValue` |  | Classes added to the part's own element, after its recipe classes. |

#### FieldLabel

Labels the input of a field.

`data-slot="field-label"` · `FieldLabel.vue`

Styling: `field-label`, which extends [`label`](https://ui.frontic.com/DESIGN.md#label). Change it there and every part that extends it follows.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `nativeLabel` | `boolean` | `true` | Whether the label renders a native `label` element. Set to `false` when rendering another element (e.g. `as="div"`): it then drops `for`, focuses the control on click, and relies on the control's `aria-labelledby`.<br><br>Useful for button controls like `SelectTrigger`, where a native label would forward clicks and `:hover` to the button. |
| `for` | `string` |  | The id of the element the label is associated with. |
| `asChild` | `boolean` | `false` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://www.reka-ui.com/docs/guides/composition) guide for more details. |
| `as` | `AsTag \| Component`: `ComponentOptions<any, any, any, ComputedOptions, MethodOptions, any, any, any, string, {}, {}, string, {}, {}, {}, string, ComponentProvideOptions> \| (props: any, ctx: Omit<{ attrs: Attrs; slots: Readonly<InternalSlots>; emit: (event: string, ...args: any[]) => void; expose: <Exposed extends Record<string, any> = Record<string, any>>(exposed?: Exposed \| undefined) => void; }, 'expose'>): any \| ComponentPublicInstanceConstructor<any, any, any, any, ComputedOptions, MethodOptions> \| 'a' \| 'button' \| 'div' \| 'form' \| 'h2' \| 'h3' \| 'img' \| 'input' \| 'label' \| 'li' \| 'nav' \| 'ol' \| 'p' \| 'span' \| 'svg' \| 'ul' \| 'template' \| {} & string` |  | The element or component this component should render as. Can be overwritten by `asChild`. |
| `class` | `ClassValue` |  | Classes added to the part's own element, after its recipe classes. |

#### FieldLegend

Titles a set of related fields. Renders a `<legend>`.

`data-slot="field-legend"` · `FieldLegend.vue`

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `asChild` | `boolean` | `false` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://www.reka-ui.com/docs/guides/composition) guide for more details. |
| `as` | `AsTag \| Component`: `ComponentOptions<any, any, any, ComputedOptions, MethodOptions, any, any, any, string, {}, {}, string, {}, {}, {}, string, ComponentProvideOptions> \| (props: any, ctx: Omit<{ attrs: Attrs; slots: Readonly<InternalSlots>; emit: (event: string, ...args: any[]) => void; expose: <Exposed extends Record<string, any> = Record<string, any>>(exposed?: Exposed \| undefined) => void; }, 'expose'>): any \| ComponentPublicInstanceConstructor<any, any, any, any, ComputedOptions, MethodOptions> \| 'a' \| 'button' \| 'div' \| 'form' \| 'h2' \| 'h3' \| 'img' \| 'input' \| 'label' \| 'li' \| 'nav' \| 'ol' \| 'p' \| 'span' \| 'svg' \| 'ul' \| 'template' \| {} & string` | `'legend'` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `class` | `ClassValue` |  | Classes added to the part's own element, after its recipe classes. |
| `variant` | `'label' \| 'legend'` | `'legend'` | Whether the legend reads as a section heading or as a field label. |

| Data attribute | Values | Description |
| --- | --- | --- |
| `data-variant` | `'label' \| 'legend'` | Carries the `variant` prop. |

#### FieldSeparator

Separates fields of a form, optionally with a short text in between. Renders a `<div>`.

`data-slot="field-separator"` · `FieldSeparator.vue`

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `class` | `ClassValue` |  | Classes added to the part's own element, after its recipe classes. |

| Data attribute | Values | Description |
| --- | --- | --- |
| `data-content` | `'true' \| 'false'` | `true` when the separator has text in it. |

#### FieldSet

Groups related fields under one legend. Renders a `<fieldset>`.

`data-slot="field-set"` · `FieldSet.vue`

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `asChild` | `boolean` | `false` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://www.reka-ui.com/docs/guides/composition) guide for more details. |
| `as` | `AsTag \| Component`: `ComponentOptions<any, any, any, ComputedOptions, MethodOptions, any, any, any, string, {}, {}, string, {}, {}, {}, string, ComponentProvideOptions> \| (props: any, ctx: Omit<{ attrs: Attrs; slots: Readonly<InternalSlots>; emit: (event: string, ...args: any[]) => void; expose: <Exposed extends Record<string, any> = Record<string, any>>(exposed?: Exposed \| undefined) => void; }, 'expose'>): any \| ComponentPublicInstanceConstructor<any, any, any, any, ComputedOptions, MethodOptions> \| 'a' \| 'button' \| 'div' \| 'form' \| 'h2' \| 'h3' \| 'img' \| 'input' \| 'label' \| 'li' \| 'nav' \| 'ol' \| 'p' \| 'span' \| 'svg' \| 'ul' \| 'template' \| {} & string` | `'fieldset'` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `class` | `ClassValue` |  | Classes added to the part's own element, after its recipe classes. |

#### FieldTitle

Shows the title of a field next to its description. Renders a `<div>`.

`data-slot="field-title"` · `FieldTitle.vue`

Styling: `field-label`, which extends [`label`](https://ui.frontic.com/DESIGN.md#label). Change it there and every part that extends it follows.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `asChild` | `boolean` | `false` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://www.reka-ui.com/docs/guides/composition) guide for more details. |
| `as` | `AsTag \| Component`: `ComponentOptions<any, any, any, ComputedOptions, MethodOptions, any, any, any, string, {}, {}, string, {}, {}, {}, string, ComponentProvideOptions> \| (props: any, ctx: Omit<{ attrs: Attrs; slots: Readonly<InternalSlots>; emit: (event: string, ...args: any[]) => void; expose: <Exposed extends Record<string, any> = Record<string, any>>(exposed?: Exposed \| undefined) => void; }, 'expose'>): any \| ComponentPublicInstanceConstructor<any, any, any, any, ComputedOptions, MethodOptions> \| 'a' \| 'button' \| 'div' \| 'form' \| 'h2' \| 'h3' \| 'img' \| 'input' \| 'label' \| 'li' \| 'nav' \| 'ol' \| 'p' \| 'span' \| 'svg' \| 'ul' \| 'template' \| {} & string` | `'div'` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `class` | `ClassValue` |  | Classes added to the part's own element, after its recipe classes. |

#### FieldValidity

Renders from the validation state of a field, such as a custom message or a strength meter.

| Slot | Slot props | Description |
| --- | --- | --- |
| `default` | `{ validity: Omit<Record<keyof ValidityState, boolean>, "valid"> & { valid: boolean \| null; }; errors: string[]; error: string; value: unknown; initialValue: unknown; }` | Gets the field's `validity` (`valid` is `null` until there is one), its `errors`, the first `error`, the `value` validated last and the `initialValue`. |
