Chakra UI and React Hook Form – How to Build Beautiful Forms

Forms are a crucial part of many web applications, but building them can often be a tedious process. You have to set up the proper markup, manage form state, implement validation, style the form components, and ensure accessibility – all while providing a smooth user experience.

Fortunately, by combining two powerful libraries – Chakra UI and React Hook Form – you can greatly simplify the process of building professional, polished forms in your React apps. In this post, we‘ll walk through how to leverage these tools effectively to create attractive, user-friendly forms with minimal hassle.

Why Use Chakra UI for Forms?

Chakra UI is a component library for React that allows you to quickly build accessible, customizable user interfaces. It provides a set of prebuilt, composable components that handle many common UI patterns out of the box, including forms and form elements.

Some key advantages of using Chakra UI for form building include:

  • Accessible components that follow WAI-ARIA standards
  • Highly customizable component styles via style props
  • Intuitive, mobile-first responsive design system
  • Robust theming and design token features
  • Well-documented APIs with strong TypeScript support

By starting with Chakra UI form components as a base, we can create professional-looking forms without having to write a lot of custom CSS or reinvent the wheel when it comes to fundamental UI concerns.

What is React Hook Form?

React Hook Form is a lightweight library that simplifies the process of managing form state and validation in React function components. It leverages React hooks to provide a declarative, intuitive API for handling common form concerns like input registration, submission, validation, and error handling.

Some notable features of React Hook Form include:

  • Simple, uncontrolled inputs by default (no onChange handlers needed)
  • Built-in validation rules and error messaging
  • Seamless integration with UI libraries like Chakra UI
  • Improved performance by minimizing re-renders
  • Extensive customization options

React Hook Form eliminates a lot of the repetitive boilerplate typically involved with building forms in React, allowing us to focus on the core functionality of our form.

Building a Basic Form

Let‘s walk through the process of building a simple form using Chakra UI and React Hook Form together. We‘ll create a basic login form with fields for username and password.

First, make sure you have Chakra UI and React Hook Form installed:

npm i @chakra-ui/react react-hook-form

Then, import the necessary components and hooks in your form component file:

import { Button, FormControl, FormLabel, Input, VStack } from "@chakra-ui/react";
import { useForm } from "react-hook-form";

Now, let‘s set up the basic structure of our form:

function LoginForm() {
  const { register, handleSubmit } = useForm();

  const onSubmit = (data) => {
    console.log(data);
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <VStack spacing={4}>
        <FormControl id="username">
          <FormLabel>Username</FormLabel>
          <Input type="text" {...register(‘username‘)} />
        </FormControl>

        <FormControl id="password">
          <FormLabel>Password</FormLabel>
          <Input type="password" {...register(‘password‘)} />
        </FormControl>

        <Button type="submit" colorScheme="blue">
          Log In
        </Button>
      </VStack>
    </form>
  );
}

Here‘s what‘s happening:

  1. We use the useForm hook from React Hook Form to handle our form state and submission. This gives us a register function to register our form inputs and a handleSubmit function to handle the form submission.

  2. We define our form UI using Chakra UI components like FormControl, FormLabel, Input, and Button. The VStack component is used to vertically stack the form elements with consistent spacing.

  3. To register the form inputs with React Hook Form, we spread the register function as props on the Input components, specifying the name of each input.

  4. We pass our onSubmit handler to handleSubmit on the form. This function will receive the form data as an argument when the form is submitted.

  5. For now, we simply log out the form data to the console on submit.

With just this basic setup, we already have a working form that captures user input and handles submission. But we can still enhance it further with validation and better styling.

Adding Form Validation

Proper form validation is essential for maintaining data integrity and guiding users to enter data in the expected format. React Hook Form makes it easy to add validation to our forms.

To define validation rules, we pass a configuration object to the register function with our desired rules. Let‘s add some validation to our login form:

<FormControl id="username">
  <FormLabel>Username</FormLabel>
  <Input
    type="text"
    {...register(‘username‘, {
      required: ‘Username is required‘,
      minLength: { value: 4, message: ‘Username must be at least 4 characters‘ },
    })}
  />
</FormControl>

<FormControl id="password">
  <FormLabel>Password</FormLabel> 
  <Input
    type="password"
    {...register(‘password‘, {
      required: ‘Password is required‘,
      minLength: { value: 8, message: ‘Password must be at least 8 characters‘ },
    })}
  />
</FormControl>

We‘ve added validation rules for both the username and password fields:

  • The required rule specifies that the field must have a value. We can provide a custom error message string.
  • The minLength rule specifies a minimum character length for the field value. We provide an object with the value and a custom message.

React Hook Form will automatically track the validation state of our inputs and prevent form submission if there are any validation errors. However, we still need to display those error messages to the user.

We can access the validation errors via the formState.errors object returned by useForm. Let‘s display our error messages using Chakra UI‘s FormErrorMessage component:

