How can I programmatically create forms and capture submissions using Hygraph, Next.js, and GraphQL?
You can dynamically build forms in Next.js by modeling your content in Hygraph, using GraphQL queries to fetch form structures, and leveraging the Mutations API to capture submissions. The process involves defining content models for pages, forms, and various field types (input, textarea, select, checkbox), querying these models via GraphQL, and handling submissions with a dedicated Submission model in Hygraph. The tutorial on the original page provides step-by-step guidance, including code samples and schema design. Note: This approach requires familiarity with GraphQL, Next.js, and Hygraph's schema editor. Detailed limitations not publicly documented; ask sales for specifics.
What field types and models are supported for dynamic forms in Hygraph?
Hygraph supports modeling forms with field types including Input (with types TEXT, EMAIL, TEL), Textarea, Select (with options), and Checkbox. Each field type is represented as a separate model (FormInput, FormTextarea, FormSelect, FormCheckbox, FormOption) and can be associated with a Form model. This allows for flexible, schema-driven form generation. Note: Adding custom field types beyond those listed requires additional schema configuration. Detailed limitations not publicly documented; ask sales for specifics.
Does Hygraph support GraphQL Union Types for form fields?
Yes, Hygraph supports GraphQL Union Types, enabling you to define models for each form field type and associate them with a Form model as a "has many" field. This allows dynamic querying and rendering of heterogeneous form fields in your application. Note: Union Types require careful query construction using the ... on TypeName syntax in GraphQL. Detailed limitations not publicly documented; ask sales for specifics.
What integrations are available with Hygraph for asset management, deployment, and localization?
Hygraph offers integrations with Digital Asset Management (DAM) systems such as Aprimo, AWS S3, Bynder, Cloudinary, Imgix, Mux, and Scaleflex Filerobot. For hosting and deployment, integrations include Netlify and Vercel. Product Information Management (PIM) integration is available with Akeneo. Other integrations include Adminix, Plasmic, BigCommerce (commerce), and EasyTranslate (localization). For a complete list, visit the Hygraph Marketplace. Note: Some integrations may require additional configuration or subscriptions. Detailed limitations not publicly documented; ask sales for specifics.
What APIs does Hygraph provide for content and asset management?
Hygraph provides several APIs: the GraphQL Content API for querying and manipulating content, the Management API for handling project structure (accessible via the Management SDK), the Asset Upload API for uploading files, and the MCP Server API for secure communication between AI assistants and Hygraph. For details, see the API Reference documentation. Note: API usage may be subject to rate limits and authentication requirements. Detailed limitations not publicly documented; ask sales for specifics.
Technical Implementation & Developer Experience
How do I configure public API access in Hygraph for querying forms and pages?
To enable public API queries in Hygraph, go to your project Settings, open the API Access page, and enable 'Content from stage Published' under Public API permissions. Save your changes. This allows public queries for published content, which is necessary for building dynamic pages and forms. Note: Do not enable mutations for the public API to avoid unauthorized data changes. Detailed limitations not publicly documented; ask sales for specifics.
What is the recommended way to handle form submissions securely with Hygraph?
Form submissions should be handled via a secure API route in your application (e.g., Next.js API route) that forwards data to Hygraph using a Permanent Auth Token with mutation permissions. Do not expose mutation tokens in client-side code. The recommended approach is to create a Submission model in Hygraph, store form data as JSON, and connect submissions to the relevant Form. For more, see the tutorial's section on submitting forms with GraphQL Mutations. Note: Exposing mutation tokens publicly can compromise data security. Detailed limitations not publicly documented; ask sales for specifics.
How long does it take to implement Hygraph for a new project?
Implementation timelines vary by project complexity. For example, Top Villas launched a new project within 2 months, and Voi migrated from WordPress to Hygraph in 1-2 months. Starter projects, structured onboarding, and extensive documentation help accelerate adoption. Note: Complex integrations or custom workflows may require additional time. Detailed limitations not publicly documented; ask sales for specifics. (Source: Top Villas Case Study)
What technical documentation is available for developers using Hygraph?
Hygraph provides comprehensive technical documentation, including API references, schema guides, integration tutorials (e.g., Mux, Akeneo, Auth0), and AI feature documentation. Getting Started guides and classic docs are available for both new and legacy users. For details, visit the Hygraph Documentation. Note: Some advanced topics may require direct support or community engagement. Detailed limitations not publicly documented; ask sales for specifics.
Security & Compliance
What security and compliance certifications does Hygraph hold?
Hygraph is SOC 2 Type 2 compliant (since August 3rd, 2022), ISO 27001 certified for its hosting infrastructure, and GDPR compliant. These certifications ensure adherence to international standards for information security and data protection. For more, see the Secure Features page. Note: Certification scope may not cover all integrations or custom workflows. Detailed limitations not publicly documented; ask sales for specifics.
What security features are available in Hygraph for managing content and API access?
Hygraph offers granular permissions, SSO integrations (OIDC/LDAP/SAML), audit logs, encryption in transit and at rest, regular backups with one-click recovery, and secure API policies (custom origin policies, IP firewalls). All endpoints use SSL certificates. For more, see the Secure Features page. Note: Some features may require enterprise plans or additional configuration. Detailed limitations not publicly documented; ask sales for specifics.
Use Cases & Benefits
Who can benefit from using Hygraph for dynamic forms and content management?
Hygraph is suitable for developers, content creators, product managers, and marketing professionals in enterprises and high-growth companies. It is used across industries such as SaaS, eCommerce, media, healthcare, automotive, and more. Its GraphQL-native architecture and content federation make it ideal for teams needing flexible, scalable content management. Note: Teams with highly specialized or legacy requirements may need to evaluate fit. Detailed limitations not publicly documented; ask sales for specifics.
What business impact have customers reported after implementing Hygraph?
Customers have reported faster time-to-market (e.g., Komax achieved 3X faster time-to-market), improved customer engagement (Samsung saw a 15% increase), and cost reduction (AutoWeb achieved a 20% increase in website monetization). These outcomes are supported by case studies available on the Hygraph case studies page. Note: Results may vary based on implementation scope and industry. Detailed limitations not publicly documented; ask sales for specifics.
What feedback have customers given about the ease of use of Hygraph?
Customers have praised Hygraph for its intuitive interface, quick adaptability, and accessibility for non-technical users. For example, Sigurður G. (CTO) noted the UI is intuitive for normal users, and Anastasija S. (Product Content Coordinator) highlighted instant front-end updates. Charissa K. (Senior CMS Specialist) described it as fast to comprehend and localizable. Note: Some advanced features may require technical expertise. Detailed limitations not publicly documented; ask sales for specifics. (Source: Hailey Feed - PMF Research.xlsx)
Performance & Scalability
How does Hygraph perform for high-traffic or large-scale content delivery?
Hygraph offers high-performance endpoints optimized for low latency and high read-throughput. A read-only cache endpoint provides 3-5x latency improvement. The platform actively measures GraphQL API performance and provides optimization advice (see the GraphQL Report 2024). Note: Actual performance may vary based on integration and usage patterns. Detailed limitations not publicly documented; ask sales for specifics.
Support & Documentation
What support and onboarding resources are available for new Hygraph users?
Hygraph provides structured onboarding (introduction calls, account provisioning, technical kickoffs), extensive documentation, starter projects, community support via Slack, and training resources such as webinars and how-to videos. For details, visit the Getting Started guide. Note: Some resources may be available only to paying customers or enterprise plans. Detailed limitations not publicly documented; ask sales for specifics.
Before we dive into creating our schema, let's first think about what we're going to need to enable our marketing team to spin up landing page forms from just using the CMS.
It all starts with a Page. Pages must have a slug field so we can easily look up content from the params of any request.
Next, for simplicity, each page will have an associated Form model. For the sake of this tutorial, we'll pick 4 form field types;
Input
Textarea
Select
Checkbox
Form Fields
If we think of a traditional form, let's try and replace all of the data points we need to recreate a simple contact form like the following:
<labelfor="favFramework">What's your favorite framework?</label>
<selectid="favFramework">
<optionvalue="react">React</option>
<optionvalue="vue">Vue</option>
<optionvalue="angular">Angular</option>
<optionvalue="svelte">Svelte</option>
</select>
</div>
<div>
<labelfor="message">Message</label>
<textareaid="message"placeholder="Leave a message"/>
</div>
<div>
<labelfor="terms">
<inputid="terms"type="checkbox"/>
I agree to the terms and privacy policy.
</label>
</div>
<div>
<buttontype="submit">Submit</button>
</div>
</form>
In the above form, we have some <input />'s that are required, some which are of type email, tel and text, while the <select /> has no placeholder or is required.
Hygraph has support for GraphQL Union Types. This means we can define models for each of our form field types, and associate them to our Form model as one "has many" field.
Our schema will end up looking a little something like the following...
Models
Page
Title, String, Single line text, Required, and used as a Title
Slug, String, Slug, Required - Specify {title} as the template
Form, Reference to Form
You can use the Slug field type that automatically generates a slug based on your title. You'll need to set the template. to{title} to make this work. You can always override slugs.
Form
Page, Reference, Accepts multiple Page values
Fields, Reference, Accepts multiple FormInput, FormTextarea, FormSelect and FormCheckbox values
FormInput
Name, String, Single line text, and used as a Title
Type, Enum, FormInputType dropdown
Label, String, Single line text
Placeholder, Single line text
Required, Boolean
Form, Reference to Form
FormTextarea
Name, String, Single line text, and used as a Title
Label, String Single line text
Placeholder, String, Single line text
Required, Boolean
Form, Reference to Form
FormSelect
Name, String, Single line text, and used as a Title
Now we have an idea of how our content model looks like. Let's create the models and their associations with eachother inside Hygraph.
You'll need an account to continue. Sign up or head to the Dashboard.
Once logged in, head to the Schema editor by selecting Schema from the side.
Click + Add in the sidebar above default system Asset model.
Go ahead and create the 7 models above. Don't worry about creating relations just yet, you can do them all at once after creating the other fields.
#3. Create an example Page and Form with Fields as a content editor
So that we are able to query, and build our forms, we're going to need some content inside our models.
Inside the Dashboard, head to the Content editor by selecting Content from the side.
Select the Page model and click + Create New from the top right.
Give your page a title and slug. I'll call use Contact Us, and contact, respectively.
Now underneath Form, click Create and add a new form.
Inside the inline Form content editor, click on Create and add a new document.
From the dropdown, select FormInput.
Inside the inline FormInput content editor, enter a name, type , label and placeholder for your form field. I'll add the values Name, TEXT, Your name, Name and set required to true.
Now click Save and publish.
Repeat steps 5-8 to add additional fields.
🖐 To follow along with the rest of this tutorial, I will be using the following values for my fields...
3 x FormInput's
Name
Name: name
Type: TEXT
Label: Name
Placeholder: Your name
Required: true
Email
Name: email
Type: EMAIL
Label: Email
Placeholder: Your email
Required: true
Tel
Name: tel
Type: TEL
Label: Tel
Placeholder: Your contact no.
Required: false
1 x FormTextarea
Message
Name: message
Label: Message
Placeholder: Leave a message
Required: true
1 x FormCheckbox
Terms
Name: terms
Label: I agree to the terms and privacy policy.
Required: true
1 x FormSelect
The FormSelect is a little special because it also references another model FormSelect.
First, create your FormSelect document as usual, entering the following.
Favourite Framework
Name: favFramework
Label: What's your favorite frontend framework?
Required: false
Next below Options, click on Create and add a new formOption.
Now for each of our choices below, repeat the steps to "Create and add a new formOption", and provide the value/option for each:
react/React
vue/Vue
angular/Angular
svelte/Svelte
Finally, click Save and publish on this and close each of the inline editors, making sure to publish any unsaved changes along the way.
Now we have created our fields, we can now reorder them using the content editor. This may be useful if you decide to add or remove some fields later, you can order the fields exactly the way you want them to appear.
✨ Simply drag each of the Field rows into the order you want. ✨
Hygraph has a flexible permissions system, which includes enabling certain user groups to do actions, and most importantly restrict who can query what data.
For the purposes of querying data to build our pages and forms, we'll enable public API queries.
To do this, go to your project Settings.
Open the API Access page
Enable Content from stage Published under Public API permissions
Save ✨
That's it! You can test this works using the API Playground and selecting Environment: master Public from the dropdown in the section above your query/result.
🖐 Make sure to copy your API Endpoint to the clipboard. We'll need it in step 8.
This comes in two significant parts. First we create the routes (or "paths") and then query for the data for each page with those path params.
8.1 Create programmatic page routes
First up is to add some code to our Next.js application that will automatically generate pages for us. For this we will be exporting the getStaticPaths function from a new file called [slug].js in our pages directory.
touch pages/[slug].js
Having a filename with square brackets may look like a typo, but rest assured this is a Next.js convention.
Inside pages/[slug].js add the following code to get going:
exportdefaultfunctionIndex(props){
return(
<pre>{JSON.stringify(props,null,2)}</pre>
)
}
If you're familiar with React already, you'll notice we are destructuring props from the Index function. We'll be updating this later to destructure our individual page data, but for now, we'll show the props data on each of our pages.
Inside pages/[slug].js, let's import graphql-request and initialize a new GraphQLClient client.
🖐 You'll need your API Endpoint from Step 6 to continue.
Finally inside getStaticPaths we are returning paths for our pages, and a fallback. These build the dynamic paths inside the root pages directory, and each of the slugs will become pages/[slug].js.
The fallback is false in this example, but you can read more about using that here.
🖐 getStaticPaths alone does nothing, we need to next query data for each of the pages.
8.2 Query page data
Now we have programmatic paths being generated for our pages, it's now time to query the same data we did in step 5, but this time, send that data to our page.
Inside pages/[slug].js, export the following function:
Here we are destructuring the params object from the request sent to our page. The params here will be what we sent in getStaticPaths, so we'd expect to see slug here.
🖐 As well as destructuring, we are also renaming (or reassigning) the variable params to variables.
All we're doing in this file is importing each of our different form fields and exporting them.
The reason we do this is that when we import using import * as Fields, we can grab any of the named exports by doing Fields['FormCheckbox'], or Fields['FormInput'] like you see in components/Form.js.
Now that that we are importing these new fields, we next need to create each of them!
For each of the imports above, create new files inside components/FormFields for:
FormCheckbox.js
FormInput.js
FormSelect.js
FormTextarea.js
Once these are created, let's export each of the components as default, and write a minimum amount of code to make them work.
The code in the below files isn't too important. What's key about this tutorial is how we can very easily construct forms, and in fact any component or layout, using just data from the CMS. Magic! ✨
In this step we will install a library to handle our form state, and submissions, as well as create an onSubmit that'll we'll use in Step 12 to forward onto Hygraph.
Inside the terminal, let's install a new dependency:
yarn add -E react-hook-form # or npm install ...
Now it's not essential we use react-hook-form for managing our form, I wanted to provide a little closer to real world scenario than your typical setState example that are used in tutorials.
After we complete this tutorial, you should be in a position to return to each of your form fields, add some CSS, error handling, and more, made easy with react-hook-form!
Inside components/Form.js, add the following import to the top of the file:
Then inside your Form function after you return null if there are no fields, add the following:
const{ handleSubmit,...methods }=useForm();
constonSubmit=(values)=>console.log(values);
Finally, you'll need to wrap the current <form> with <FormContext {...methods}>, and add a onSubmit prop to the <form> that is onSubmit={handleSubmit(onSubmit)}.
Your final components/Form.js should look like this:
🖐 Let's start the Next.js development server, and view the console when we submit the form!
yarn dev # or npm run dev
Once the server has started, head to http://localhost:3000/contact (or a slug you defined in the CMS) to see your form!
Open the browser developer tools console, and then fill out the form and click submit!
You should now see the form values submitted!
#12. Submitting our Form to Hygraph with GraphQL Mutations
It's now time to take our form to the next level. We are going to update our Hygraph schema with a new Submission model that will be used to store submissions.
Inside the Hygraph Schema Editor, click + Add to create a new model.
Give the model a name of Submission,
Add a new JSON Editor field with the Display Name Form Data, and, API ID as formData,
Add a new Reference field with the Display Name/API ID Form/form , and select Form as the Model that can be referenced,
Configure the reverse field to Allow multiple values and set the default Display Name/API ID to (Submissions/submissions) respectively.
Things should look a little something like the following:
And the Form model should now have a new field submisson:
Since we want full control via the CMS what appears on our form, we'll just save all of that data inside formData JSON field.
🖐 Using something like webhooks would enable you to forward formData onto a service like Zapier, and do what you need to with the data, all without writing a single line of code! ✨
In order to use the Mutations API, we'll need to configure our API access to permit mutations and create a dedicated Permanent Auth Token. Don't enable Mutations for the Public API, as anybody will be able to query/mutate your data!
Head to Settings > API Access > Permanent Auth Tokens and create a token with the following setup:
Next, Copy the token to the clipboard once created.
Inside of the root of your Next.js project, create the file .env and, add the following, replacing YOUR_TOKEN_HERE with your token:
HYGRAPH_MUTATION_TOKEN=YOUR_TOKEN_HERE
With this token added, let's also do some housekeeping. Replace the API Endpoint you created in/pages/[slug].js with a the .env variable HYGRAPH_ENDPOINT and assign the value inside .env:
Now before we can use the HYGRAPH_MUTATION_TOKEN, we'll need to update our components/Form/index.js to POST the values to a Next.js API route.
Inside the form, let's do a few things:
import useState from React,
Invoke useState inside your Form function,
Replace the onSubmit function,
Render error after the submit <button />
import{ useState }from'react'
// ...
exportdefaultfunctionForm({ fields }){
if(!fields)returnnull;
const[success, setSuccess]=useState(null);
const[error, setError]=useState(null);
// ...
constonSubmit=async(values)=>{
try{
const response =awaitfetch("/api/submit",{
method:"POST",
body:JSON.stringify(values),
});
if(!response.ok)
thrownewError(`Something went wrong submitting the form.`);
setSuccess(true);
}catch(err){
setError(err.message);
}
};
if(success)return<p>Form submitted. We'll be in touch!</p>;
return(
// ...
<buttontype="submit">Submit</button>
{error &&<span>{error}</span>}}
)
}
Finally we'll create the API route /api/submit that forwards requests to Hygraph securely. We need to do this to prevent exposing our Mutation Token to the public.
One of the best ways to scaffold your mutation is to use the API Playground inside your Hygraph project. It contains all of the documentation and types associated with your project/models.
If you've followed along so far, the following mutation is all we need to create + connect form submissions.
Now go ahead and submit the form, open the content editor and navigate to the Submission content.
You should see your new entry!
You could use Hygraph webhooks to listen for new submissions, and using another API route forward that onto a service of your choice, such as email, Slack or Zapier.
Now all that's left to do is deploy our Next.js site to Vercel. Next.js is buil, and managed by the Vercel team and the community.
To deploy to Vercel, you'll need to install the CLI.
npm i -g vercel # or yarn global add vercel
Once installed, all it takes to deploy is one command!
vercel # or vc
You'll next be asked to confirm whether you wish to deploy the current directory, and what the project is named, etc. The defaults should be enough to get you going! 😅
Once deployed, you'll get a URL to your site. Open the deployment URL and append /contact to see your form!
Jamie is a software engineer turned developer advocate. Born and bred in North East England, he loves learning and teaching others through video and written tutorials. Jamie currently publishes Weekly GraphQL Screencasts.
Share with others
Sign up for our newsletter!
Be the first to know about releases and industry news and insights.
Before we dive into creating our schema, let's first think about what we're going to need to enable our marketing team to spin up landing page forms from just using the CMS.
It all starts with a Page. Pages must have a slug field so we can easily look up content from the params of any request.
Next, for simplicity, each page will have an associated Form model. For the sake of this tutorial, we'll pick 4 form field types;
Input
Textarea
Select
Checkbox
Form Fields
If we think of a traditional form, let's try and replace all of the data points we need to recreate a simple contact form like the following:
<labelfor="favFramework">What's your favorite framework?</label>
<selectid="favFramework">
<optionvalue="react">React</option>
<optionvalue="vue">Vue</option>
<optionvalue="angular">Angular</option>
<optionvalue="svelte">Svelte</option>
</select>
</div>
<div>
<labelfor="message">Message</label>
<textareaid="message"placeholder="Leave a message"/>
</div>
<div>
<labelfor="terms">
<inputid="terms"type="checkbox"/>
I agree to the terms and privacy policy.
</label>
</div>
<div>
<buttontype="submit">Submit</button>
</div>
</form>
In the above form, we have some <input />'s that are required, some which are of type email, tel and text, while the <select /> has no placeholder or is required.
Hygraph has support for GraphQL Union Types. This means we can define models for each of our form field types, and associate them to our Form model as one "has many" field.
Our schema will end up looking a little something like the following...
Models
Page
Title, String, Single line text, Required, and used as a Title
Slug, String, Slug, Required - Specify {title} as the template
Form, Reference to Form
You can use the Slug field type that automatically generates a slug based on your title. You'll need to set the template. to{title} to make this work. You can always override slugs.
Form
Page, Reference, Accepts multiple Page values
Fields, Reference, Accepts multiple FormInput, FormTextarea, FormSelect and FormCheckbox values
FormInput
Name, String, Single line text, and used as a Title
Type, Enum, FormInputType dropdown
Label, String, Single line text
Placeholder, Single line text
Required, Boolean
Form, Reference to Form
FormTextarea
Name, String, Single line text, and used as a Title
Label, String Single line text
Placeholder, String, Single line text
Required, Boolean
Form, Reference to Form
FormSelect
Name, String, Single line text, and used as a Title
Now we have an idea of how our content model looks like. Let's create the models and their associations with eachother inside Hygraph.
You'll need an account to continue. Sign up or head to the Dashboard.
Once logged in, head to the Schema editor by selecting Schema from the side.
Click + Add in the sidebar above default system Asset model.
Go ahead and create the 7 models above. Don't worry about creating relations just yet, you can do them all at once after creating the other fields.
#3. Create an example Page and Form with Fields as a content editor
So that we are able to query, and build our forms, we're going to need some content inside our models.
Inside the Dashboard, head to the Content editor by selecting Content from the side.
Select the Page model and click + Create New from the top right.
Give your page a title and slug. I'll call use Contact Us, and contact, respectively.
Now underneath Form, click Create and add a new form.
Inside the inline Form content editor, click on Create and add a new document.
From the dropdown, select FormInput.
Inside the inline FormInput content editor, enter a name, type , label and placeholder for your form field. I'll add the values Name, TEXT, Your name, Name and set required to true.
Now click Save and publish.
Repeat steps 5-8 to add additional fields.
🖐 To follow along with the rest of this tutorial, I will be using the following values for my fields...
3 x FormInput's
Name
Name: name
Type: TEXT
Label: Name
Placeholder: Your name
Required: true
Email
Name: email
Type: EMAIL
Label: Email
Placeholder: Your email
Required: true
Tel
Name: tel
Type: TEL
Label: Tel
Placeholder: Your contact no.
Required: false
1 x FormTextarea
Message
Name: message
Label: Message
Placeholder: Leave a message
Required: true
1 x FormCheckbox
Terms
Name: terms
Label: I agree to the terms and privacy policy.
Required: true
1 x FormSelect
The FormSelect is a little special because it also references another model FormSelect.
First, create your FormSelect document as usual, entering the following.
Favourite Framework
Name: favFramework
Label: What's your favorite frontend framework?
Required: false
Next below Options, click on Create and add a new formOption.
Now for each of our choices below, repeat the steps to "Create and add a new formOption", and provide the value/option for each:
react/React
vue/Vue
angular/Angular
svelte/Svelte
Finally, click Save and publish on this and close each of the inline editors, making sure to publish any unsaved changes along the way.
Now we have created our fields, we can now reorder them using the content editor. This may be useful if you decide to add or remove some fields later, you can order the fields exactly the way you want them to appear.
✨ Simply drag each of the Field rows into the order you want. ✨
Hygraph has a flexible permissions system, which includes enabling certain user groups to do actions, and most importantly restrict who can query what data.
For the purposes of querying data to build our pages and forms, we'll enable public API queries.
To do this, go to your project Settings.
Open the API Access page
Enable Content from stage Published under Public API permissions
Save ✨
That's it! You can test this works using the API Playground and selecting Environment: master Public from the dropdown in the section above your query/result.
🖐 Make sure to copy your API Endpoint to the clipboard. We'll need it in step 8.
This comes in two significant parts. First we create the routes (or "paths") and then query for the data for each page with those path params.
8.1 Create programmatic page routes
First up is to add some code to our Next.js application that will automatically generate pages for us. For this we will be exporting the getStaticPaths function from a new file called [slug].js in our pages directory.
touch pages/[slug].js
Having a filename with square brackets may look like a typo, but rest assured this is a Next.js convention.
Inside pages/[slug].js add the following code to get going:
exportdefaultfunctionIndex(props){
return(
<pre>{JSON.stringify(props,null,2)}</pre>
)
}
If you're familiar with React already, you'll notice we are destructuring props from the Index function. We'll be updating this later to destructure our individual page data, but for now, we'll show the props data on each of our pages.
Inside pages/[slug].js, let's import graphql-request and initialize a new GraphQLClient client.
🖐 You'll need your API Endpoint from Step 6 to continue.
Finally inside getStaticPaths we are returning paths for our pages, and a fallback. These build the dynamic paths inside the root pages directory, and each of the slugs will become pages/[slug].js.
The fallback is false in this example, but you can read more about using that here.
🖐 getStaticPaths alone does nothing, we need to next query data for each of the pages.
8.2 Query page data
Now we have programmatic paths being generated for our pages, it's now time to query the same data we did in step 5, but this time, send that data to our page.
Inside pages/[slug].js, export the following function:
Here we are destructuring the params object from the request sent to our page. The params here will be what we sent in getStaticPaths, so we'd expect to see slug here.
🖐 As well as destructuring, we are also renaming (or reassigning) the variable params to variables.
All we're doing in this file is importing each of our different form fields and exporting them.
The reason we do this is that when we import using import * as Fields, we can grab any of the named exports by doing Fields['FormCheckbox'], or Fields['FormInput'] like you see in components/Form.js.
Now that that we are importing these new fields, we next need to create each of them!
For each of the imports above, create new files inside components/FormFields for:
FormCheckbox.js
FormInput.js
FormSelect.js
FormTextarea.js
Once these are created, let's export each of the components as default, and write a minimum amount of code to make them work.
The code in the below files isn't too important. What's key about this tutorial is how we can very easily construct forms, and in fact any component or layout, using just data from the CMS. Magic! ✨
In this step we will install a library to handle our form state, and submissions, as well as create an onSubmit that'll we'll use in Step 12 to forward onto Hygraph.
Inside the terminal, let's install a new dependency:
yarn add -E react-hook-form # or npm install ...
Now it's not essential we use react-hook-form for managing our form, I wanted to provide a little closer to real world scenario than your typical setState example that are used in tutorials.
After we complete this tutorial, you should be in a position to return to each of your form fields, add some CSS, error handling, and more, made easy with react-hook-form!
Inside components/Form.js, add the following import to the top of the file:
Then inside your Form function after you return null if there are no fields, add the following:
const{ handleSubmit,...methods }=useForm();
constonSubmit=(values)=>console.log(values);
Finally, you'll need to wrap the current <form> with <FormContext {...methods}>, and add a onSubmit prop to the <form> that is onSubmit={handleSubmit(onSubmit)}.
Your final components/Form.js should look like this:
🖐 Let's start the Next.js development server, and view the console when we submit the form!
yarn dev # or npm run dev
Once the server has started, head to http://localhost:3000/contact (or a slug you defined in the CMS) to see your form!
Open the browser developer tools console, and then fill out the form and click submit!
You should now see the form values submitted!
#12. Submitting our Form to Hygraph with GraphQL Mutations
It's now time to take our form to the next level. We are going to update our Hygraph schema with a new Submission model that will be used to store submissions.
Inside the Hygraph Schema Editor, click + Add to create a new model.
Give the model a name of Submission,
Add a new JSON Editor field with the Display Name Form Data, and, API ID as formData,
Add a new Reference field with the Display Name/API ID Form/form , and select Form as the Model that can be referenced,
Configure the reverse field to Allow multiple values and set the default Display Name/API ID to (Submissions/submissions) respectively.
Things should look a little something like the following:
And the Form model should now have a new field submisson:
Since we want full control via the CMS what appears on our form, we'll just save all of that data inside formData JSON field.
🖐 Using something like webhooks would enable you to forward formData onto a service like Zapier, and do what you need to with the data, all without writing a single line of code! ✨
In order to use the Mutations API, we'll need to configure our API access to permit mutations and create a dedicated Permanent Auth Token. Don't enable Mutations for the Public API, as anybody will be able to query/mutate your data!
Head to Settings > API Access > Permanent Auth Tokens and create a token with the following setup:
Next, Copy the token to the clipboard once created.
Inside of the root of your Next.js project, create the file .env and, add the following, replacing YOUR_TOKEN_HERE with your token:
HYGRAPH_MUTATION_TOKEN=YOUR_TOKEN_HERE
With this token added, let's also do some housekeeping. Replace the API Endpoint you created in/pages/[slug].js with a the .env variable HYGRAPH_ENDPOINT and assign the value inside .env:
Now before we can use the HYGRAPH_MUTATION_TOKEN, we'll need to update our components/Form/index.js to POST the values to a Next.js API route.
Inside the form, let's do a few things:
import useState from React,
Invoke useState inside your Form function,
Replace the onSubmit function,
Render error after the submit <button />
import{ useState }from'react'
// ...
exportdefaultfunctionForm({ fields }){
if(!fields)returnnull;
const[success, setSuccess]=useState(null);
const[error, setError]=useState(null);
// ...
constonSubmit=async(values)=>{
try{
const response =awaitfetch("/api/submit",{
method:"POST",
body:JSON.stringify(values),
});
if(!response.ok)
thrownewError(`Something went wrong submitting the form.`);
setSuccess(true);
}catch(err){
setError(err.message);
}
};
if(success)return<p>Form submitted. We'll be in touch!</p>;
return(
// ...
<buttontype="submit">Submit</button>
{error &&<span>{error}</span>}}
)
}
Finally we'll create the API route /api/submit that forwards requests to Hygraph securely. We need to do this to prevent exposing our Mutation Token to the public.
One of the best ways to scaffold your mutation is to use the API Playground inside your Hygraph project. It contains all of the documentation and types associated with your project/models.
If you've followed along so far, the following mutation is all we need to create + connect form submissions.
Now go ahead and submit the form, open the content editor and navigate to the Submission content.
You should see your new entry!
You could use Hygraph webhooks to listen for new submissions, and using another API route forward that onto a service of your choice, such as email, Slack or Zapier.
Now all that's left to do is deploy our Next.js site to Vercel. Next.js is buil, and managed by the Vercel team and the community.
To deploy to Vercel, you'll need to install the CLI.
npm i -g vercel # or yarn global add vercel
Once installed, all it takes to deploy is one command!
vercel # or vc
You'll next be asked to confirm whether you wish to deploy the current directory, and what the project is named, etc. The defaults should be enough to get you going! 😅
Once deployed, you'll get a URL to your site. Open the deployment URL and append /contact to see your form!
Jamie is a software engineer turned developer advocate. Born and bred in North East England, he loves learning and teaching others through video and written tutorials. Jamie currently publishes Weekly GraphQL Screencasts.
Share with others
Sign up for our newsletter!
Be the first to know about releases and industry news and insights.