VTextField
The VTextField component provides a single-line text input field with support for various input types, validation, prefix/suffix text, and more.
Basic Usage
<template>
<VTextField
v-model="name"
label="Name"
/>
</template>
<script setup>
import { ref } from 'vue'
const name = ref('')
</script>
The value of the text field.
Label text for the text field.
HTML input type (text, password, email, number, tel, url, search, etc.).
Text to prepend inside the input.
Text to append inside the input.
counter
boolean | number | string
Display a character counter. Pass a number to set max length.
counterValue
number | ((value: any) => number)
Function or number to compute the counter value.
Always show the counter instead of only when focused.
Always show the placeholder.
Add a clear icon to remove the text.
Make the text field readonly.
Automatically focus the field when mounted.
Input Types
<template>
<div>
<VTextField
v-model="text"
label="Text"
type="text"
/>
<VTextField
v-model="password"
label="Password"
type="password"
/>
<VTextField
v-model="email"
label="Email"
type="email"
/>
<VTextField
v-model="number"
label="Number"
type="number"
/>
<VTextField
v-model="tel"
label="Phone"
type="tel"
/>
<VTextField
v-model="url"
label="Website"
type="url"
/>
<VTextField
v-model="search"
label="Search"
type="search"
/>
</div>
</template>
<script setup>
import { ref } from 'vue'
const text = ref('')
const password = ref('')
const email = ref('')
const number = ref('')
const tel = ref('')
const url = ref('')
const search = ref('')
</script>
Prefix and Suffix
<template>
<div>
<VTextField
v-model="price"
label="Price"
prefix="$"
type="number"
/>
<VTextField
v-model="weight"
label="Weight"
suffix="kg"
type="number"
/>
<VTextField
v-model="domain"
label="Domain"
prefix="https://"
suffix=".com"
/>
</div>
</template>
<script setup>
import { ref } from 'vue'
const price = ref('')
const weight = ref('')
const domain = ref('')
</script>
Character Counter
<template>
<div>
<!-- Simple counter -->
<VTextField
v-model="username"
label="Username"
counter
/>
<!-- Counter with max length -->
<VTextField
v-model="bio"
label="Bio"
:counter="100"
:rules="[v => v.length <= 100 || 'Max 100 characters']"
/>
<!-- Always visible counter -->
<VTextField
v-model="title"
label="Title"
counter
persistent-counter
/>
</div>
</template>
<script setup>
import { ref } from 'vue'
const username = ref('')
const bio = ref('')
const title = ref('')
</script>
Clearable
<template>
<VTextField
v-model="search"
label="Search"
clearable
type="search"
/>
</template>
<script setup>
import { ref } from 'vue'
const search = ref('')
</script>
Validation
<template>
<VForm>
<VTextField
v-model="email"
label="Email"
type="email"
:rules="[
v => !!v || 'Email is required',
v => /.+@.+\..+/.test(v) || 'Email must be valid'
]"
/>
<VTextField
v-model="username"
label="Username"
:counter="20"
:rules="[
v => !!v || 'Username is required',
v => (v && v.length >= 3) || 'Min 3 characters',
v => (v && v.length <= 20) || 'Max 20 characters',
v => /^[a-zA-Z0-9_]+$/.test(v) || 'Only letters, numbers, and underscores'
]"
/>
<VTextField
v-model="age"
label="Age"
type="number"
:rules="[
v => !!v || 'Age is required',
v => v > 0 || 'Age must be positive',
v => v < 150 || 'Age must be realistic'
]"
/>
</VForm>
</template>
<script setup>
import { ref } from 'vue'
const email = ref('')
const username = ref('')
const age = ref('')
</script>
<template>
<div>
<VTextField
v-model="email"
label="Email"
prepend-icon="mdi-email"
/>
<VTextField
v-model="password"
label="Password"
type="password"
prepend-inner-icon="mdi-lock"
append-inner-icon="mdi-eye"
/>
<VTextField
v-model="search"
label="Search"
prepend-inner-icon="mdi-magnify"
clearable
/>
</div>
</template>
<script setup>
import { ref } from 'vue'
const email = ref('')
const password = ref('')
const search = ref('')
</script>
Password Toggle
<template>
<VTextField
v-model="password"
label="Password"
:type="showPassword ? 'text' : 'password'"
:append-inner-icon="showPassword ? 'mdi-eye' : 'mdi-eye-off'"
@click:append-inner="showPassword = !showPassword"
/>
</template>
<script setup>
import { ref } from 'vue'
const password = ref('')
const showPassword = ref(false)
</script>
Disabled and Readonly
<template>
<div>
<VTextField
v-model="disabled"
label="Disabled"
disabled
/>
<VTextField
v-model="readonly"
label="Readonly"
readonly
/>
</div>
</template>
<script setup>
import { ref } from 'vue'
const disabled = ref('Cannot edit')
const readonly = ref('Cannot edit but can copy')
</script>
Model Modifiers
<template>
<VTextField
v-model.trim="username"
label="Username (auto-trimmed)"
hint="Whitespace will be automatically trimmed"
persistent-hint
/>
</template>
<script setup>
import { ref } from 'vue'
const username = ref('')
</script>
Emitted when the text field value changes.
update:focused
(focused: boolean) => void
Emitted when the focus state changes.
Emitted when the control area is clicked.
Emitted when mousedown occurs on the control area.
Default slot - can be used for custom input content.
Customize the counter display.
Customize the details area (below the input).