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 installed on your local machine
- Tailwind CSS will handle the styling of the application. For setup, follow this installation framework guide
- Basic knowledge of JavaScript
- Create an account on Xata and Cloudinary. Sign-up is free
Demo
Check out the deployed project of the customer feedback form.
Repository
In this GitHub repo, 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.
Next, create a table called customers that will hold data collection in a schema. The schema should look something like this:
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.
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:
Upload the Image to Cloudinary
Go to your Cloudinary dashboard and upload an image in the media library.
Copy the link to the image to be used later in the application.
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
Your home page should look something like this:
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
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:
// 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:
// 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:
Returning to index.js
, update the file with the submit
function.
// 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's work together
</h1>
<p>
We'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 thePOST
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
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.
Project Demo
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.