---
name: input-otp
title: Input OTP
url: https://ui.frontic.com/components/ui/input-otp.md
tier: ui
install: npx @frontic/ui add input-otp
files:
  - components/ui/input-otp/InputOTPGroup.vue
  - components/ui/input-otp/InputOTPSeparator.vue
  - components/ui/input-otp/InputOTPSlot.vue
  - components/ui/input-otp/InputOtp.vue
  - components/ui/input-otp/index.ts
registryDependencies:
  - use-field-control
dependencies:
  - "@lucide/vue"
  - "@vueuse/core"
  - reka-ui
  - vue-input-otp
---

# Input OTP

Lets the user type or paste a one-time code across several slots, such as the code a sign-in email sends.

## Install

```sh
npx @frontic/ui add input-otp
```

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

Used by: [Payment Method](https://ui.frontic.com/components/sections/payment-method.md), [Sign In](https://ui.frontic.com/components/sections/sign-in.md)

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

## Examples

```vue
<script setup lang="ts">
import { Field, FieldDescription, FieldLabel } from '@/components/ui/field'
import { InputOtp, InputOTPGroup, InputOTPSeparator, InputOTPSlot } from '@/components/ui/input-otp'
</script>

<template>
  <Field name="code">
    <FieldLabel>Verification code</FieldLabel>
    <InputOtp :maxlength="6" autocomplete="one-time-code">
      <InputOTPGroup>
        <InputOTPSlot v-for="index in 3" :key="index" :index="index - 1" />
      </InputOTPGroup>
      <InputOTPSeparator />
      <InputOTPGroup>
        <InputOTPSlot v-for="index in 3" :key="index" :index="index + 2" />
      </InputOTPGroup>
    </InputOtp>
    <FieldDescription>We sent it to you@example.com.</FieldDescription>
  </Field>
</template>
```

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

## Anatomy

```vue
<InputOtp>
  <InputOTPGroup>
    <InputOTPSlot />
  </InputOTPGroup>
  <InputOTPSeparator />
</InputOtp>
```

## API reference

### InputOtp

Lets the user enter a one-time code across several slots.

Also exported as `InputOTP`.

`data-slot="input-otp"` · `InputOtp.vue`

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `maxlength` (required) | `number` |  | How many characters the code has: one slot each, and `complete` fires when the last is filled. |
| `textAlign` | `'center' \| 'right' \| 'left'` |  | Aligns the text in the hidden `<input>`, which decides where a long press or click-and-hold lands. |
| `inputmode` | `'numeric' \| 'text'` |  | The on-screen keyboard mobile browsers open: digits, or full text. |
| `containerClass` | `string` |  | Classes added to the element that wraps the slots and the hidden input. |
| `pushPasswordManagerStrategy` | `'none' \| 'increase-width'` |  | How to keep a password manager's badge off the last slot: widen the field, or do nothing. |
| `noScriptCssFallback` | `string \| null`: `null \| string` |  | CSS that keeps the hidden input usable when JavaScript is off; `null` leaves it out. |
| `defaultValue` | `any` |  | The code the field starts with when uncontrolled. |
| `pasteTransformer` | `((pasted: string \| undefined) => string)`: `(pasted: string \| undefined): string` |  | Rewrites pasted text before it fills the slots, e.g. to strip the dash from `123-456`. |
| `nonce` | `string` |  | Applied to the injected `<style>` tag, for a nonce-based `style-src` CSP. |
| `accept` | `string` |  | Set on the hidden `<input>` the code is typed into, as its `accept` attribute. |
| `alt` | `string` |  | Set on the hidden `<input>` the code is typed into, as its `alt` attribute. |
| `autocomplete` | `string` |  | The autocomplete hint; `one-time-code` lets the browser offer a code it received by SMS. |
| `autofocus` | `boolean` | `false` | Focuses the field when it mounts. |
| `capture` | `boolean \| 'user' \| 'environment'` |  | Set on the hidden `<input>` the code is typed into, as its `capture` attribute. |
| `checked` | `boolean \| any[] \| Set<any>` |  | Set on the hidden `<input>` the code is typed into, as its `checked` attribute. |
| `crossorigin` | `string` |  | Set on the hidden `<input>` the code is typed into, as its `crossorigin` attribute. |
| `disabled` | `boolean` | `false` | Disables the field. |
| `enterKeyHint` | `'done' \| 'search' \| 'enter' \| 'go' \| 'next' \| 'previous' \| 'send'` |  | Set on the hidden `<input>` the code is typed into, as its `enterKeyHint` attribute. |
| `form` | `string` |  | Set on the hidden `<input>` the code is typed into, as its `form` attribute. |
| `formaction` | `string` |  | Set on the hidden `<input>` the code is typed into, as its `formaction` attribute. |
| `formenctype` | `string` |  | Set on the hidden `<input>` the code is typed into, as its `formenctype` attribute. |
| `formmethod` | `string` |  | Set on the hidden `<input>` the code is typed into, as its `formmethod` attribute. |
| `formnovalidate` | `boolean` | `false` | Set on the hidden `<input>` the code is typed into, as its `formnovalidate` attribute. |
| `formtarget` | `string` |  | Set on the hidden `<input>` the code is typed into, as its `formtarget` attribute. |
| `height` | `number` |  | Set on the hidden `<input>` the code is typed into, as its `height` attribute. |
| `indeterminate` | `boolean` | `false` | Set on the hidden `<input>` the code is typed into, as its `indeterminate` attribute. |
| `list` | `string` |  | Set on the hidden `<input>` the code is typed into, as its `list` attribute. |
| `max` | `number` |  | Set on the hidden `<input>` the code is typed into, as its `max` attribute. |
| `min` | `number` |  | Set on the hidden `<input>` the code is typed into, as its `min` attribute. |
| `minlength` | `number` |  | Set on the hidden `<input>` the code is typed into, as its `minlength` attribute. |
| `multiple` | `boolean` | `false` | Set on the hidden `<input>` the code is typed into, as its `multiple` attribute. |
| `name` | `string` |  | Set on the hidden `<input>` the code is typed into, as its `name` attribute. |
| `pattern` | `string` |  | A regular expression every typed or pasted character must match; others are dropped. |
| `placeholder` | `string` |  | Set on the hidden `<input>` the code is typed into, as its `placeholder` attribute. |
| `readonly` | `boolean` | `false` | Set on the hidden `<input>` the code is typed into, as its `readonly` attribute. |
| `required` | `boolean` | `false` | Set on the hidden `<input>` the code is typed into, as its `required` attribute. |
| `size` | `number` |  | Set on the hidden `<input>` the code is typed into, as its `size` attribute. |
| `spellcheck` | `boolean` | `false` | Set on the hidden `<input>` the code is typed into, as its `spellcheck` attribute. |
| `src` | `string` |  | Set on the hidden `<input>` the code is typed into, as its `src` attribute. |
| `step` | `number` |  | Set on the hidden `<input>` the code is typed into, as its `step` attribute. |
| `type` | `string` |  | Set on the hidden `<input>` the code is typed into, as its `type` attribute. |
| `value` | `any` |  | The code shown, when the field is controlled. |
| `width` | `number` |  | Set on the hidden `<input>` the code is typed into, as its `width` attribute. |
| `modelValue` | `string` |  | The code, bound with v-model. |
| `class` | `ClassValue` |  | Classes added to the part's own element, after its recipe classes. |

| Event | Payload | Description |
| --- | --- | --- |
| `update:modelValue` | `value: string` | Fires with the new value when `modelValue` changes; `v-model` binds it. |
| `input` | `value: string` | Fires with the code on every keystroke and paste. |
| `select` | `e: Event` | Fires when text in the hidden `<input>` is selected. |
| `focus` | `e: FocusEvent` | Fires when the field takes focus. |
| `change` | `e: Event` | Fires when the hidden `<input>` commits a change. |
| `blur` | `e: FocusEvent` | Fires when the field loses focus. |
| `complete` | `value: string` | Fires with the code once every slot is filled. |
| `mouseover` | `e: MouseEvent` | Fires when the pointer moves onto the field. |
| `mouseleave` | `e: MouseEvent` | Fires when the pointer leaves the field. |
| `paste` | `e: ClipboardEvent` | Fires when text is pasted into the field, before it fills the slots. |

| Slot | Slot props | Description |
| --- | --- | --- |
| `default` | `{ slots: SlotProps[]; isFocused: boolean; isHovering: boolean; }` | Holds the code's slots and separators; gets each slot's character and state, and whether the input is focused or hovered. |

### InputOTPGroup

Groups neighbouring slots of the one-time code. Renders a `<div>`.

`data-slot="input-otp-group"` · `InputOTPGroup.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. |

### InputOTPSeparator

Separates groups of slots in the one-time code. Renders a `<div>`.

`data-slot="input-otp-separator"` · `InputOTPSeparator.vue`

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

### InputOTPSlot

Shows one character of the one-time code. Renders a `<div>`.

`data-slot="input-otp-slot"` · `InputOTPSlot.vue`

Styling: `input-otp-slot`, 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 |
| --- | --- | --- | --- |
| `index` (required) | `number` |  | Which character of the code this slot shows, counting from 0. |
| `class` | `ClassValue` |  | Classes added to the part's own element, after its recipe classes. |

| Data attribute | Values | Description |
| --- | --- | --- |
| `data-active` |  | Present on the slot the caret is in. |

## Styling

| Part | Recipe |
| --- | --- |
| `default` | [`input-otp`](https://ui.frontic.com/DESIGN.md#input-otp) |
| `separator` | [`input-otp-separator`](https://ui.frontic.com/DESIGN.md#input-otp-separator) |
| `group` | [`input-otp-group`](https://ui.frontic.com/DESIGN.md#input-otp-group) |
| `slot` | [`input-otp-slot`](https://ui.frontic.com/DESIGN.md#input-otp-slot) |
| `caret` | [`input-otp-caret`](https://ui.frontic.com/DESIGN.md#input-otp-caret) |
| `disabled` | [`disabled`](https://ui.frontic.com/DESIGN.md#disabled) |

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

## Source

`components/ui/input-otp/InputOTPGroup.vue`

```vue
<script lang="ts">
/** Groups neighbouring slots of the one-time code. */
export default {}
</script>

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

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

const delegatedProps = reactiveOmit(props, 'class')

const forwarded = useForwardProps(delegatedProps)
</script>

<template>
  <Primitive data-slot="input-otp-group" v-bind="forwarded" :class="['fui-input-otp-group', props.class]">
    <slot />
  </Primitive>
</template>
```

`components/ui/input-otp/InputOTPSeparator.vue`

```vue
<script lang="ts">
/** Separates groups of slots in the one-time code. */
export default {}
</script>

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

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

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

const delegatedProps = reactiveOmit(props, 'class')
const forwarded = useForwardProps(delegatedProps)
</script>

<template>
  <div data-slot="input-otp-separator" role="separator" v-bind="forwarded" :class="['fui-input-otp-separator', props.class]">
    <slot>
      <MinusIcon />
    </slot>
  </div>
</template>
```

`components/ui/input-otp/InputOTPSlot.vue`

```vue
<script lang="ts">
/** Shows one character of the one-time code. */
export default {}
</script>

<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { reactiveOmit } from '@vueuse/core'
import { useForwardProps } from 'reka-ui'
import { computed } from 'vue'
import { useVueOTPContext } from 'vue-input-otp'

const props = defineProps<{
  /** Which character of the code this slot shows, counting from 0. */
  index: number
  class?: HTMLAttributes['class']
}>()

const delegatedProps = reactiveOmit(props, 'class')

const forwarded = useForwardProps(delegatedProps)

const context = useVueOTPContext()

const slot = computed(() => context?.value.slots[props.index])
</script>

<template>
  <div v-bind="forwarded" data-slot="input-otp-slot" :data-active="slot?.isActive || undefined" :class="['fui-input-otp-slot relative outline-none transition-colors data-active:z-10', props.class]">
    {{ slot?.char }}
    <div v-if="slot?.hasFakeCaret" class="pointer-events-none absolute inset-0 flex items-center justify-center">
      <div class="fui-input-otp-caret animate-caret-blink duration-1000" />
    </div>
  </div>
</template>
```

`components/ui/input-otp/InputOtp.vue`

```vue
<script lang="ts">
/** Lets the user enter a one-time code across several slots. */
export default {}
</script>

<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import type { OTPInputEmits, OTPInputProps, SlotProps } from 'vue-input-otp'
import { reactiveOmit } from '@vueuse/core'
import { useForwardPropsEmits } from 'reka-ui'
import { OTPInput } from 'vue-input-otp'
import { normalizeClass, useAttrs } from 'vue'
import { useFieldControl } from '@library/composables/use-field-control'

const props = defineProps<
  OTPInputProps & {
    /** The code, bound with v-model. */
    modelValue?: string
    class?: HTMLAttributes['class']
  }
>()

const emits = defineEmits<OTPInputEmits & { (event: 'update:modelValue', value: string): void }>()

defineSlots<{
  /** Holds the code's slots and separators; gets each slot's character and state, and whether the input is focused or hovered. */
  default?: (props: { slots: SlotProps[]; isFocused: boolean; isHovering: boolean }) => unknown
}>()

const delegatedProps = reactiveOmit(props, 'class')

const forwarded = useForwardPropsEmits(delegatedProps, emits)

// Delete once Reka's PinInput reads the Field itself.
const attrs = useAttrs()
const { joined, report, field } = useFieldControl({
  props,
  forwarded,
  element: (): HTMLElement | null => document.getElementById((attrs.id as string | undefined) ?? field?.fieldId.value ?? ''),
  id: () => attrs.id as string | undefined,
  focus: 'focus',
  normalize: (value) => String(value ?? ''),
  isFilled: (value) => String(value ?? '').length >= props.maxlength,
})
</script>

<template>
  <OTPInput
    v-slot="slotProps"
    v-bind="joined"
    :container-class="normalizeClass(['fui-input-otp has-disabled:fui-disabled', props.class])"
    data-slot="input-otp"
    :spellcheck="false"
    class="disabled:cursor-not-allowed"
    @update:model-value="report"
  >
    <slot v-bind="slotProps" />
  </OTPInput>
</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`. |
