Vue cookbook · Beginner
Build custom inputs with defineModel and modifiers
A custom input component needs v-model support with trimming or number conversion.
Approach
Use defineModel for the value; read modifiers (like v-model.trim) from the second tuple element and apply them
in the model's set transformer.
Solution
<!-- TextField.vue -->
<script setup lang="ts">
const [model, modifiers] = defineModel<string, "trim" | "lowercase">({
default: "",
set(value) {
let next = value;
if (modifiers.trim) next = next.trim();
if (modifiers.lowercase) next = next.toLowerCase();
return next;
},
});
defineProps<{ label: string; error?: string }>();
const id = useId();
</script>
<template>
<label :for="id">{{ label }}</label>
<input :id="id" v-model="model" :aria-invalid="!!error" :aria-describedby="error ? `${id}-error` : undefined" />
<p v-if="error" :id="`${id}-error`" role="alert">{{ error }}</p>
</template>
<!-- Parent -->
<script setup lang="ts">
import { ref } from "vue";
import TextField from "./TextField.vue";
const email = ref("");
</script>
<template>
<TextField v-model.trim.lowercase="email" label="Email" />
<p>Saved as: {{ email }}</p>
</template>
Pitfalls
- Mutating the prop directly instead of using
defineModel. - Generating random IDs for labels that differ between server and client;
useId()(Vue 3.5) is SSR-safe. - Forgetting accessible labels and error associations on custom inputs.
Variations
- Several models on one component:
defineModel("first")anddefineModel("last")forv-model:first. - Use the
gettransformer to format the displayed value (for example currency).
Further reading: v-model modifiers
Reference: https://vuejs.org/guide/components/v-model.html#handling-v-model-modifiers
More Vue recipes
- Access child component methods with template refs and defineExpose
- Add SEO metadata and structured data in Nuxt
- Build an accessible modal with Teleport
- Catch component errors with an error boundary
- Debounce user input with a custom ref
- Fetch data in a composable and cancel stale requests
- Fetch, refresh and share data with Nuxt useFetch
- Implement a dark mode toggle that respects system settings