28
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Svelte フォームライブラリ選手権

Last updated at Posted at 2021-05-08

はじめに

Web開発において、フォームは開発者の悩みのタネの一つです。とくに、ユーザーの入力中にリアルタイムでバリデーションを行い、エラーメッセージを表示するようなフォームは自前で実装するのが大変です。全部HTML標準のバリデーションに任せたいところですが、デザインの都合上、そうも行かないことも多いでしょう。

そういったときに必要になるのがフォームライブラリです。執筆時点(2022年2月)で,
Reactでは React Hook Formが覇権を握っているようです。VueではVeeValidateあたりが有名所でしょうか。
さて、近年その勢いを増しているSvelteですが、フォームライブラリが乱立しています。本記事ではSvelteのフォームライブラリを比較していきます。

注意点

  • https://bestofsvelte.com/t/form こちらのサイトに乗っているフォームライブラリを比較します。
  • 各ライブラリは2022年2月時点での最新バージョンを扱います。
  • 筆者のSvelte歴は業務で1年ほど使ったくらいです。
  • 10段階評価をしていますが、ざっくりと以下の点を見ています
    • ボイラープレートの少なさ(Svelteの重要な思想だと思ってます)
    • TypeScriptサポート(昨今のフロントエンドにおいて、TypeScriptの重要さは言うまでもありません)
    • テストケースが書かれているか
  • なお、GitHubのスター数やnpmのダウンロード数はあまり参考にしません。筆者の経験上、Svelte界隈のライブラリはスター数やダウンロード数とクオリティが一致していないことが多いためです。(Svelteがまだ比較的新しいフレームワークで、フォームライブラリが乱立しているのが原因と考えています。)

選手権スタート

エントリーNo. 1 Svelte forms lib

評価:7/10

ReactのフォームライブラリであるFomikに近いAPIであることをうたっています。yupのスキーマと連携できます。TypeScriptの型定義もありますが、input要素すべてにon:keyup={handleChange}と指定する必要があるのはマイナスポイントです。

