はじめに
Vueでフォームを作るとき、v-modelとバリデーションロジックとエラーメッセージ表示を、入力の数だけ書き続けた経験はないでしょうか。項目が10個あれば、ラベル・入力・エラー文言・アクセシビリティ属性のセットを10回書くことになり、フォームが増えるほど保守コストも積み上がっていきます。
FormKitは、この「入力ひとつぶんの定型作業」を<FormKit>という単一コンポーネントに閉じ込めることで解決するフォームフレームワークです。バリデーション・エラー表示・アクセシビリティ属性の付与までを1つのコンポーネントが担当し、さらにJSONのスキーマだけでフォーム全体を生成することもできます。
とはいえ、説明より実物を見た方が早いと思います。入力しながらバリデーションが反応する様子を、先に確認してみてください。
FormKitとは
FormKitはVue 3向けに作られたフォーム構築フレームワークで、近年はReact向けの@formkit/reactパッケージも提供されています。単なる入力UIコンポーネント集ではなく、バリデーション・アクセシビリティ・国際化・スキーマ生成までを含む「フォーム開発の土台」として設計されています。GitHub上で4.8k以上のスターを集め、Nike、Bosch、NBCといった企業でも採用実績があります。
主な特徴
- 単一コンポーネントAPI - テキスト、メール、セレクト、チェックボックスなど、どの入力タイプも
<FormKit type="...">という同じインターフェースで扱えます - 組み込みバリデーション -
requiredやemailなど30種類以上のルールをパイプ区切りの文字列で指定するだけで使えます - スキーマによるフォーム生成 - JSONの配列を渡すだけでフォーム全体を動的に生成できます。フォーム構造をデータとして保存・配信できるのが強みです
- アクセシビリティ標準対応 -
aria-describedbyやラベルの関連付けなど、アクセシブルなマークアップが自動で付与されます - 国際化 - 30以上の言語ロケールが標準で用意されています
- プラグイン拡張 - カスタム入力タイプやバリデーションルールをプラグインとして追加できます
インストール
Vueプロジェクトには、以下のコマンドで導入します。
npm install @formkit/vue
pnpmやyarnを使っている場合は、それぞれ次のように読み替えてください。
pnpm add @formkit/vue
yarn add @formkit/vue
FormKitのサンプルを動かす
以下はFormKitの<FormKit type="form">とvalidationプロパティを使った登録フォームです。name・email・passwordの3項目それぞれにrequiredやemail、length:8といったバリデーションルールを指定しており、validation-visibility="live"によって入力のたびにリアルタイムでエラーメッセージが表示されます。フォーム全体が有効になるまで送信ボタンは自動的に無効化されるので、成功・失敗の状態がひと目で分かります。
要点だけを抜き出すと、次のようにバリデーションルールをパイプでつなげて書くだけです。
<FormKit
type="email"
name="email"
label="メールアドレス"
validation="required|email"
validation-visibility="live"
/>
<FormKit
type="password"
name="password"
label="パスワード"
validation="required|length:8"
validation-visibility="live"
help="8文字以上で入力してください"
/>
実際に動かせるのが下のサンプルです。メールアドレスを空にしたり@を消したりすると、その場でエラーメッセージと送信ボタンの無効化を確認できます。逆にすべて正しい値に戻せば、ボタンはすぐに押せる状態に戻ります。
このサンプルからも分かるとおり、FormKitではvalidationプロパティに文字列でルールを書くだけで、入力・エラー表示・送信制御までが自動で連動します。length:8の数値をlength:4に変えれば必要文字数が変わり、validation-visibility="live"を"blur"に変えるとフォーカスが外れるまでエラーが表示されなくなる、という違いも試してみてください。
基本的な使い方
実際のアプリでFormKitを使うには、main.tsでpluginとdefaultConfigをVueアプリに登録します。これによりアプリ全体で<FormKit>コンポーネントが使えるようになります。
// main.ts
import { createApp } from 'vue'
import App from './App.vue'
import { plugin, defaultConfig } from '@formkit/vue'
createApp(App).use(plugin, defaultConfig()).mount('#app')
登録が済めば、コンポーネント側では<FormKit>をそのままテンプレートに書くだけです。
<!-- App.vue -->
<template>
<FormKit
type="text"
name="username"
label="ユーザー名"
validation="required|length:3,20"
/>
</template>
typeをtextからemailやselect、checkboxに変えるだけで、入力タイプに応じた属性やバリデーションルールがそのまま使えるのがFormKitの単一コンポーネントAPIの特徴です。
実践的なユースケース
グループ化した入力でネストしたデータを作る
住所のように複数のフィールドをひとまとまりのオブジェクトとして送信したい場合、FormKitのtype="group"が使えます。<FormKit type="group" name="address">で囲んだ子要素は、送信データの中で自動的にaddressキーの下にネストされます。プロパティのブリッジやイベント配線を自分で書く必要がありません。
<FormKit type="group" name="address">
<FormKit type="text" name="zip" label="郵便番号" />
<FormKit type="text" name="city" label="市区町村" />
</FormKit>
<!-- 送信データ: { address: { zip: '...', city: '...' } } -->
下のサンプルでは、郵便番号をmatchesルールで「999-9999」形式に強制しています。数字以外やハイフン抜きの値を入力するとエラーが出て、送信するとグループ化された結果が下に表示されます。
type="group"は入れ子にもできるので、「配送先」と「請求先」のように同じ形のグループを複数持つフォームも、コンポーネントをネストするだけで表現できます。
動的なリストで項目を増減させる
電話番号やタグのように、数が決まっていない入力を扱いたいケースではtype="list"をdynamic付きで使います。スロットから受け取るitems・node・valueを使い、node.input()で配列を書き換えると、FormKitがフォーム構造を自動的に同期してくれます。
<FormKit type="list" name="phones" dynamic :value="['090-0000-0000']" v-slot="{ items, node, value }">
<FormKit v-for="(item, index) in items" :key="index" :index="index" label="電話番号" />
<FormKit type="button" @click="node.input(value.concat(''))">+ 追加</FormKit>
</FormKit>
下のサンプルでは「+ 電話番号を追加」ボタンで項目を増やし、各行の「削除」ボタンでnode.input(value.filter(...))を呼んで該当項目だけを取り除いています。入力値はmatchesルールで電話番号形式かどうかを検証しています。
なお、ドラッグでの並び替えUIまで欲しい場合はFormKit Pro(有料アドオン)のrepeater入力が用意されていますが、無料のコア機能だけでもtype="list"で増減する仕組みは十分に組み立てられます。
JSONスキーマだけでフォーム構造を組み立てる
FormKitの<FormKitSchema>コンポーネントを使うと、JSONの配列を渡すだけでフォーム全体を描画できます。$formkitキーに入力タイプを指定する形式で、フォーム構造をコンポーネントのコードではなくデータとして表現できるのが特徴です。
const schema = [
{
$formkit: 'text',
name: 'nickname',
label: 'ニックネーム',
validation: 'required',
},
{
$formkit: 'email',
name: 'email',
label: 'メールアドレス',
validation: 'required|email',
},
]
下のサンプルでは、チェックボックスの状態に応じてschemaをcomputedで組み替え、メールアドレス欄そのものを出したり消したりしています。フォームの見た目をJavaScriptのif文ではなく、スキーマの配列操作で切り替えられる様子を確認してください。
チェックを外すとメール入力欄そのものがスキーマから消え、再度チェックすると復活します。フォーム定義をサーバーやDBから取得したJSONに差し替えれば、コードを書き換えずにフォーム構造だけを配信・更新するといった運用も可能になります。
まとめ
FormKitは、<FormKit>という単一コンポーネントにバリデーション・アクセシビリティ・エラー表示を集約することで、入力項目ごとに定型コードを書く手間を減らしてくれるフォームフレームワークです。type="group"によるネストしたデータ構造、type="list"による動的な項目管理、そして<FormKitSchema>によるJSON駆動のフォーム生成まで、フォームが複雑になるほど恩恵の大きい機能が揃っています。
まずは小さなフォームでvalidationプロパティを試すところから始めて、慣れてきたらスキーマ機能で「フォーム構造をデータとして扱う」設計に挑戦してみてください。
