Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

create component for form errors using react-hook-form

I’m using react-hook-form, and I’m wondering if it’s possible to create a component that is passing the form errors using react-hook-form.

I have the following component

import { useForm } from "react-hook-form";
import { XIcon } from "@heroicons/react/outline";

export default function ErrorsPopup() {
  const {
    formState: { errors },
  } = useForm({
    criteriaMode: "all",
  });

  return (
    <>
      {Object.keys(errors).length > 0 && (
        <div className="mt-6 text-white bg-red-600 border-4 border-red-700 alert-start">
          <div className="flex justify-between items-center bg-red-700 py-2 px-4">
            <div>
              <p>The following errors have occurred:</p>
            </div>

            <div className="cursor-pointer">
              <XIcon className="h-6 w-6 text-white alert-close" />
            </div>
          </div>

          <div className="py-2 px-4">
            <div className="flex flex-col gap-2">
              {Object.entries(errors).map(([index, error]) => (
                <div className="flex flex-col gap-y-6 sm:gap-x-8" key={index}>
                  <p>&bull; {error.message}</p>
                </div>
              ))}
            </div>
          </div>
        </div>
      )}
    </>
  );
}

and I have added this to the following page

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

import { useState } from "react";
import Head from "next/head";
import Link from "next/link";
import Image from "next/image";
import Background from "../../../public/images/option1.png";
import Router from "next/router";
import { signIn } from "next-auth/client";
import { useForm } from "react-hook-form";
import { SaveIcon } from "@heroicons/react/outline";

import ErrorsPopup from "../../components/ErrorsPopup";

export default function Login() {
  const { register, handleSubmit } = useForm();

  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");

  const onSubmit = async () => {
    await signIn("credentials", {
      redirect: false,
      email: email,
      password: password,
    });

    Router.push("/dashboard");
  };

  return (
    <>
      <Head>
        <title>Ellis Development - Login</title>
      </Head>

      <div className="relative">
        <div className="md:flex">
          {/* Image */}
          <div className="flex items-center justify-center bg-blue-700 h-screen lg:w-96">
            <Image src={Background} width={350} height={350} layout="fixed" />
          </div>

          {/* Contact form */}
          <div className="flex flex-col justify-center py-10 px-6 sm:px-10 w-full">
            <h1 className="text-4xl font-extrabold text-grey-800">Login</h1>

            {/* errors */}
            <ErrorsPopup />

            <form
              onSubmit={handleSubmit(onSubmit)}
              className="mt-6 flex flex-col gap-y-6 sm:gap-x-8"
            >
              {/* email field */}
              <div>
                <label
                  htmlFor="email"
                  className="block text-sm font-medium text-gray-900"
                >
                  Email
                </label>

                <div className="mt-1">
                  <input
                    {...register("email", { required: "E-mail is required" })}
                    type="text"
                    name="email"
                    id="email"
                    className="py-3 px-4 block w-full shadow-sm text-gray-900 focus:ring-blue-700 focus:border-blue-900 border-gray-300 rounded-md"
                    onChange={(event) => setEmail(event.target.value)}
                  />
                </div>
              </div>

              {/* password field */}
              <div>
                <label
                  htmlFor="password"
                  className="block text-sm font-medium text-gray-900"
                >
                  Password
                </label>

                <div className="mt-1">
                  <input
                    {...register("password", {
                      required: "Password is required",
                    })}
                    type="password"
                    name="password"
                    id="password"
                    className="py-3 px-4 block w-full shadow-sm text-gray-900 focus:ring-blue-700 focus:border-blue-900 border-gray-300 rounded-md"
                    onChange={(event) => setPassword(event.target.value)}
                  />
                </div>
              </div>

              <div className="flex items-center justify-between sm:col-span-2">
                <div>
                  <button
                    type="submit"
                    className="mt-2 mr-2 w-full inline-flex items-center justify-center px-6 py-3 border border-transparent rounded-md shadow-sm text-base font-medium text-white bg-blue-700 hover:bg-blue-900 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-700 sm:w-auto"
                  >
                    <SaveIcon className="w-4 h-4 mr-4" />
                    Login
                  </button>
                </div>

                <div>
                  <Link href="/dashboard/auth/register">
                    <a className="underline decoration-blue-500 decoration-4 hover:decoration-2 mr-4">
                      Register
                    </a>
                  </Link>

                  <Link href="/dashboard/auth/forgot">
                    <a className="underline decoration-blue-500 decoration-4 hover:decoration-2">
                      Forgot your password?
                    </a>
                  </Link>
                </div>
              </div>
            </form>
          </div>
        </div>
      </div>
    </>
  );
}

So I’m trying to create a component for all forms where I can simply just show any errors to keep the code DRY, but the component is not showing up.

Sure I’m missing something silly but I’m new to react so any help would be create.

>Solution :