サンプルコード
  <script>
    import { createForm } from "svelte-forms-lib";

    const {
      form,
      errors,
      state,
      touched,
      isValid,
      isSubmitting,
      isValidating,
      // handlers
      handleBlur,
      handleChange,
      handleSubmit
    } = createForm({
      initialValues: { name: "", email: "" },
      validationSchema: yup.object().shape({
        name: yup.string().required(),
        email: yup.string().email().required()
      }),
      onSubmit: values => { /** ... */ }
    });
  </script>

  <form class:valid={$isValid} on:submit={handleSubmit}>
    <label>name</label>
    <input name="name" on:keyup={handleChange} />
    {#if $errors.name && $touched.name}
      <small>{$errors.name}</small>
    {/if}

    <label>email</label>
    <input name="email" on:keyup={handleChange} />
    {#if $errors.email && $touched.email}
      <small>{$errors.email}</small>
    {/if}

    <button type="submit" disabled={!$isValid}>
      {#if $isSubmitting}loading...{:else}submit{/if}
    </button>
  </form>

(https://svelte-forms-lib-sapper-docs.vercel.app/basic より抜粋)

エントリーNo. 2 Svelte Final Form

評価:6/10

Final Formという、フレームワークに関係なく使えるフォームライブラリをSvelteで使いやすくしたラッパーです。on:blur, on:focusをいちいち指定する手間がかかるのが難点です。TypeScriptの型定義はあります。リポジトリを見るとまだテストケースがないようです。

サンプルコード(一部抜粋)
<Form {onSubmit} {validate} {initialValues} let:form let:state>
  <form on:submit|preventDefault={form.submit}>
    <Field name="firstName" let:input let:meta>
      <label for="firstName">First Name</label>
      <input
        name={input.name}
        on:blur={input.onBlur}
        on:focus={input.onFocus}
        on:input={(e) => input.onChange(e.target.value)}
        type="text"
        placeholder="Last Name"
        value={input.value} />
      {#if meta.touched && meta.error}
        <div>{meta.error}</div>
      {/if}
    </Field>

(https://github.com/jetrockets/svelte-final-form より抜粋)

エントリーNo. 3 Svelte Formly

評価:3/10

なんと、フォーム要素をオブジェクトで宣言する設計になっています。scriptとtemplateを分業したい人には全くもってマッチしないでしょう。「フォーム要素の間に何か違う要素を入れたい」という細かい要望に対処できないのがなかなか厳しそう。TypeScriptの型定義がないのもいただけないです。

サンプルコード(一部抜粋)
<script>
  import { get } from "svelte/store";
  import { valuesForm, Field } from "svelte-formly";

  const fields = [
    {
      type: 'input',
      name: 'firstname',
      value: '',
      attributes: {
        type: 'text',
        label: 'Username',
        id: 'firstname',
        classes: ['form-control'],
        placeholder: 'Tap your first name',
      },
      rules: ['required', 'min:6'],
      messages: {
        required: 'Firstname field is required!',
        min: 'First name field must have more that 6 caracters!',
      },
    },
    {
      type: 'input',
      name: 'email',
      value: '',
      attributes: {
        type: 'email',
        id: 'email',
        placeholder: 'Tap your email',
      },
      rules: ['required', 'email'],
    },
// 略
</script>

<form
  on:submit|preventDefault="{onSubmit}"
  class="custom-form"
  style="--theme-color: {color}"
>
  <Field {fields} />
  <button class="btn btn-primary" type="submit">Submit</button>
</form>

(https://github.com/arabdevelop/svelte-formly#usage より)

エントリーNo. 4 Svelte Use Form

評価:8/10

圧倒的にシンプルな書き心地が特徴です。formという変数がstore($formと使う)とaction(use:formと使う)の両方の振る舞いをするというのが面白いです。初めて見たときは天才かと思いました。TypeScriptの型定義もあります。
ただ、現時点でテストケースがありません。

サンプルコード
<script>
  import { useForm, Hint, validators, minLength } from "svelte-use-form";

  const form = useForm();
</script>

<form use:form>
  <input name="title" use:validators={[minLength(5)]} />
  <Hint for="title" on="minLength" let:value>
    The title requires at least {value} characters.
  </Hint>

  <button disabled={!$form.valid}>Submit</button> <br />
</form>

(https://github.com/noahsalvi/svelte-use-form#minimal-example-repl より)

エントリーNo. 5 Felte

評価:10/10
Svelte Use Formと似た書き心地です。ドキュメントが非常に整備されています。また、動的にフォーム要素が増える場合に対応していたり、yupだけでなくzodやsuperstructといったスキーマに対応していたりと痒いところに手が届く仕様になっています。アクセシビリティについても考慮されていたり、公式が用意しているプラグインによって、エラーの表示形式が変更できたりと至りつくせりです。
TypeScriptで開発されており、型定義も標準装備されています。テストケースもしっかり書かれており、そのカバレッジは99%と非常に高いです。

<script>
  import { createForm } from 'felte';

  const { form } = createForm({
    onSubmit: (values) => {
      // ...
    },
  })
</script>

<form use:form>
  <input type="text" name="email">
  <input type="password" name="password">
  <input type="submit" value="Sign in">
</form>

(https://felte.dev/docs/svelte/getting-started より)

エントリーNo. 6 svelte-forms

評価9/10
フィールド1つ1つに対して、fieldメソッドを使ってストアを作る必要があります。変数が増えてしまうというデメリットはあるものの、ボイラープレートが多すぎるというわけではなく、書き味は悪くないです。他のフォームライブラリとの違いは、bind:valueなどsvelteのreactive機能を使う方針をとっていることです。この方法にはUIライブラリと組み合わせやすいというメリットがあります。UIライブラリが提供するフォームコンポーネントはbind:valueなどbindを使う前提のものも多いためです。
TypeScriptの型定義もあり、テストケースも書かれている点も嬉しいです。

サンプルコード
<script>
  import { form, field } from 'svelte-forms';
  import { required } from 'svelte-forms/validators';

  const name = field('name', '', [required()]);
  const myForm = form(name);
</script>


<section>
  <input type="text" bind:value={$name.value} />

  <button disabled={!$myForm.valid}>Send form</button>
</section>

(https://chainlist.github.io/svelte-forms/ より)

結果発表

Svelte フォームライブラリ選手権 優勝はFelteです。
抽象化が非常にうまくなされている印象で、ベースが使いやすいだけでなく、細かいユースケースにも対応できる作りになっています。またTypeScriptで開発されていること、テストケースもしっかり書かれていることから、保守性も高いです。
Felteを使ってみて気に入った方はGitHubでスターをつけて開発者を応援しましょう。

更新履歴

2022/02/14

再調査しました。
エントリーNo. 6 svelte-formsを追加しました。
エントリNo. 1~4のライブラリに特に大きな変化はなく、相変わらずfelteが優勝でした。
felteは1.0.0が無事リリースされました。
https://github.com/pablo-abc/felte/blob/main/packages/felte/CHANGELOG.md#100

28
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
28
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?