Build a Frontend for Your Nitric Survey App with React

In this guide, you'll build a simple web application using React that connects to the survey backend we created with Nitric.

What You'll Build

  • A form to submit survey responses to the Nitric backend
  • A link to retrieve and view the submitted PDF receipt

Prerequisites

Project Setup

This guide assumes you already have the survey backend project.

To add a website frontend, create a new Vite project:

npm create vite@latest main-website -- --template react-ts
cd main-website
npm install
cd ..

Next, configure your nitric.yaml to enable and configure the website:

Along with the website configuration, you will need to add the preview key to your nitric.yaml, as website support is currently a preview feature and subject to change.

name: survey-app
services:
- basedir: ''
match: services/*.ts
runtime: node
start: npm run dev:services $SERVICE_PATH
batch-services: []
websites:
- basedir: ./main-website
error: index.html
build:
command: npm run build
output: dist
dev:
command: npm run dev -- --port 3000
url: http://localhost:3000
runtimes:
node:
dockerfile: ./node.dockerfile
context: ''
args: {}
preview:
- websites

Connect to the API

Create a new folder components inside main-website/src and add the following file:

This component collects the user's name, rating, and feedback, then submits the data to the Nitric API.

import React, { useState } from 'react'
const SurveyForm = () => {
const [formData, setFormData] = useState({
name: '',
rating: 1,
feedback: '',
})
const [submissionId, setSubmissionId] = useState<string | null>(null)
const handleChange = (
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
) => {
setFormData({ ...formData, [e.target.name]: e.target.value })
}
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault()
try {
const response = await fetch('/api/forms/forms/feedback', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
...formData,
// ensure rating is a number
rating: Number(formData.rating),
}),
})
if (!response.ok) throw new Error('Failed to submit')
const data: { id: string } = await response.json()
setSubmissionId(data.id)
alert('Survey submitted successfully!')
} catch (error) {
console.error('Submission error:', error)
alert('Failed to submit survey.')
}
}
const fetchReceipt = async () => {
try {
const response = await fetch(`/api/receipts/receipts/${submissionId}`)
if (!response.ok) throw new Error('Could not get receipt URL')
const url = await response.text()
window.location.href = url
} catch (err) {
console.error(err)
alert('Failed to load receipt')
}
}
return (
<div style={{ maxWidth: 500, margin: '0 auto', padding: 20 }}>
<h2>Feedback Survey</h2>
<form
onSubmit={handleSubmit}
style={{ display: 'flex', flexDirection: 'column', gap: 12 }}
>
<label>
Name:
<input
type="text"
name="name"
value={formData.name}
onChange={handleChange}
required
/>
</label>
<label>
Rating (1-5):
<input
type="number"
name="rating"
value={formData.rating}
onChange={handleChange}
min="1"
max="5"
required
/>
</label>
<label>
Feedback:
<textarea
name="feedback"
value={formData.feedback}
onChange={handleChange}
/>
</label>
<button type="submit">Submit</button>
</form>
{submissionId && (
<div style={{ marginTop: 20 }}>
<p>
Thank you! Your submission ID is <code>{submissionId}</code>
</p>
<button onClick={fetchReceipt}>View Receipt</button>
</div>
)}
</div>
)
}
export default SurveyForm

Add the component to your app

Update the following file to use your new form component:

import React from 'react'
import SurveyForm from './components/SurveyForm'
function App() {
return (
<div>
<SurveyForm />
</div>
)
}
export default App

Run the Frontend Locally

With your nitric.yaml configured correctly and the site added as a Nitric website, you can start both the frontend and backend using:

nitric start

This will start the API and the website together, and serve your React frontend from http://localhost:5000 (confirm the port in the console output).

To test it, visit http://localhost:5000 in your browser and submit a survey response. You should see a link to view the generated receipt hosted by the backend.

Deploying to AWS

With the frontend tested, you can deploy it to the cloud knowing it will function as intended. Nitric will deploy your frontend and backend together, serving them under the same origin. This eliminates CORS issues and removes the need for headers, complex gateway config, or workarounds.

Deployment to the cloud requires that you have created a stack file. If you had followed the backend guide, you should have this stack file already; otherwise, follow the steps below.

Create your stack

Create an AWS stack called aws-staging for your staging environment.

nitric stack new aws-staging aws

Inside the stack file, set your region.

provider: nitric/aws@latest
region: us-east-2

Deploy

Deploy to AWS using the nitric up command. Ensure you have set up your AWS credentials correctly.

nitric up

This should output a URL pointing to the CDN like xxxx.cloudfront.net. You can go to this URL in your browser, and it will take you to the website with your survey form. All API routes will be served under xxxx.cloudfront.net/apis.

Tear down

To avoid unwanted costs of running your test app, you can tear down the stack using the nitric down command.

nitric down
Last updated on May 8, 2025