DEV Community

Cover image for Shared form with config files in NextJs
Sebastian Pavel
Sebastian Pavel

Posted on

Shared form with config files in NextJs

Working with forms has always been one of the most challenging aspects of development—not because creating a form is inherently difficult, but because of the sheer amount of code required to make a truly good one.

Recently, I became a father! The play time has shortened, but I found myself with a bit still to tackle this challenge head-on. So, I decided to build a way to assemble forms faster in React (Next.js, of course). Let's dive in and explore the solution.


I will act like you already have everything prepared and you are ready to build a shared form solution for your future projects.


1. Build a zod schema.

It can be whatever you want, i will go with something simple, a user schema.

userSchema.ts

export const userSchema = z.object({
  id: z.string().optional(), // we don't want it to complain about adding an id in the frontend i assume
  name: z.string(),
  email: z.string(),
  image: z.string(),
});
Enter fullscreen mode Exit fullscreen mode

We can add lots of fields here but it will remain on you to add more based on your needs.

2. Add the schema configuration

Have a look at this gist to add the schema configuration that handles some of the magic.

3. Add the configuration specific to your zod schema.

export const productFieldConfigs = () =>
  createFieldConfigs(userSchema, {
    name: {
      type: "text",
      placeholder: "Johnny Doe",
      className: "w-full",
      inputClassName: "text-sm",
      rules: {
        required: {
          value: true,
          message: "This field is required",
        },
      },
    },
    image: {
      optional: true,
      label: "Some label whatever you want",
      className: "w-full",
      inputClassName: "text-sm text-center",
      type: "image",
      onImageLoad(value) {
        console.log(value, "loaded");
      },
      previewClassName: "w-full h-48 border rounded-xl overflow-hidden",
      uploadAreaClassName: "max-w-md mx-auto",
    },
    email: {
      type: "text",
      placeholder: "Email",
      className: "w-full",
      inputClassName: "text-sm",
      rules: {
        required: {
          value: true,
          message: "This field is required",
        },
      },
    },
  });
Enter fullscreen mode Exit fullscreen mode

This seemed pretty simple, let's go further and see how do we render this form on the screen.

4. Add the shared form component.

Here we have the shared form component, it is not perfect, but it did the job for me and i think it will for others too. On the same gist, you can see all the other components I made to cover my needs.

You can combine those fields as you wish, here a small example:

Assume the user has to chose between 3 subscriptions.

export const userSchema = z.object({
  subscription: z.string()
})

export const productFieldConfigs = () =>
  createFieldConfigs(userSchema, {
    subscription: {
      type: "select",
      options: [
        {
          label: "Subscription 1",
          value: "sub-1",
        },
        {
          label: "Subscription 2",
          value: "sub-2",
        },
        {
          label: "Subscription 3",
          value: "sub-3",
        },
      ],
      rules: {
        required: {
          value: true,
          message: "This field is required",
        },
      },
    },
  });
Enter fullscreen mode Exit fullscreen mode

It does not have a documentation yet, but, i am preparing for something, i have limited time, as i am father now, but i still managed to find time to buy a cheap a* domain to push on it a documentation for this and for a badass multi-step form, stay close and you'll see it.

Top comments (0)