DEV Community

hajime
hajime

Posted on

An autocomplete select input using shadcn/ui+react-hook-form+zod.

Overview

simple answer:
https://www.armand-salle.fr/post/autocomplete-select-shadcn-ui

Additional Implementations

Hi,I am currently developing a site called placeof.app and needed to add few things to above implementation like "Changes to the suggest logic""Validating the value with the key’s attribute""i18n". Here is how I did it. I hope it helps.

Changes to the suggest logic

The Combobox of shadcn/ui used in the above implementation is a wrapped version of cmdk’s Combobox. I wanted to change the logic of suggest, so I added my own implementation to the filter as described in cmdk’s documentation. It seems that sorting is also possible.
For example,change https://github.com/armandsalle/my-site/blob/main/src/components/autocomplete.tsx#L88 to the following:

<CommandPrimitive
  filter={(value, search) => {
    if (value.includes(search)) return 1
    return 0
  }}
...
/>
Enter fullscreen mode Exit fullscreen mode

Validating the value with the key’s attribute

Add key

There are two forms, key and value, and this is the implementation when you need to validate the value with the value of the key. When the key to suggest is confirmed by handleKeyDown or other, it calls the parent component’s function with onValueChange, and at that time,

 onValueChange={(key: SuggestKey) => {
    form.setValue("suggestKeyId", key.suggestKeyId)
    form.setValue("suggestValueType", key.valueType)
}}
Enter fullscreen mode Exit fullscreen mode

Use the setValue function of react-hook-form to add the confirmed key to the form. At this time, the react-hook-form is defined like this:

  type Inputs = z.infer<typeof SuggestKeyFormSchema>
  const form = useForm<Inputs>({
    resolver: zodResolver(SuggestKeyFormSchema),
    defaultValues: defaultValues,
  })
Enter fullscreen mode Exit fullscreen mode

Processing when adding a value

Register the value as follows:

    <FormItem>
      <FormControl>
        {specKey?.valueType === SpecValueType.TEXTAREA ? ((
          <Input
            aria-invalid={!!form.formState.errors.value}
            {...form.register("value")}
          />
        )}
      </FormControl>
    </FormItem>
Enter fullscreen mode Exit fullscreen mode

And validate using zod’s superRefine as follows. The valueType added when the key is added is used at this time.

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"],
      })
    }

   ....
  })
Enter fullscreen mode Exit fullscreen mode

i18n

By the way, the key is displayed by referring to the i18n file.

Conversion location for the suggest list https://github.com/armandsalle/my-site/blob/main/src/components/autocomplete.tsx#L36

Conversion location for the confirmed key https://github.com/armandsalle/my-site/blob/main/src/components/autocomplete.tsx#L128

Conclusion

My special thanks to Armand.

Top comments (0)