Skip to main content

Server Actions in Forms

React extends the HTML <form> element to allow Server Actions to be invoked with the action prop.

export default function Page() {
async function createInvoice(formData: FormData) {
'use server';

const rawFormData = {
customerId: formData.get('customerId'),
amount: formData.get('amount'),
status: formData.get('status'),
};

// mutate data
// revalidate cache
}

return <form action={createInvoice}>...</form>;
}

Handling Form State

To check if the form is submitting in React, use the useFormStatus hook. This hook returns the status for a specific <form> and must be defined as a child of the <form> element.

'use client'

import { useFormStatus } from 'react-dom'

export function SubmitButton() {
const { pending } = useFormStatus()

return (
<button type="submit" disabled={pending}>
Add
</button>
)
}

Since useFormStatus is a React hook, it should be used within a Client Component.

Submit a Form Programmatically

The requestSubmit method allows you to trigger the form's submit event, including validation and event listeners, as if the form was submitted by a user.

// app/page.js
import { submitForm } from './actions';
import { useState } from 'react';

export default function HomePage() {
const [formData, setFormData] = useState({ name: '', email: '' });
const formRef = useRef(null);

const handleChange = (e) => {
const { name, value } = e.target;
setFormData((prevData) => ({ ...prevData, [name]: value }));
};

const handleProgrammaticSubmit = async (e) => {
e.preventDefault();
formRef.current.requestSubmit();
};

return (
<form ref={formRef} action={submitForm} method="post">
<input
type="text"
name="name"
value={formData.name}
onChange={handleChange}
placeholder="Name"
/>
<input
type="email"
name="email"
value={formData.email}
onChange={handleChange}
placeholder="Email"
/>
<button type="button" onClick={handleProgrammaticSubmit}>
Submit Programmatically
</button>
<button type="submit">Submit Normally</button>
</form>
);
}