Skip to the solution
EasyFrontend7 min read

What are v-model modifiers?

203 views

The problem

Question presented to candidate: "Our age field stores "42" as a string, the username keeps stray spaces, and a search box fires an API call on every keystroke. Which v-model modifiers would you reach for, what exactly does each one do, and can a component define its own?"

What a strong answer should cover:

  • .lazy syncs on the change event (blur or Enter) instead of every input event.
  • .number converts with parseFloat, and keeps the original string when it cannot parse ("abc" stays "abc"); type="number" inputs get this automatically.
  • .trim strips leading and trailing whitespace from the stored value.
  • Modifiers chain: v-model.lazy.number.
  • On components, modifiers arrive as a modelModifiers prop (or <name>Modifiers for named models); custom ones are implemented with defineModel's set transformer. Built-in .trim and .number are applied for you.
  • Modifiers are a convenience for timing and type coercion, not validation.

Clarifying questions expected:

  • "Should an empty or invalid number be stored as a string, null, or rejected?"

Code / implementation expected: Yes. A form showing the three built-in modifiers; bonus for a custom modifier on a component.

  • v-model
  • modifiers

Try it yourself

Sketch your approach before you read the solution. That is what the interview tests.

Stuck? Get a hint.

A short nudge toward the approach. It will not give the answer away.

Solution

The solution is hidden so you can try first

7 min read Β· 9 sections

Read the code

Vue.lazy, .number and .trim side by side
<script setup>
import { ref } from "vue";

const plain = ref("");
const lazy = ref("");
const age = ref(0);
const qty = ref(0);
const username = ref("");
const both = ref(0);
</script>

<template>
  <!-- no modifier: syncs on every input event, always a string -->
  <input class="plain" v-model="plain" />

  <!-- .lazy: syncs on change (blur or Enter) instead of input -->
  <input class="lazy" v-model.lazy="lazy" />

  <!-- .number: parseFloat when it can, otherwise keeps the raw string -->
  <input class="age" v-model.number="age" />

  <!-- type="number" gets the .number behaviour automatically -->
  <input class="qty" type="number" v-model="qty" />

  <!-- .trim: strips leading and trailing whitespace -->
  <input class="user" v-model.trim="username" />

  <!-- modifiers chain -->
  <input class="both" v-model.lazy.number="both" />

  <pre>{{ { plain, lazy, age, qty, username, both } }}</pre>
</template>
VueA custom .capitalize modifier with defineModel
<!-- TitleInput.vue -->
<script setup>
const [title, modifiers] = defineModel("title", {
  set(value) {
    return modifiers.capitalize ? value.charAt(0).toUpperCase() + value.slice(1) : value;
  },
});
</script>
<template><input class="title" :value="title" @input="title = $event.target.value" /></template>

<!-- Parent: <TitleInput v-model:title.capitalize="heading" /> -->
<!-- Typing "hello" stored "Hello" in heading -->

Discussion

Other approaches, follow-ups and how it went in real interviews.

Sign in to join the discussion.

No comments yet. Share how you would answer it.

Question 17 of 92 in Vue.js

Keep your momentum going.

Mark this question solved to track your progress, then take the next one while it is fresh.

All Vue.js questions
Up nextMedium

How does Vue's reactivity system work?

Continue