この記事は、SolidJSアドベントカレンダー 2024 9日目の記事です。
フォームライブラリ
現状私が確認してる限りではsolidjsで使えるフォームライブラリは以下の2つです。
- modular-forms
- @solid-mediakit/form
ドキュメントが充実してたのでmodular-formsを触ってみました。
概要
- デフォルトではuncontrolled、controlledへの移行も簡単
- validationではzodだけでなくvalibotも対応
- ArrayやObjectの形式の構成も可能
- Actionsは残念ながら非対応
- FAQの「Does it work with SolidStart?」参照
使い方
導入
pnpm install modular-forms/solid
フォーム実装
getValueを "@modular-forms/solid"
からimportしているように、react-hook-form等とは違い細かい関数はimportする必要があります。(バンドルサイズを減らすため)
import { createForm, getValues, insert, valiForm } from "@modular-forms/solid";
import * as v from "valibot";
const LoginSchema = v.object({
username: v.string(),
password: v.string(),
});
export default function Page() {
const [form, { Form, Field }] = createForm<SpecialForm>({
validate: valiForm(LoginSchema),
});
createEffect(() => {
console.log(getValues(form));
});
return (
<div>
<h1>Modular Forms</h1>
<Form onSubmit={(v)=>{console.log(v)}}>
<Field name="username" >
{(field, props) => <input {...props} />}
</Field>
<Field name="password" >
{(field, props) => <input type="password" {...props} />}
</Field>
<button type="submit">Submit</button>
</Form>
</div>
);
}
その他
Controlled
デフォルトではuncontrolledなのでcontrolledにする場合はfield.valueをvalueに渡す
<Field name="username" >
{(field, props) => <input value={field.value} {...props} />}
</Field>
Error表示
<Field name="username" >
{(field, props) => {
return <div>
<input {...props} />
<div>{field.error}</div>
</div>;
}}
</Field>
FieldArray
// ↓こんな感じのフォームのとき
const LoginSchema = v.object({
list: v.array(v.object({ value: v.string() }))
});
// ↓フォームはこうなる
<FieldArray name="list">
{(fieldArray) => (
<>
<For each={fieldArray.items}>
{(item, index) => (
<div>
<Field name={`list.${index()}.value`}>
{(field, props) => <input {...props} type="text" />}
</Field>
</div>
)}
</For>
<button
type="button"
onClick={() => insert(form, "list", { value:{ value: "" } })}
>
Add
</button>
</>
)}
</FieldArray>
Custom Input
必要なプロパティをcontextで引き回してあげるとシンプルに実装できる
import {
Field as BaseField,
type FormStore,
createForm,
valiForm,
} from "@modular-forms/solid";
import { Show, createContext, useContext } from "solid-js";
import * as v from "valibot";
const LoginSchema = v.object({
username: v.string(),
});
type LoginForm = v.InferInput<typeof LoginSchema>;
const formContext = createContext<FormStore<LoginForm>>();
const UserName = () => {
const context = useContext(formContext);
return (
<Show when={context}>
{(form) => {
return (
<BaseField name="username" of={form()}>
{(field, props) => {
return (
<>
<input {...props} />
{field.error}
</>
);
}}
</BaseField>
);
}}
</Show>
);
};
export default function Page() {
const [form, { Form, Field, FieldArray }] = createForm<LoginForm>({
validate: valiForm(LoginSchema),
});
return (
<div>
<h1>Modular Forms</h1>
<formContext.Provider value={form}>
<Form
onSubmit={(v) => {
console.log(v);
}}
>
<UserName />
<button type="submit">Submit</button>
</Form>
</formContext.Provider>
</div>
);
}