How to Build Forms in Next Using Xata and Cloudinary
Tags: javascript, nextjs, react, tutorial
Published: 2022-11-24 11:30:27

Forms are essential in collecting user data on web applications. They allow users to input and submit data directly from a login screen or checkout page. 

Having a customer feedback form attached to a web page is vital for every modern website as this data can be stored in a database once submitted.

In this tutorial, you’ll learn how to use the React framework, Next.js, in combination with Xata, a serverless database with built-in powerful search and analytics and Cloudinary, a cloud-based media library for images and videos to build a customer feedback form.
 

## Prerequisites

The following are required to complete this tutorial:

- For installation of development dependencies and packages, you will need to have [Node](https://nodejs.org/en/?utm_source=hackmamba&utm_campaign=hackmamba-hackathon&utm_medium=hackmamba-blog) installed on your local machine
- Tailwind CSS will handle the styling of the application. For setup, follow this installation [framework guide](https://tailwindcss.com/docs/guides/nextjs/?utm_source=hackmamba&utm_campaign=hackmamba-hackathon&utm_medium=hackmamba-blog)
- Basic knowledge of JavaScript
- Create an account on [Xata](https://xata.io/?utm_source=hackmamba&utm_campaign=hackmamba-hackathon&utm_medium=hackmamba-blog) and [Cloudinary](https://cloudinary.com/signup/?utm_source=hackmamba&utm_campaign=hackmamba-hackathon&utm_medium=hackmamba-blog). Sign-up is free
 
## Demo

Check out the [deployed project](https://next-customer-form-with-xata-cloudinary.vercel.app/?utm_source=hackmamba&utm_campaign=hackmamba-hackathon&utm_medium=hackmamba-blog) of the customer feedback form.


## Repository

In this [GitHub repo](https://github.com/Terieyenike/next-customer-form-with-xata-cloudinary/?utm_source=hackmamba&utm_campaign=hackmamba-hackathon&utm_medium=hackmamba-blog), you can find the complete source code. 


## Creating a Database

After creating your Xata account, go to your workspace dashboard and create a new database. For this project, the database name is called collect_user_data. You are at liberty to name it whatever.


![xata db](https://paper-attachments.dropboxusercontent.com/s_64B6F1D134D2798FF8F73D1614022F57CC6A270CE16C97C1D967B8CFDAF228B7_1668618089672_Screenshot+2022-11-16+at+17.58.32.png)


Next, create a table called customers that will hold data collection in a schema. The schema should look something like this:


![xata schema](https://paper-attachments.dropboxusercontent.com/s_64B6F1D134D2798FF8F73D1614022F57CC6A270CE16C97C1D967B8CFDAF228B7_1668618370606_image.png)


**Note:** The auto-generated IDs are unique for each new record.


## Installation and Setup

To begin, scaffold a new Next app with all the files and folders with this command in your terminal:

```
npx create-next-app <app-name>
```

After installation, navigate to the created directory and run the command below to start the development server on port 3000. 

```
cd <app-nam>
    
npm run dev
```

Open `http://localhost:3000` in your browser to confirm it is running.


## Setup Xata Instance

To initialize the customer feedback form app, install the Xata CLI globally. Run the following command:

```
npm install @xata.io/cli -g
```
Next, let’s run the following command:

```
xata auth login
```

If this is your first time running this command, it will open a new window in the browser to authenticate your account. Afterwards, it will prompt you to Create a new API key or use an existing one; go with the former.


![xata authentication](https://paper-attachments.dropboxusercontent.com/s_64B6F1D134D2798FF8F73D1614022F57CC6A270CE16C97C1D967B8CFDAF228B7_1668624236500_xata+auth+login.png)


Make sure you copy and paste the API key provided by Xata in the `.env` file as a variable.

Now in the project directory, run the command:

```
xata init
```

This command will initialize your project locally with several prompts to set up Xata in your app. The options should look something like this:


![initialize the project](https://paper-attachments.dropboxusercontent.com/s_64B6F1D134D2798FF8F73D1614022F57CC6A270CE16C97C1D967B8CFDAF228B7_1668625240458_image.png)



## Upload the Image to Cloudinary

Go to your Cloudinary dashboard and upload an image in the media library.


![cloudinary](https://paper-attachments.dropboxusercontent.com/s_64B6F1D134D2798FF8F73D1614022F57CC6A270CE16C97C1D967B8CFDAF228B7_1668626213727_Screenshot+2022-11-16+at+20.15.59.png)


Copy the link to the image to be used later in the application.


![cloudinary media library](https://paper-attachments.dropboxusercontent.com/s_64B6F1D134D2798FF8F73D1614022F57CC6A270CE16C97C1D967B8CFDAF228B7_1668635674297_Screenshot+2022-11-16+at+22.52.55.png)



## Creating a Basic Form

In this section, you’ll create an empty form with HTML elements and a submit button using JSX. Copy and paste the following code with the Tailwind CSS classes to handle the styling of the form.

Open the `pages/index.js` file and clear out the existing code with this:


[https://gist.github.com/Terieyenike/57741807dca96a1e56b4da7a9b95048c](https://gist.github.com/Terieyenike/57741807dca96a1e56b4da7a9b95048c/?utm_source=hackmamba&utm_campaign=hackmamba-hackathon&utm_medium=hackmamba-blog)

Your home page should look something like this:


![form page](https://paper-attachments.dropboxusercontent.com/s_64B6F1D134D2798FF8F73D1614022F57CC6A270CE16C97C1D967B8CFDAF228B7_1668638503056_image.png)



## Collecting Form Data

Testing the app in the browser and clicking the submit button, the page reloads. Since this is a single-page application, you’ll pass in an event handler to the `<form>` element, not the `<button>`, to handle the event.

Update the `index.js` file with the useState hook to create states and later update the state to get the value of the input with the `handleChange` function and submit the form with the handleSubmit function.

Copy and paste the updated code:


[https://gist.github.com/Terieyenike/26a66ddeeef3691161ada3dce58d000c](https://gist.github.com/Terieyenike/26a66ddeeef3691161ada3dce58d000c/?utm_source=hackmamba&utm_campaign=hackmamba-hackathon&utm_medium=hackmamba-blog)

The `.preventDefault()` is to stop the page from submitting the form.


## Creating Data 

In the `api` folder within `pages`, create a new file called `add-detail.js`. Copy and paste the following code:

```javascript
// pages/api/add-detail.js
    
import { getXataClient } from '../../src/xata';
    
const handler = async (req, res) => {
 const xata = await getXataClient();
 
const { first_name, last_name, email, company, message, hear_about_us } = req.body;
 await xata.db.customers.create({
  first_name,
  last_name,
  email,
  company,
  message,
  hear_about_us,
});
  res.end();
};
    
export default handler;
```

The import `getXataClient` is present in the app when the project is initialized with the xata command. Next.js is to create asynchronous function called `handler` with the `req` and `res` parameters. The `req.body` will handle the values from the data submitted in the request body from the form with the individual declared data type from the Xata database.

Next, pass in the data as an object in the `create()` function.


## Submitting the Form

Back in the index.js, let’s create another function that will handle the form data submission into Xata to store and persist the data in the database, which on success, shows a message that the data was saved successfully.

But first, let’s create a file, `success.js` and copy the following code:

```javascript
// pages/success.js
    
import Link from 'next/link';
    
    const Success = () => {
      return (
        <section className='bg-gray-900'>
          <div className=' mx-auto max-w-6xl w-4/5'>
            <div className='flex items-center justify-center min-h-screen flex-col'>
              <p className='text-white text-2xl lg:text-4xl capitalize text-center mb-10'>
                message sent successfully. We would get back to you
              </p>
              <Link
                href='/'
                className='text-white bg-green-800 font-bold py-1 px-3'>
                Return home
              </Link>
            </div>
          </div>
        </section>
      );
    };
    
export default Success;
```

This page lets you click on a link that returns you to the home page with the Tailwind CSS classes.

The success page should look like this:


![success page](https://paper-attachments.dropboxusercontent.com/s_64B6F1D134D2798FF8F73D1614022F57CC6A270CE16C97C1D967B8CFDAF228B7_1668643260852_Screenshot+2022-11-13+at+22.13.17.png)


Returning to `index.js`, update the file with the `submit` function.

```javascript
// pages/index.js
    
{/* other imports */}
import { useRouter } from 'next/router'
    
export default function Home() {
      const router = useRouter();
      
      {/* form state */} 
    
      const submit = () => {
        fetch('/api/add-detail', {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
          },
          body: JSON.stringify({
            first_name,
            last_name,
            email,
            company,
            message,
            hear_about_us,
          }),
        }).then(() => router.push('/success'));
      };
    
      const handleSubmitForm = (e) => {
        e.preventDefault();
        submit();
      };
     
      return (
        <div>
          {/* head element */}
          <main className='min-h-screen flex flex-col'>
            <div className='flex flex-col lg:flex lg:flex-row'>
              <div className='mx-auto max-w-6xl w-4/5 lg:p-8'>
                <div className='mt-8 lg:mt-0'>
                  <h1 className='font-bold text-2xl mb-2'>
                    Let&apos;s work together
                  </h1>
                  <p>
                    We&apos;d love to hear from you! Send us a message and we will
                    get back to you.
                  </p>
                </div>
                <form onSubmit={handleSubmitForm}>
                  {/* other JSX */}
                </form>
              </div>
              {/* image container */}
            </div>
          </main>
        </div>
      );
}
```

The following occurs in the snippet code above:

- Import the `useRouter` hook to have access to the router object inside any function component in your app
- Within the submit function, the use of the fetch method to call the `add-detail` file and send network requests to the server using the `POST` method and headers. In addition, the form data submitted is in the form of an object in JSON format
- Finally, using `router.push` navigate to the success page on successful form submission

The final code for the `index.js` file:


[https://gist.github.com/Terieyenike/a1b73d31e428e49e6b068d2b9b789db8](https://gist.github.com/Terieyenike/a1b73d31e428e49e6b068d2b9b789db8/?utm_source=hackmamba&utm_campaign=hackmamba-hackathon&utm_medium=hackmamba-blog)


## Deployment

The customer feedback form app is deployed on Vercel. There are many other options that one can use to deploy a client-side application. If you want to use Vercel, check out its [documentation](https://vercel.com/docs/?utm_source=hackmamba&utm_campaign=hackmamba-hackathon&utm_medium=hackmamba-blog).


## Project Demo


{% embed https://youtu.be/Q9cVGYrJwHQ/?utm_source=hackmamba&utm_campaign=hackmamba-hackathon&utm_medium=hackmamba-blog %}


## Conclusion

This article taught you how to create a customer feedback form with the Next.js framework and store your collected data with Xata.

Try using Xata and Cloudinary.


## Learn More
- [HTTP request method](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST/?utm_source=hackmamba&utm_campaign=hackmamba-hackathon&utm_medium=hackmamba-blog)
- [Xata documentation](https://xata.io/docs/overview/?utm_source=hackmamba&utm_campaign=hackmamba-hackathon&utm_medium=hackmamba-blog)
- [Cloudinary documentation](https://cloudinary.com/documentation/?utm_source=hackmamba&utm_campaign=hackmamba-hackathon&utm_medium=hackmamba-blog)
- [next/router](https://nextjs.org/docs/api-reference/next/router/?utm_source=hackmamba&utm_campaign=hackmamba-hackathon&utm_medium=hackmamba-blog)