function LoginForm() {
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm();

  // ...

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <VStack spacing={4}>
        <FormControl id="username" isInvalid={errors.username}>
          <FormLabel>Username</FormLabel>
          <Input
            type="text"
            {...register(‘username‘, {
              required: ‘Username is required‘,
              minLength: { value: 4, message: ‘Username must be at least 4 characters‘ },
            })}
          />
          <FormErrorMessage>{errors.username?.message}</FormErrorMessage>
        </FormControl>

        <FormControl id="password" isInvalid={errors.password}>
          <FormLabel>Password</FormLabel>
          <Input
            type="password"
            {...register(‘password‘, {
              required: ‘Password is required‘,
              minLength: { value: 8, message: ‘Password must be at least 8 characters‘ },
            })}
          />
          <FormErrorMessage>{errors.password?.message}</FormErrorMessage>
        </FormControl>

        <Button type="submit" colorScheme="blue">
          Log In  
        </Button>
      </VStack>
    </form>
  );
}

We‘ve made a few key changes:

  1. We destructure errors from formState returned by useForm. This will contain any validation error messages.

  2. We pass isInvalid={errors.username} and isInvalid={errors.password} to the FormControls to conditionally apply error styling.

  3. We display the error message for each field using FormErrorMessage, accessing it via errors.username?.message and errors.password?.message. The ?. optional chaining operator ensures we don‘t get an error if the errors object doesn‘t contain an entry for that field.

Now our form displays inline validation errors whenever a field has an invalid value, providing clear feedback to the user.

Styling with Chakra UI

While our form is functional, it‘s a bit plain looking. We can easily spruce it up with some additional styling using Chakra UI‘s style props.

Chakra UI components are highly customizable directly through props, allowing us to change styles without writing custom CSS classes. We can leverage this to improve the appearance of our form:

<VStack spacing={8} width="100%" maxWidth="md" margin="auto" mt={8}>
  <Heading as="h1" size="xl" textAlign="center">
    Log In
  </Heading>

  <Box  
    p={8}
    borderWidth={1}
    borderRadius={8}
    boxShadow="lg"
    bg="white"
    width="100%"
  >
    <form onSubmit={handleSubmit(onSubmit)}>
      <VStack spacing={6}>
        <FormControl id="username" isInvalid={errors.username}>
          <FormLabel>Username</FormLabel>
          <Input
            type="text"
            {...register(‘username‘, {
              required: ‘Username is required‘,
              minLength: { value: 4, message: ‘Username must be at least 4 characters‘ },
            })}
          />
          <FormErrorMessage>{errors.username?.message}</FormErrorMessage>
        </FormControl>

        <FormControl id="password" isInvalid={errors.password}>
          <FormLabel>Password</FormLabel>
          <Input
            type="password"
            {...register(‘password‘, {
              required: ‘Password is required‘,
              minLength: { value: 8, message: ‘Password must be at least 8 characters‘ },
            })}
          />
          <FormErrorMessage>{errors.password?.message}</FormErrorMessage>
        </FormControl>

        <Button type="submit" colorScheme="blue" size="lg" width="full">
          Log In
        </Button>
      </VStack>
    </form>
  </Box>
</VStack>

Let‘s break down the changes:

  1. We wrap our whole form in a VStack to center it on the page and limit its max width. The spacing, width, maxWidth, margin, and mt props control the layout and spacing.

  2. We add a heading to the form using the Heading component.

  3. We wrap the form in a Box component to give it a border, border radius, box shadow, and background color, making it visually distinct from the page background. The p prop adds padding around the form contents.

  4. We tweak the spacing of the VStack wrapping the form fields to adjust the vertical gap between fields.

  5. We make the submit button larger (size="lg") and set its width to "full" to fill the width of the form.

With just a handful of Chakra UI components and style props, our form now has a much more polished, professional look.

Accessibility Considerations

When building forms, it‘s important to ensure they are accessible to all users, including those using assistive technologies like screen readers. Chakra UI and React Hook Form both help us build forms with good accessibility by default, but there are a few key things to keep in mind:

  • Use semantic HTML elements like <form>, <label>, <input>, and <button> to provide meaning and structure.
  • Provide a unique, descriptive id for each form field that matches its associated <label>. Chakra UI‘s FormControl component handles this for us.
  • Ensure all form fields have a visible label. Again, Chakra UI‘s FormLabel takes care of this.
  • Provide clear error messages for validation errors, associated with the relevant form field. We achieve this with Chakra UI‘s FormErrorMessage.
  • Ensure form elements have sufficient color contrast. Chakra UI‘s default theme is designed with accessibility in mind.
  • Make sure the form can be navigated and submitted using only a keyboard. React Hook Form‘s uncontrolled inputs allow this by default.

By using Chakra UI and React Hook Form and following these guidelines, we can create forms that are usable and accessible for all users.

Conclusion

Building forms in React doesn‘t have to be a chore. By leveraging the power of Chakra UI and React Hook Form together, we can create professional, accessible, and user-friendly forms with minimal boilerplate and effort.

Chakra UI provides a solid foundation of customizable, accessible form components that allow us to quickly scaffold out our form UI. React Hook Form simplifies the process of managing form state, validation, and submission, eliminating common pain points.

By combining these two libraries and following some form building best practices, we can create polished forms that provide a great user experience while also being easy to develop and maintain.

So next time you need to build a form in your React app, consider giving Chakra UI and React Hook Form a try. Happy form building!

Similar Posts