v-model Modifiers

.lazy, .number, .trim — Convenience Built In

v-model Modifiers

v-model accepts modifiers that tweak when and how the ref is updated: .lazy, .number, and .trim cover the common cases.

4 min read Level 1/5 #vue#forms#modifiers
What you'll learn
  • Use .lazy to sync on change instead of input
  • Use .number to coerce the value to a number
  • Use .trim to strip whitespace

v-model exposes three built-in modifiers that handle small but common chores: timing, type coercion, and whitespace trimming.

.lazy

By default v-model listens to the input event and fires on every keystroke. The .lazy modifier switches it to the change event, which fires when the input loses focus.

<script setup lang="ts">
import { ref } from 'vue'
const msg = ref('')
</script>

<template>
  <input v-model.lazy="msg" />
  <p>Synced on blur: {{ msg }}</p>
</template>

Use .lazy when running expensive logic in a watcher (search, validation) and you do not want it firing on every keystroke.

.number

User input is always a string. .number runs parseFloat on the value before storing it. If parsing fails the original string is kept, so combine it with a number input or numeric validation.

<script setup lang="ts">
import { ref } from 'vue'
const age = ref<number | null>(null)
</script>

<template>
  <input type="number" v-model.number="age" />
  <p>Type: {{ typeof age }} — Value: {{ age }}</p>
</template>

.trim

.trim calls String.prototype.trim on the value before storing. Useful for emails, usernames, and anything where leading or trailing spaces are accidents.

<input v-model.trim="email" />

Chaining

Modifiers stack. Order does not change the outcome for the built-ins, but the convention is to write them in the order they apply.

<input v-model.trim.lazy="name" />
<input type="number" v-model.number.lazy="quantity" />

Custom v-model on a component can also expose its own modifiers — you receive them as a second argument to defineModel.

Custom v-model on Components →