Webform
Using webforms with Next.js and Drupal
There are two ways to handle Webform in Next.js for Drupal.
- Client Side
- Server Side (API Route)
Both implementations use the Webform REST module.
Demo
See https://example-webform.next-drupal.org.
Installation
- Install the Webform REST module:
composer require drupal/webform_rest
- Visit
/admin/config/services/rest
and enable the Webform Submit resource. - Select POST for the Methods, json for Accepted request formats and cookie for Authentication providers
- Save configuration
- Next, visit
/admin/people/permissions
and give anonymous users the Access POST on Webform Submit resource permission.
Client Side
We use the Webform REST module to submit the form values directly to Drupal.
Note: when submitting webform values client-side, the webform_id
and the Drupal base URL is exposed.
export default function ContactPage() { async function handleSubmit(event) { event.preventDefault()
const response = await fetch( `${process.env.NEXT_PUBLIC_DRUPAL_BASE_URL}/webform_rest/submit`, { method: "POST", body: JSON.stringify({ webform_id: "contact", name: event.target.name.value, email: event.target.email.value, }), headers: { "Content-Type": "application/json", }, } )
if (response.ok) { // Show success. }
// Handle error. }
return ( <div> <form onSubmit={handleSubmit}> <p>Implement your form here</p> <div> <label htmlFor="name">Name</label> <input type="text" id="name" name="name" /> </div> <div> <label htmlFor="email">Email</label> <input type="email" id="email" name="email" /> </div> <button type="submit">Submit</button> </form> </div> )}
Server side
We submit the form values to a custom API route first. The API route then submits the form to Drupal using the Webform REST module.
This is useful if we need to hide client IDs and secrets or our Drupal implementation.
- Create a
/pages/api/contact
API route to handle our POST request.
pages/api/contact.ts
import { NextApiRequest, NextApiResponse } from "next"import { drupal } from "lib/drupal"
export default async function handler( request: NextApiRequest, response: NextApiResponse) { try { if (request.method === "POST") { const url = drupal.buildUrl("/webform_rest/submit")
// Submit to Drupal. const result = await drupal.fetch(url.toString(), { method: "POST", body: JSON.stringify({ webform_id: "contact", name: request.body.name, email: request.body.email, }), headers: { "Content-Type": "application/json", }, })
if (!result.ok) { throw new Error() }
response.status(200).end() } } catch (error) { return response.status(400).json(error.message) }}
- Next, update our contact form to submit to this API route.
export default function ContactPage() { async function handleSubmit(event) { event.preventDefault()
const response = await fetch(`/api/contact`, { method: "POST", body: JSON.stringify({ name: event.target.name.value, email: event.target.email.value, }), })
if (response.ok) { // Show success. }
// Handle error. }
return ( <div> <form onSubmit={handleSubmit}> <p>Implement your form here</p> <div> <label htmlFor="name">Name</label> <input type="text" id="name" name="name" /> </div> <div> <label htmlFor="email">Email</label> <input type="email" id="email" name="email" /> </div> <button type="submit">Submit</button> </form> </div> )}
Example
See example-webform for a real-life example of building webform with react-hook-form and handling validation using yup.