基本的には、shadcn/uiを使ったサジェストフォームの簡単なサンプルとして、下記のデモサイトがありますが、こちらをコピペすればよいです。
https://www.armand-salle.fr/post/autocomplete-select-shadcn-ui
このサイトを運営しているarmandさんのgithubのソースコード
今個人開発しているプレイスオブというサイトの物件のスペックを入力する画面でこの実装をほぼコピペさせてもらっているのですが、何点か追加実装が必要だったのでメモしておきます。何かしらの参考になれば幸いです。
完成図
suggestのロジックの変更
上記実装で使われている、shadcn/uiのCombobox はcmdkのComboboxをwrapしたものです。suggestのロジックを変更したかった(+日本語だと上手くいかない気がした)ので、cmdkのドキュメントに記載されている通りfilterに独自実装を追加してます。sortとかも出来るようです。
<Command
filter={(value, search) => {
if (value.includes(search)) return 1
return 0
}}
/>
keyの値でvalueのバリデーションをする
keyの追加時の処理
keyとvalueの2つのフォームがあり、keyの値でvalueの値をvalidationする必要するときの実装です。suggestをするkeyがhandleKeyDownなどで確定するときに、onValueChangeで親のComponentの関数を呼び出していますが、そのときに、
onValueChange={(key: SuggestKey) => {
form.setValue("suggestKeyId", key.suggestKeyId)
form.setValue("suggestValueType", key.valueType)
}}
のようにreact-hook-formのsetValue関数を使い、確定したkeyをformに追加します。なお、このときに下記のようにreact-hook-formのformが定義されています。
type Inputs = z.infer<typeof SuggestKeyFormSchema>
const form = useForm<Inputs>({
resolver: zodResolver(SuggestKeyFormSchema),
defaultValues: defaultValues,
})
valueの追加時の処理
下記のようにvalueをregisterします。
<FormItem>
<FormControl>
{specKey?.valueType === SpecValueType.TEXTAREA ? ((
<Input
aria-invalid={!!form.formState.errors.value}
{...form.register("value")}
/>
)}
</FormControl>
</FormItem>
そして、下記のようにzodのsuperRefineを使ってvalidateします。このときkeyを追加したときのvalueTypeが使われます。
export const SuggestKeyFormSchema = z
.object({
suggestKeyId: z.string().min(1),
valueType: SuggestValueTypeSchema,
value: z.string().min(1),
})
.superRefine((values, ctx) => {
if (
values.valueType === SuggestValueTypeSchema.STRING &&
values.value.length >= 20
) {
ctx.addIssue({
message: "need to be less than 20 words",
code: z.ZodIssueCode.custom,
path: ["value"],
})
}
....
})
i18n
ちなみに、keyはi18nのファイルを参照するようにして表示しています。
suggest一覧の変換箇所
https://github.com/armandsalle/my-site/blob/main/src/components/autocomplete.tsx#L36
確定したkeyの変換箇所
https://github.com/armandsalle/my-site/blob/main/src/components/autocomplete.tsx#L128
サーバーからデータを取得
サーバーからデータを取得する場合は、こちらのやり方が参考になるかと思います
https://zenn.dev/mktu/articles/2f9166374d09a0
まとめ
もっと完成度を高めて物件のありとあらゆるスペックが入力できるフォームにしていきたいので、何かあれば教えて下さい。