How to Use Server Side Forms in NextJS?

COMMENTS ()
Tweet

Exploring forms in Next.js 14, Server Actions, React Server Components (RSC), and Next’s App Router were utilized. In modern web development, handling forms efficiently and securely is crucial.

Next.js, a popular React framework, offers powerful tools and techniques to manage forms on the server side, enhancing performance, security, and user experience. 

Whether building a simple contact form or a complex data entry interface, this guide will help you implement server-side forms in Next.js, making your applications more efficient and resilient.

Operating Forms in NextJS

Installing the most recent version of Next.js via Next’s App Router. Using Server Actions and React Server Components (RSC), create a message list component and a form component named directory-creates-form on the root page.

// page.tsx (src/app/page)
import { DirectoryCreateForm } from "@/components/directory-create-form";
import { MessageList } from "@/components/message-list";
export default function Home() {
 return (
   <>
     {/* Background SVG */}
     
       
     
     {/* Main content */}

{/* Directory Create Form */}

{/* Divider */}

{/* Message List */}

 

</>
);
}

 

Operating Actions

Implement the getMessages function in the action.ts file. Although initially absent, the createMessage function is used in the form’s action attribute. This function is then created to operate on the same artificial data.

The first arguments are taken from the FormData object, which holds the entire form data. This object adds new messages to the messages array, simulating a slow network with a pseudo delay of 300ms. The revalidatePath function is used to revalidate the page’s route (‘/’) to display new messages after form submission without reloading the page.

// action.tsx (src/app/action)
"use server";
import { z } from "zod";
import { revalidatePath } from "next/cache";
import {
 FormState,
 fromErrorToFormState,
 toFormState,
} from "@/utils/to-form-state";
type Message = {
 id: string;
 name: string;
 employeeId: string;
 contactNo: string;
 dateOfJoining: Date;
};
let messages: Message[] = [];
export const getMessages = async (): Promise<Message[]> => {
 await new Promise((resolve) => setTimeout(resolve, 300));
 return Promise.resolve(messages);
};
// Regular expression for validating phone numbers
const phoneNumberRegex = /^\d{10,15}$/;
// Regular expression for validating employee ID
const empIdRegex = /^\d{3,5}$/;
const createMessageSchema = z.object({
 name: z.string().min(1).max(50),
 employeeId: z.string().refine((value) => empIdRegex.test(value), {
   message: "Invalid Employee ID. Must be 3 to 5 digits.",
 }),
 contactNo: z.string().refine((value) => phoneNumberRegex.test(value), {
   message: "Invalid Phone number. Must be 10 to 15 digits.",
 }),
 dateOfJoining: z.string().transform((val, ctx) => {
   const date = new Date(val);
   if (isNaN(date.getTime())) {
     ctx.addIssue({
       code: z.ZodIssueCode.custom,
       message: "Invalid date. Must be a valid date string.",
     });
     return z.NEVER;
   }
   return date;
 }),
});
export const createMessage = async (
 formState: FormState,
 formData: FormData
) => {
 await new Promise((resolve) => setTimeout(resolve, 300));
 try {
   const data = createMessageSchema.parse({
     name: formData.get("name"),
     employeeId: formData.get("employeeId"),
     contactNo: formData.get("contactNo"),
     dateOfJoining: formData.get("dateOfJoining"),
   });
   messages.push({
     id: crypto.randomUUID(),
     ...data,
   });
   revalidatePath("/");
   return toFormState("SUCCESS", "Employee successfully created");
 } catch (error) {
   return fromErrorToFormState(error);
 }
};

Operating Directory Create Form State

React’s useFormState Hook is used with a server action, enabling the transfer of customer data between the client component and the server action. The new hook consists of an initial state object and the server action, returning the current form state and the improved server action.

// directory-create-form.tsx (src/compnents/directory-create-form)
"use client";
import { useFormState } from "react-dom";
import { createMessage } from "@/app/actions";
import { SubmitButton } from "./submit-button";
import { EMPTY_FORM_STATE } from "@/utils/to-form-state";
import { useToastMessage } from "@/hooks/use-toast-message";
import { FieldError } from "./field-error";
import { useFormReset } from "@/hooks/use-form-reset";
const DirectoryCreateForm = () => {
 const [formState, action] = useFormState(createMessage, EMPTY_FORM_STATE);
 const noScriptFallback = useToastMessage(formState);
 const formRef = useFormReset(formState);
 return (
{noScriptFallback}

); }; type FormFieldProps = { label: string; name: string; placeholder: string; formState: any; // Adjust the type according to your form state type }; const FormField: React.FC = ({ label, name, placeholder, formState, }) => ( <> </> ); export { DirectoryCreateForm };

Operating Message List

The server component handles data delivery on the server and makes its list of messages available. It uses await to fetch data, while the function component is designated async.

// message-list.tsx (src/components/message-list)
import { getMessages } from "@/app/actions";
const formatDate = (date: Date): string => {
 return date.toISOString().split("T")[0]; // Converts date to 'YYYY-MM-DD' format
};
const MessageList: React.FC = async () => {
 const directories = await getMessages();
 return (
   <>

Employees Directories

 


 

    • {directories.map((directory) => (

 


 

))}

</> ); }; type ListItemProps = { label: string; value: string | Date; }; const ListItem: React.FC = ({ label, value }) => (

  • {label}: {typeof value === “string” ? value : formatDate(value)}

); export { MessageList };

Conclusion

This blog covers forms in Next.js with server actions and server components, demonstrating a web-native world with a progressive enhancement that works without JavaScript. Next and React provide fundamental building blocks, with many features the framework offers.

Imagine if a new useAction hook could be created using a framework consisting of useFormReset, useToastMessage, and useFormState. This would resolve many of the manual tasks completed in this blog.

Senior Software Engineer

CALL

USA408 365 4638

VISIT

1301 Shoreway Road, Suite 160,

Belmont, CA 94002

Contact us

Whether you are a large enterprise looking to augment your teams with experts resources or an SME looking to scale your business or a startup looking to build something.
We are your digital growth partner.

Tel: +1 408 365 4638
Support: +1 (408) 512 1812