You’ve have to use FormProvider in your Login component and useFormContext in your ErrorPopup

👉🏻 https://react-hook-form.com/api/useformcontext

I’ve added a comment // 👈 where I’ve made changes.

Login.js

import { useState } from "react";
import Head from "next/head";
import Link from "next/link";
import Image from "next/image";
import Background from "../../../public/images/option1.png";
import Router from "next/router";
import { signIn } from "next-auth/client";
import { useForm, FormProvider } from "react-hook-form"; //👈
import { SaveIcon } from "@heroicons/react/outline";

import ErrorsPopup from "../../components/ErrorsPopup";

export default function Login() {
  const methods = useForm(); //👈
const { register, handleSubmit } = methods; //👈

  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");

  const onSubmit = async () => {
    await signIn("credentials", {
      redirect: false,
      email: email,
      password: password,
    });

    Router.push("/dashboard");
  };

  return (
    <>
      <Head>
        <title>Ellis Development - Login</title>
      </Head>

      <div className="relative">
        <div className="md:flex">
          {/* Image */}
          <div className="flex items-center justify-center bg-blue-700 h-screen lg:w-96">
            <Image src={Background} width={350} height={350} layout="fixed" />
          </div>

          {/* Contact form */}
          <div className="flex flex-col justify-center py-10 px-6 sm:px-10 w-full">
            <h1 className="text-4xl font-extrabold text-grey-800">Login</h1>
        
           <FormProvider {...methods}>  //👈
            {/* errors */}
            <ErrorsPopup />

            <form
              onSubmit={handleSubmit(onSubmit)}
              className="mt-6 flex flex-col gap-y-6 sm:gap-x-8"
            >
              {/* email field */}
              <div>
                <label
                  htmlFor="email"
                  className="block text-sm font-medium text-gray-900"
                >
                  Email
                </label>

                <div className="mt-1">
                  <input
                    {...register("email", { required: "E-mail is required" })}
                    type="text"
                    name="email"
                    id="email"
                    className="py-3 px-4 block w-full shadow-sm text-gray-900 focus:ring-blue-700 focus:border-blue-900 border-gray-300 rounded-md"
                    onChange={(event) => setEmail(event.target.value)}
                  />
                </div>
              </div>

              {/* password field */}
              <div>
                <label
                  htmlFor="password"
                  className="block text-sm font-medium text-gray-900"
                >
                  Password
                </label>

                <div className="mt-1">
                  <input
                    {...register("password", {
                      required: "Password is required",
                    })}
                    type="password"
                    name="password"
                    id="password"
                    className="py-3 px-4 block w-full shadow-sm text-gray-900 focus:ring-blue-700 focus:border-blue-900 border-gray-300 rounded-md"
                    onChange={(event) => setPassword(event.target.value)}
                  />
                </div>
              </div>

              <div className="flex items-center justify-between sm:col-span-2">
                <div>
                  <button
                    type="submit"
                    className="mt-2 mr-2 w-full inline-flex items-center justify-center px-6 py-3 border border-transparent rounded-md shadow-sm text-base font-medium text-white bg-blue-700 hover:bg-blue-900 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-700 sm:w-auto"
                  >
                    <SaveIcon className="w-4 h-4 mr-4" />
                    Login
                  </button>
                </div>

                <div>
                  <Link href="/dashboard/auth/register">
                    <a className="underline decoration-blue-500 decoration-4 hover:decoration-2 mr-4">
                      Register
                    </a>
                  </Link>

                  <Link href="/dashboard/auth/forgot">
                    <a className="underline decoration-blue-500 decoration-4 hover:decoration-2">
                      Forgot your password?
                    </a>
                  </Link>
                </div>
              </div>
            </form>
</FormProvider> //👈
          </div>
        </div>
      </div>
    </>
  );
}

ErrorPopup.js

import { useFormContext } from "react-hook-form"; // 👈
import { XIcon } from "@heroicons/react/outline";

export default function ErrorsPopup() {
  const {
    formState: { errors },
  } = useFormContext({ // 👈
    criteriaMode: "all",
  });

  return (
    <>
      {Object.keys(errors).length > 0 && (
        <div className="mt-6 text-white bg-red-600 border-4 border-red-700 alert-start">
          <div className="flex justify-between items-center bg-red-700 py-2 px-4">
            <div>
              <p>The following errors have occurred:</p>
            </div>

            <div className="cursor-pointer">
              <XIcon className="h-6 w-6 text-white alert-close" />
            </div>
          </div>

          <div className="py-2 px-4">
            <div className="flex flex-col gap-2">
              {Object.entries(errors).map(([index, error]) => (
                <div className="flex flex-col gap-y-6 sm:gap-x-8" key={index}>
                  <p>&bull; {error.message}</p>
                </div>
              ))}
            </div>
          </div>
        </div>
      )}
    </>
  );
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading