Recipe: forms
Developer preview
Goal: authors put a newsletter form on a page in Canvas, and set its labels. The visitor types an email address. A Next.js Server Action validates the address and sends it to your email service. After the signup, Uniform Context gets a quirk, so personalizations can change for the visitor.
You will make these files:
| File | Type | Job |
|---|---|---|
components/newsletter/types.ts | Shared | The state of the form. |
app/actions/subscribe.ts | Server Action | Validates the data and sends it to your email service. |
components/newsletter/NewsletterFormClient.tsx | Client component | The form, the errors and the success message. |
components/newsletter/NewsletterForm.tsx | Server component | The Uniform component. It reads the parameters. |
Prerequisites#
- An app with the Uniform SDK and a
resolveComponentfunction. Refer to Map Uniform types to React components. - A component type
newsletterFormin Uniform, with these text parameters:title,emailLabel,buttonLabelandsuccessMessage. Allow the type in the slots where authors can put the form. - An email service with an HTTP API. The example sends a
POSTrequest to the URL in the environment variableNEWSLETTER_API_URL. Change this part for your service.
Step 1: Define the form state#
The Server Action and the client component share this type:
components/newsletter/types.ts
Step 2: Make the Server Action#
app/actions/subscribe.ts
"use server"at the top of the file makes each exported async function a Server Action.- With
useActionState, the action gets the previous state as the first argument, and the form data as the second argument. - The action returns the new state. It returns the email address on an error, so the form keeps the value.
warning
A Server Action is a public endpoint. Each person who can send a POST request to your page can call it. Validate all data on the server. Add rate limits or a bot check before you use the form in production.
Step 3: Make the client form#
components/newsletter/NewsletterFormClient.tsx
useActionStatereturns the state, the action for the<form>, andpending.pendingistruewhile the action runs.type="email"andrequiredgive a fast check in the browser. The server check in Step 2 is the real check.useUniformContext()returns{ context }.contextisundefineduntil the browser Context is ready. Thus the code usescontext?..context.update({ quirks })gives the quirknewsletterthe valuesubscribed.
Step 4: Make the Uniform component#
The Uniform component is a server component. It reads the parameters, and gives plain strings to the client form:
components/newsletter/NewsletterForm.tsx
UniformTextlets authors edit the title in the page in Canvas.- The other labels have default values, because a parameter is
undefinedwhen the author did not fill it in. - Only serializable props can go from a server component to a client component. Thus the code gives strings, not the parameter objects.
Step 5: Register the component#
Add the component to your resolveComponent map:
components/resolveComponent.tsx
Then put a newsletterForm component on a composition in Canvas, and publish it.
How it works#
- The page renders the
NewsletterFormserver component with the parameters from Uniform. - The browser hydrates
NewsletterFormClient. - The visitor submits the form. React sends a
POSTrequest to the current URL with the form data. - Next.js runs
subscribeon the server, and sends the new state back to the browser. - The client form shows the error, or the success message.
- On success, the browser Context gets the quirk
newsletter: subscribed.
The page stays static. The Server Action does not render the page again, because it does not call revalidatePath or refresh.
Personalization after the signup#
You can use the quirk in Uniform:
- Add the quirk
newsletterto your Uniform project, and publish the Context manifest. - Use the quirk in personalization criteria or in visibility rules. For example, show a "Thank you" banner and not the signup form to visitors with
newsletter=subscribed.
When the quirk changes, the page updates in the browser:
- Lite mode: the browser chooses all variants, so the page changes at once.
- Edge mode: personalizations that the edge rendered also choose again. A/B tests keep their variant.
- Visibility rules: the browser applies them with the current quirks.
On the next page load, the quirk comes from a cookie. The browser Context writes the quirks to the cookie ufvdqk only when the visitor gave consent, and when quirkSerialization is on (the default). The edge middleware reads this cookie. Refer to Client context and Personalization.
Limits#
- Consent: without consent, the browser Context does not write the quirk to a cookie. The edge and the next full page load do not see it.
- No data in Uniform: the form sends the data to your service. Uniform does not store form data.
- Canvas preview: a submit in the Canvas preview calls the real Server Action. Use a test address, or skip the request to your service in draft mode.
- Middleware: the middleware rewrites the
POSTrequest of the action, as it does for other requests. Make sure that your middleware matcher includes the page.