公開日:
更新日:
カテゴリー:

SvelteのフォームライブラリをFelteからTanStack Formに移行した

目次

先日、弊サイトのお問い合わせフォームのライブラリをFelteからTanStack Formへ移行しました。

本記事では、移行の背景や選定理由、移行時のポイントを紹介します。

移行のモチベーション

FelteはSvelte向けのシンプルなフォームライブラリです。型サポートやバリデーションライブラリにも対応しており、フォーム管理をうまく抽象化できる優れたライブラリでした。

弊サイト制作時にSvelteを採用したためフォームライブラリもそれに合わせて選定する必要があり、いくつかの候補の中から機能や当時のメンテナンス状況を考慮してFelteを選択しました。

今回Felteから移行するに至ったのですが、実を言うとFelteの機能自体に全く不満はありませんでした。

ではなぜFelteからの移行を検討したかというと、Felteのメンテナンスがここ1年ほど止まっていたからです。また、それに引きずられる形でZodのバージョンを4系にアップグレードできないという問題もありました。このままFelteを使い続けると将来的にZodだけでなくSvelteのアップグレードもできなくなる可能性があると考え、Felteからの移行を決定しました。

TanStack Formを選んだ理由

移行先に求める条件は以下の通りでした。

  • Svelteに対応している
  • Felteと同等かそれ以上の機能がある
  • 活発に開発・メンテナンスされている

まずSvelte向けのライブラリを探しましたが、機能が十分でなかったりメンテナンスが滞りがちだったりで有力なものは見つけられませんでした。

次に検討したのはReact Hook Formでした。機能や採用実績、メンテナンス状況は文句なしでしたが、Svelteに対応していないのが唯一かつ最大の問題でした。フォームのためだけにReactを導入するのもナンセンスなので、採用は見送りました。

続いて検討したのがTanStack Formでした。TanStack FormはTanStack RouterやTanStack Queryで有名なTanStackによるフォームライブラリです。型安全、ヘッドレス、高パフォーマンスを特徴としています。2025年3月にv1がリリースされた比較的新しいライブラリですが、すでに約6,000のGitHub Starsを集めており注目度の高さがうかがえます。検討の結果、移行先に求める条件を満たしていたことから採用することにしました。

移行時のポイント

FelteからTanStack Formへの移行は難しくありません。TanStack FormのドキュメントのBasic Concepts and Terminologyを読んで基本を理解したら移行できるので、具体的な移行手順の紹介は省略します。

ここでは、実際の移行にあたって押さえておくとよさそうなTanStack Formのポイントを紹介します。

状態はフィールドごとに管理される

Felteは個々のフィールドの情報をフォーム全体でまとめて管理しています。例えば、createForm()の返り値のdataは各フィールドの値を格納するストア、errorsは各フィールドのバリデーションエラーを格納するストアです。

<script>
import { createForm } from "felte";
const { form, data, errors } = createForm();
</script>
<form use:form action="/example" method="post">
<input type="text" name="email" />
<input type="password" name="password" />
<button type="submit">Sign In</button>
</form>

このように各フィールドの情報を中央のストアに集めるFelteに対し、TanStack Formは各フィールド自身に情報を持たせます。フィールドの状態はfield.stateに格納されており、必要に応じて利用できます。TanStack Formは情報を各フィールドが持つ「フィールドファースト」とも言える設計になっています。

<form.Field name="firstName">
{#snippet children(field)}
<input
name={field.name}
value={field.state.value}
onblur={field.handleBlur}
oninput={(e) => field.handleChange(e.target.value)}
/>
{/snippet}
</form.Field>

Felteではグローバルなストアを意識する必要がありましたが、TanStack Formではそれぞれのフィールドで完結しておりグローバルなストアを意識する必要はありません。フィールドファーストな設計によってコードの見通しも良くなりました。

バリデーション結果の初期値はtrue

Felteではバリデーション結果の初期値はfalseですが、TanStack Formではtrueです。バリデーション結果によってUIの表示を切り替えている場合は注意が必要です。

createForm()の引数のvalidators.onMountにバリデーションを設定するとマウント時にバリデーションを実行できます。初期値をfalseにしたい場合はvalidators.onMountにバリデーションを設定しましょう。

<script>
import { createForm } from "@tanstack/svelte-form";
const form = createForm(() => ({
defaultValues: {
fullName: "",
},
validators: {
onMount: ({ value }) => {
// Validate value
},
},
}));
</script>

バリデーションの成否は実行タイミングごとに管理される

FelteとTanStack FormはともにonBluronInputといった任意のタイミングでバリデーションを実行できます。しかし、複数のタイミングにバリデーションを設定した場合の挙動がFelteとTanStack Formで異なるので注意が必要です。

例えばFelteの場合、onBlurのタイミングでバリデーションに失敗したあとonInputのタイミングで成功するとバリデーション結果は成功となります。

一方TanStack Formの場合、onBlurのタイミングでバリデーションに失敗したあとonInputのタイミングで成功してもバリデーション結果は失敗のままです。これはFelteがバリデーション結果を実行タイミング問わず一元管理しているのに対し、TanStack Formは実行タイミングごとに管理しているためです。

ドキュメントのサンプルを見る限り、TanStack Formのこの仕様は各実行タイミングごとに別々のバリデーションを設定することを想定したもののようです。Felteの方はシンプルで、TanStack Formの方はより細かい制御ができる仕様になっています。

まとめ

本記事ではFelteから移行した背景やTanStack Formの選定理由、そして移行時のポイントを紹介しました。

元の機能を維持したまま移行できZodのバージョンもアップグレードできたので、TanStack Formへの移行は正解でした。

Felteからの移行を検討している方の参考になれば幸いです。

記事をシェアする
この記事が参考になったらシェアしていただけると嬉しいです!

私たちgreenciderは「地域のクリエイティブ・パートナー」です。

スタッフそれぞれの専門スキルや興味関心を生かして、地域課題をクリエイティブの力で解決しています。

制作に関するご相談はお問い合わせフォームよりお気軽にご連絡ください。

また、私たちgreenciderとともに、クリエイティブを通して地域課題や地方創生に取り組みたい方も、ぜひお問い合わせフォームよりご連絡ください。

お問い合わせ|greencider(グリーンサイダー)

制作のご相談や見積もり依頼、その他お問い合わせはお問い合わせフォームよりお気軽にご連絡ください。

greencd.jp