Search code examples
reactjstypescriptreact-hook-formzodshadcnui

map over zod objects to dynamically populate a form select


I have a Zod Object declared:

const FormSchema = z.object({
  field1: z.string(),
  field2: z.string(),
  field3: z.enum([
    "Option 1",
    "Option 2",
    "Option 3"
  ]),
});

to validate my shadcn form:

<form onSubmit={form.handleSubmit(onSubmit)}>
            <div>
              <FormField control={form.control} name="field1" render={({ field }) => (
                <FormItem>
                  <FormLabel>Field 1</FormLabel>
                  <FormControl>
                    <Input {...field} />
                  </FormControl>
                </FormItem>
              )} />

              <FormField control={form.control} name="field2" render={({ field }) => (
                <FormItem>
                  <FormLabel>Field 2</FormLabel>
                  <FormControl>
                    <Input {...field} />
                  </FormControl>
                </FormItem>
              )} />
            
              <FormField control={form.control} name="field3" render={({ field }) => (
                <FormItem>
                  <FormLabel>Field 3</FormLabel>
                  <FormControl>
                    <SelectTrigger>
                      <SelectValue />
                    </SelectTrigger>
                  </FormControl>
                  <SelectContent>
                    <SelectItem value="Option 1">Option 1</SelectItem>
                    <SelectItem value="Option 2">Option 2</SelectItem>
                    <SelectItem value="Option 3">Option 3</SelectItem>
                  </SelectContent>
                </FormItem>
              )} />
            </div>

          </form>

and this is fine, straight forward and works as intended. Select options list however is very long so I'm trying to dynamically generate the <SelectItem>'s in the form, have tried every way to map over the zod object but can't find anything that works. Is it even possible?

I considered creating a separate dataset consisting of the same data and mapping that, which works but I can't figure out how to populate the zod object with it so it seems impractical to effectively have the same data twice.


Solution

  • If I understand your question correctly, you're trying to dynamically create the SelectItem elements from your zod enum. If so, you want the .options property of the field3 property on your FormSchema's shape (you may have to scroll around a bit, sadly the Zod website isn't good at deep linking):

    <SelectContent>
        {FormSchema.shape.field3.options.map((option) => (
            <SelectItem key={option} value={option}>
                {option}
            </SelectItem>
        ))}
    </SelectContent>
    

    ZodEnum objects also have an .enum property which is an object with both the keys and values being the enum members, but .option seems more useful here.