Skip to main content
You are viewing Pre-Alpha documentation.
Vuetify0 Logo
Theme
Mode
Palettes
Accessibility
Vuetify One

Sign in to Vuetify One

Access premium tools across the Vuetify ecosystem — Bin, Play, Studio, and more.

Not a subscriber? See what's included

Input

A headless text input component with integrated validation. Creates a createValidation context internally and auto-registers with parent createForm instances.


IntermediateMar 16, 2026

Usage

The Input supports text, email, password, and other native input types. Validation rules run on blur by default, with lazy and eager modifiers available.

We'll never share your email.
<script setup lang="ts">
  import { Input } from '@vuetify/v0'
  import { shallowRef } from 'vue'

  const email = shallowRef('')
</script>

<template>
  <div class="flex flex-col gap-1 max-w-sm mx-auto">
    <Input.Root
      id="email"
      v-model="email"
      label="Email"
      :rules="[
        (v: string) => !!v || 'Email is required',
        (v: string) => /.+@.+\..+/.test(v) || 'Must be a valid email',
      ]"
      type="email"
    >
      <label class="text-sm font-medium text-on-surface" for="email">
        Email
      </label>

      <Input.Control
        class="w-full px-3 py-2 rounded-lg border border-divider bg-surface text-on-surface placeholder:text-on-surface-variant/50 outline-none data-[focused]:border-primary data-[state=invalid]:border-error transition-colors"
        placeholder="you@example.com"
      />

      <Input.Description class="text-xs text-on-surface-variant">
        We'll never share your email.
      </Input.Description>

      <Input.Error v-slot="{ errors }" class="text-xs text-error">
        <span v-for="error in errors" :key="error">{{ error }}</span>
      </Input.Error>
    </Input.Root>
  </div>
</template>

Anatomy

vue
<script setup lang="ts">
  import { Input } from '@vuetify/v0'
</script>

<template>
  <Input.Root>
    <Input.Control />
    <Input.Description />
    <Input.Error />
  </Input.Root>
</template>

Architecture

Root creates a validation context, provides it to children, and manages focus/validation lifecycle. Control is the native <input> (or any element via as). Description and Error auto-wire their IDs into Control’s ARIA attributes.

Input Architecture

Use controls to zoom and pan. Click outside or press Escape to close.

Input Architecture

Examples

Contact Form

Multi-field form with createForm integration, lazy validation, and server-side error injection. Each Input.Root creates its own createValidation and auto-registers with the parent form.

File breakdown:

FileRole
useContact.tsComposable — form instance, field refs, submit with server-side validation
ContactForm.vueReusable component — three Input fields with different rules and types
contact-form.vueDemo — wires composable to form, shows submitted data

Key patterns:

  • validateOn="blur lazy" defers validation until the user blurs the field for the first time, then validates on every subsequent blur

  • :error and :error-messages inject server-side errors after submit — the email field shows “already registered” when taken@example.com is used

  • Input.Control as="textarea" renders the message field as a native textarea while keeping all validation and ARIA wiring

Try submitting with taken@example.com to see server-side error injection.

Debounced search with validateOn="input" for real-time validation. The composable watches the Input’s value ref directly — no event wiring needed.

File breakdown:

FileRole
useSearch.tsComposable — debounced search with mock results, watches the query ref
SearchInput.vueReusable component — Input with search icon, loading spinner, result count
search.vueDemo — renders SearchInput with a result list

Key patterns:

  • validateOn="input" validates on every keystroke (minimum 2 characters)

  • The composable watches the query ref with debounce from @vuetify/v0/utilities, demonstrating that value is a standard writable Ref

  • data-[focused]:border-primary and data-[state=invalid]:border-error style the input purely through data attributes — no slot props needed for visual states

Accessibility

Input.Control renders as a native <input> and manages all ARIA attributes automatically.

ARIA Attributes

AttributeValueNotes
aria-invalidtrueWhen validation fails or error prop is set
aria-labelLabel textFrom Root’s label prop
aria-describedbyDescription IDOnly present when Input.Description is mounted
aria-errormessageError IDOnly present when Input.Error is mounted and errors exist
aria-requiredtrueFrom Root’s required prop
requiredtrueNative attribute, from Root’s required prop
disabledtrueNative attribute, from Root’s disabled prop
readonlytrueNative attribute, from Root’s readonly prop

Keyboard Navigation

Standard native <input> keyboard behavior. No custom key handlers — the browser handles focus, selection, and editing.

API Reference

The following API details are for all variations of the Input component.

Input.Root

Props

name

string

Form field name

namespace

string

Namespace for context provision to children

Default: "v0:input:root"

type

string

Input type

Default: "text"

required

boolean

Whether this input is required

id

ID

Unique identifier (auto-generated if not provided)

Default: useId()

label

string

Optional display label

form

string

Associate with form by ID

disabled

MaybeRefOrGetter<boolean>

Disables this input

Default: false

readonly

MaybeRefOrGetter<boolean>

Makes this input readonly

rules

any[]

Validation rules

Default: []

validateOn

ValidateOn

When to trigger validation

Default: "blur"

error

boolean

Manual error state override — forces invalid regardless of validation

Default: false

errorMessages

MaybeArray<string>

Manual error messages — merged with rule-based errors

modelValue

string

Default: ""

Events

update:model-value

[value: string]

update:isFocused

[value: boolean]

Slots

default

InputRootSlotProps

Input.Control

Props

namespace

string

Default: "v0:input:root"

Slots

default

InputControlSlotProps

Input.Description

Props

namespace

string

Namespace for connecting to parent Input.Root

Default: "v0:input:root"

Slots

default

InputDescriptionSlotProps

Input.Error

Props

namespace

string

Namespace for connecting to parent Input.Root

Default: "v0:input:root"

Slots

default

InputErrorSlotProps

Recipes

validateOn Modes

Control when validation runs with the validateOn prop and optional lazy/eager modifiers:

vue
<template>
  <!-- Validate on blur (default) -->
  <Input.Root validate-on="blur" />

  <!-- Validate on every keystroke -->
  <Input.Root validate-on="input" />

  <!-- Only validate on form submit -->
  <Input.Root validate-on="submit" />

  <!-- Lazy: skip validation until first blur, then validate on blur -->
  <Input.Root validate-on="blur lazy" />

  <!-- Eager: after first error, validate on every keystroke -->
  <Input.Root validate-on="blur eager" />
</template>

Manual Error State

Override validation with the error and error-messages props for server-side errors:

vue
<template>
  <Input.Root
    :error="!!serverError"
    :error-messages="serverError"
    :rules="[(v) => !!v || 'Required']"
  >
    <Input.Control />
    <Input.Error v-slot="{ errors }">
      <span v-for="e in errors" :key="e">{{ e }}</span>
    </Input.Error>
  </Input.Root>
</template>

Data Attributes

Style interactive states without slot props:

vue
<template>
  <Input.Control class="data-[focused]:border-primary data-[state=invalid]:border-error" />
</template>
AttributeValuesComponents
data-statepristine, valid, invalidRoot, Control
data-dirtytrueRoot
data-focusedtrueRoot, Control
data-disabledtrueRoot, Control
data-readonlytrueRoot, Control
Was this page helpful?

© 2016-1970 Vuetify, LLC
Ctrl+/