Part 105: Embracing Progressive Enhancement with Next.js Server Actions

[App] Server Actions

[App] Server Actions

In the ever-evolving landscape of web development, creating applications that offer seamless user experiences across various environments is crucial. Enter progressive enhancement, a strategy that ensures basic functionality is accessible to all users, while offering enhanced features to those with more capable browsers. In this post, we'll delve into how Next.js Server Actions enable progressive enhancement, allowing forms to function even without JavaScript.

The Power of revalidatePath

Before diving into progressive enhancement, it's worth noting how Next.js handles page updates. Thanks to the revalidatePath function, the ReviewPage automatically regenerates whenever a user posts a new comment. This ensures that all users see the most up-to-date content without manual intervention.

Server Actions and Progressive Enhancement

A standout advantage of Server Actions in Next.js is their ability to support progressive enhancement. This means that even if JavaScript is disabled, core functionalities remain intact. Let's explore this with a practical example.

Testing Without JavaScript

To see how our form behaves without JavaScript, we'll disable it in the browser's developer tools:

  1. Disable JavaScript: Open your browser's developer tools, navigate to the settings, and disable JavaScript for the current session.

  2. Reload the Page: After disabling JavaScript, reload the page. You'll notice that while JavaScript requests are blocked, the page still renders correctly. This is because most of it is server-rendered.

  3. Submit a Form: Enter a comment, such as "Look ma: no JS," and submit the form. Observe how the browser reloads the entire page, causing a loss in scroll position. Despite this, your new comment appears at the bottom of the list, confirming that the form submission was successful.

How It Works

When JavaScript is disabled, the form submission process works as follows:

  • Standard Form Submission: The browser makes a POST request to the server, similar to traditional form submissions.

  • HTTP Redirect: The server responds with a "303 See Other" status code, along with a "Location" header that directs the browser to a specific URL.

  • Page Reload: The browser then makes a GET request to the specified URL, fetching the full HTML document for the page.

Without JavaScript, Next.js can't update elements using client-side routing or React Server Components. Instead, it returns a complete HTML document, mimicking a traditional multi-page application. This ensures that the form submission process remains intact, even in the absence of JavaScript.

Progressive Enhancement in Action

While the application functions without JavaScript, enabling it provides a smoother experience. With JavaScript, the page doesn't need to reload entirely; Next.js can update specific elements dynamically, offering a more interactive and efficient user experience.

Code Example

Here's a simple example of how you might implement a form in Next.js to leverage Server Actions:

// components/CommentForm.jsx

import { revalidatePath } from 'next/cache';
import { redirect } from 'next/navigation';
import { createComment } from '@/lib/comments';

export default function CommentForm({ slug, title }) {
  async function action(formData) {
    'use server';
    const comment = await createComment({
      slug,
      user: formData.get('user'),
      message: formData.get('message'),
    });
    console.log('created:', comment);
    revalidatePath(`/reviews/${slug}`);
    redirect(`/reviews/${slug}`);
  }

  return (
    <form action={action}
      className="border bg-white flex flex-col gap-2 mt-3 px-3 py-3 rounded">
      <p className="pb-1">
        Already played <strong>{title}</strong>? Have your say!
      </p>
      <div className="flex">
        <label htmlFor="userField" className="shrink-0 w-32">
          Your name
        </label>
        <input id="userField" name="user"
          className="border px-2 py-1 rounded w-48"
        />
      </div>
      <div className="flex">
        <label htmlFor="messageField" className="shrink-0 w-32">
          Your comment
        </label>
        <textarea id="messageField" name="message"
          className="border px-2 py-1 rounded w-full"
        />
      </div>
      <button type="submit"
        className="bg-orange-800 rounded px-2 py-1 self-center
                   text-slate-50 w-32 hover:bg-orange-700">
        Submit
      </button>
    </form>
  );
}

Conclusion

Progressive enhancement is a vital approach in web development, ensuring that essential functionality is accessible to all users while offering enhanced experiences for those with JavaScript-enabled browsers. By leveraging Next.js Server Actions, developers can create robust applications that gracefully degrade, providing a consistent user experience regardless of browser capabilities. This not only broadens the accessibility of your application but also enhances its resilience in diverse environments.

Last updated