Newsletter signup form example

This is a simple newsletter signup form example. It has client side validation and displays a success message after a successful submission.

Subscribe to our newsletter

newsletter-signup-form.tsx

'use client';
 
import { Button } from '@/ui/components/button/button';
import { Checkbox } from '@/ui/components/forms/checkbox';
import { Form, FormRoot } from '@/ui/components/forms/form';
import {
  FormServerError,
  FormStatus,
  FormSuccessMessage,
} from '@/ui/components/forms/form-status';
import { useForm } from '@/ui/components/forms/hooks/use-form';
import { TextField } from '@/ui/components/forms/text-field';
import { validators } from '@/ui/components/forms/util';
import { newsletterSignupAction } from './action';
import { LoginFormValues } from './types';
 
export const NewsletterSignupForm = () => {
  const form = useForm<LoginFormValues>({
    onSubmit: async ({ values, reset }) => {
      await newsletterSignupAction(values);
      reset(); // on success clear form values
    },
  });
 
  return (
    <FormRoot context={form}>
      <h2 id="login-form-heading" className="mb-4 text-3xl font-bold">
        Subscribe to our newsletter
      </h2>
      <FormStatus>
        {form.serverError && (
          <FormServerError
            title="Something went wrong!"
            className="animate-in fade-in-90 slide-in-from-bottom-10 duration-300"
          />
        )}
        {form.status === 'success' && (
          <FormSuccessMessage
            title="Success!"
            message="You are now subscribed to our newsletter"
            className="animate-in fade-in-90 slide-in-from-bottom-10 duration-300"
          />
        )}
      </FormStatus>
      {form.status !== 'success' && (
        <Form
          className="flex flex-row gap-2 rounded-lg border-2 border-gray-200 p-4 shadow-xl"
          aria-labelledby="login-form-heading"
        >
          <div className="flex flex-1 flex-col gap-2">
            <TextField
              id="email"
              name="email"
              label="Email"
              type="email"
              autoComplete="email"
              validate={(value) => {
                if (!value) {
                  return 'Please enter your email address';
                }
 
                if (!validators.email(value)) {
                  return 'Please enter a valid email address';
                }
              }}
              isRequired
            />
            <Checkbox
              id="privacyPolicy"
              name="privacyPolicy"
              label="I agree to the privacy policy"
              isRequired
              validate={(value) => {
                if (!value) {
                  return 'You must agree to the privacy policy';
                }
              }}
            />
          </div>
          <div className="pt-6">
            <Button
              type="submit"
              className="h-11"
              disabled={form.isPending}
              loading={form.isPending}
            >
              Subscribe
            </Button>
          </div>
        </Form>
      )}
    </FormRoot>
  );
};