Docs
UploadShad integration with ShadCN Form

UploadShad integration with ShadCN Form

Learn how to integrate UploadShad with the ShadCN Form.

In this guide, we will take a look at building forms with the ShadCN Form component which uses react-hook-form and zod for form state management, error handling and type safety.

Installation

If you don't have UploadShad installed. Please visit Install UploadShad guide


Create a form schema

Define the shape of your form using a Zod schema. You can read more about using Zod in the Zod documentation.


import { z } from "zod";
 
const FormSchema = z.object({
  // ...other-values
  images: z
    .array(z.string().url({ message: "Invalid Url" }))
    // .min(1, { message: `There must be at least ${MINFILES} Image.` })
    .max(MAXFILES, {
      message: `$t('propertySchema.images.part1') ${MAXFILES} $t('propertySchema.images.part2')`,
    }),
});
I would recommend storing the MIN/MAX Files values as a Constant value.

Define a form

Use the useForm hook from react-hook-form to create a form.

  • Preload UploadShad files with pre-fetched images, using the default value.

"use client";
 
export function Form() {
  // 1. Define your form.
  const form = useForm<z.infer<typeof FormSchema>>({
    resolver: zodResolver(FormSchema),
    defaultValues: {
      images: [],
    },
  });
 
  // 2. Define a submit handler.
  function onSubmit(data: z.infer<typeof FormSchema>) {
    toast({
      title: "You submitted the following values:",
      description: (
        <pre className="mt-2 w-[340px] rounded-md bg-slate-950 p-4">
          <code className="text-white">{JSON.stringify(data, null, 2)}</code>
        </pre>
      ),
    });
  }
}

Since FormField is using a controlled component, you need to provide a default value for the field.
See the React Hook Form docs to learn more about controlled components.

Build your form

We can now use the Form components to build our form.


"use client";
export function Form() {
  // ...
 
  const { setValue } = form;
 
  return (
    <Form {...form}>
      <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8 flex flex-col items-start">
        <FormField
          control={form.control}
          name="images"
          render={({ field }) => (
            <FormItem className="flex flex-col items-start">
              <FormLabel className="text-left">Images</FormLabel>
              <FormControl className="w-full">
                <UploadShad
                  handleChange={(files) => {
                    setValue("images", files); // store files to Form State
                  }}
                >
                  <FileInput maxfiles={5} maxsize={5 * 1024 * 1024} />
                  <FilesPreview>
                    <FilesPreview.Head>
                      <h3 className="text-xl font-semibold">Uploaded files</h3>
                      <CardDescription>You have no images uploaded yet</CardDescription>
                    </FilesPreview.Head>
                  </FilesPreview>
                </UploadShad>
              </FormControl>
              <FormDescription className="text-left">
                These are your images, check out their preview Urls in the React Developer tools.
              </FormDescription>
              <FormMessage />
            </FormItem>
          )}
        />
        <Button type="submit">Submit</Button>
      </form>
    </Form>
  );
}

Done

That's it. You now have a fully accessible form with, a secure File Input, that is type-safe with client-side validation. 🎊