引き続きNuxt3のトピックです。
Vue3のUIフレームワークであるvee-validateの組み合わせでフォームのバリデーションを組んでみます。というのも、vee-validate4の使用について少しハマってしまったので、その備忘録をかねて記述しています。
インストールと設定
Nuxt3とvee-validate4をインストールします。
npx nuxi init nuxt-app cd nuxt-app npm install npm i vee-validate @vee-validate/i18n @vee-validate/rules npm install --dev sass
今回は、i18nとルール、それからsassも一緒に入れておきます。
また、プラグイン定義でルールやロケールを設定します。
import { localize, setLocale } from "@vee-validate/i18n";
import en from "@vee-validate/i18n/dist/locale/en.json";
import ja from "@vee-validate/i18n/dist/locale/ja.json";
import AllRules from "@vee-validate/rules";
import { defineRule, configure } from "vee-validate";
import { defineNuxtPlugin } from "#app";
export default defineNuxtPlugin((_nuxtApp) => {
configure({
generateMessage: localize({
en,
ja,
}),
});
Object.keys(AllRules).forEach((rule) => {
defineRule(rule, AllRules[rule]); // 全ルールを使えるようにする
});
setLocale("ja");
});
Fieldのバリデーション
実際の使用例を見てみてます。今回の記事では、Composable APIを使うケースを想定しています。
<script lang="ts" setup>
import { useField } from "vee-validate";
const { value: username, errorMessage: usernameError } = useField(
"username",
"required|min:2", // バリデーションルールを文字列形式で指定
);
const { value: email, errorMessage: emailError } = useField(
"email",
"required|email", // バリデーションルールを文字列形式で指定
);
const submit = () => {
console.log(username.value, email.value);
};
</script>
<template>
<div class="form">
<div class="field">
<label for="username">username</label>
<input type="text" v-model="username" name="username" />
<small v-if="usernameError"
><span class="invalid">{{ usernameError }}</span></small
>
</div>
<div class="field">
<label for="email">email</label>
<input
type="text"
v-model="email"
name="email"
placeholder="admin@example.com"
/>
<small v-if="emailError"
><span class="invalid">{{ emailError }}</span></small
>
</div>
<div class="field">
<button type="button" @click="submit">登録</button>
</div>
</div>
</template>
<style lang="scss" scoped>
html {
font-size: 14px;
}
.form {
.field {
padding: 0.5rem 0;
}
input {
width: 15rem;
display: block;
}
label {
display: block;
font-weight: bold;
}
.invalid {
color: red;
}
}
</style>
useFieldでフォームフィールドごとの定義をしています。useFieldは、valueやerrorMessageといったオブジェクトを返します。
実際に動かした画面は以下のようになります。

Formのバリデーション
続いてFormのケースです。useFormというComposable APIを使います。
<script lang="ts" setup>
import { useForm, useField } from "vee-validate";
const { handleSubmit, errors } = useForm({
validationSchema: {
username: "required|min:2",
email: "required|email",
},
});
const { value: username } = useField("username");
const { value: email } = useField("email");
const submit = handleSubmit(() => {
console.log(username.value, email.value);
});
</script>
<template>
<div class="form">
<div class="field">
<label for="username">username</label>
<input type="text" v-model="username" name="username" />
<small v-if="errors.username"
><span class="invalid">{{ errors.username }}</span></small
>
</div>
<div class="field">
<label for="email">email</label>
<input
type="text"
v-model="email"
name="email"
placeholder="admin@example.com"
/>
<small v-if="errors.email"
><span class="invalid">{{ errors.email }}</span></small
>
</div>
<div class="field">
<button type="button" @click="submit">登録</button>
</div>
</div>
</template>
<style lang="scss" scoped>
html {
font-size: 14px;
}
.form {
.field {
padding: 0.5rem 0;
}
input {
width: 15rem;
display: block;
}
label {
display: block;
font-weight: bold;
}
.invalid {
color: red;
}
}
</style>
useFieldで定義していたバリデーションをuseFormで指定しています。useFieldは、useFormのformを自動的に検出してくれます。実際には、provide/injectの仕組みが内部で使用されており、useFormやuseFieldの呼び出し時にそれぞれ固有のSymbolでコンテキストがprovideされています。useFieldは、useFormでprovideされたformコンテキストを自身のコンポーネント内でinjectしています。そのため、上記の例で言うと、useFieldを先に呼び出し、useFormを後で呼び出すとuseFieldがformコンテキストを探せず期待した動きにならないことがあります(私自身ややハマってしまった)。初回表示時にuseFormがfieldを見つけられずエラーと扱ってしまいます。
<script lang="ts" setup>
import { useForm, useField } from "vee-validate";
const { value: username } = useField("username");
const { value: email } = useField("email");
const { handleSubmit, errors } = useForm({
validationSchema: {
username: "required|min:2",
email: "required|email",
},
});
const submit = handleSubmit(() => {
console.log(username.value, email.value);
});
</script>
実際に上記例を動かすと、ページ表示時にバリデーションエラーが表示されてしまい期待した動きになりませんでした。

まとめ
Nuxt3とvee-validateの組み合わせを試してみました。Composable APIで簡単にフォームバリデーションを導入することができます。
本サンプルは以下になります。
参考リンク
- https://vee-validate.logaretm.com/v4/
vee-validateの公式サイトです。 - https://github.com/logaretm/vee-validate
vee-validateのGitリポジトリです。 - https://reffect.co.jp/vue/veevaliate4
使い方がとても詳しく説明されており大変参考になります。

コメント