Forms with Tailwind UI and Next Safe Action

Article written with ChatGPT until I have a chance to upload my own work! Things are crazy for me right now in the fall of 2024 :) devflow.tech

Creating Forms Using TailwindCSS and Next-Safe-Action

Forms are an essential part of any web application, and ensuring they are user-friendly, responsive, and secure is key to a smooth user experience. TailwindCSS, a utility-first CSS framework, makes styling forms a breeze, while next-safe-action offers a simple way to handle form submissions securely in Next.js. In this article, we'll explore how to create beautiful, functional forms using TailwindCSS and next-safe-action for secure handling.

Why TailwindCSS and Next-Safe-Action?

TailwindCSS

TailwindCSS allows developers to style forms quickly and consistently without leaving the HTML file. By using utility classes, you can avoid bloated CSS files and ensure responsive design across different screen sizes. For form elements, TailwindCSS provides utilities that help you:

  • Add margins, padding, and alignment.
  • Customize form inputs, buttons, and text areas.
  • Control layout, spacing, and responsive behaviors.

Next-Safe-Action

Forms often involve handling sensitive data, such as user inputs for registration or payment. next-safe-action provides a secure way to handle form submissions by managing server-side actions securely in Next.js. It minimizes security risks like Cross-Site Scripting (XSS) and Cross-Site Request Forgery (CSRF), ensuring form data is safely processed.

Building the Form UI with TailwindCSS

Let's start by creating a simple form using TailwindCSS. Here's a basic example of a registration form:

<form className="mx-auto max-w-lg rounded-lg bg-white p-6 shadow-md">
  <div className="mb-4">
    <label
      className="mb-2 block text-sm font-bold text-gray-700"
      htmlFor="name"
    >
      Name
    </label>
    <input
      className="focus:shadow-outline w-full appearance-none rounded border px-3 py-2 leading-tight text-gray-700 shadow focus:outline-none"
      id="name"
      type="text"
      placeholder="Enter your name"
    />
  </div>
  <div className="mb-4">
    <label
      className="mb-2 block text-sm font-bold text-gray-700"
      htmlFor="email"
    >
      Email
    </label>
    <input
      className="focus:shadow-outline w-full appearance-none rounded border px-3 py-2 leading-tight text-gray-700 shadow focus:outline-none"
      id="email"
      type="email"
      placeholder="Enter your email"
    />
  </div>
  <div className="mb-6">
    <label
      className="mb-2 block text-sm font-bold text-gray-700"
      htmlFor="password"
    >
      Password
    </label>
    <input
      className="focus:shadow-outline mb-3 w-full appearance-none rounded border px-3 py-2 leading-tight text-gray-700 shadow focus:outline-none"
      id="password"
      type="password"
      placeholder="Enter your password"
    />
  </div>
  <div className="flex items-center justify-between">
    <button
      className="focus:shadow-outline rounded bg-blue-500 px-4 py-2 font-bold text-white hover:bg-blue-700 focus:outline-none"
      type="submit"
    >
      Sign Up
    </button>
  </div>
</form>

Breakdown of the TailwindCSS Code

  1. Form Container: The form is wrapped in a `max-w-lg` container for maximum width, centered using `mx-auto`. We also applied padding, a background color, a shadow for elevation, and rounded corners with `rounded-lg`.

  2. Labels and Inputs: Each input field has a label styled with Tailwind classes like `text-gray-700` for color, `text-sm` for size, and `font-bold` for weight. The input fields use `shadow`, `appearance-none`, `border`, `rounded`, and `focus:outline-none` to ensure a smooth and responsive look.

  3. Button: The submit button uses utility classes like `bg-blue-500` for background, `hover:bg-blue-700` for hover effect, `text-white` for text color, and `font-bold` for the font weight. Rounded corners and focus states are also defined.

With just a few utility classes, you can create a clean, responsive form that's ready for integration with your backend logic.

Handling Form Submissions Securely with Next-Safe-Action

To handle the form submission securely, we can use `next-safe-action`. Here’s a simplified version of how to integrate it into your Next.js project.

  1. Install Next-Safe-Action:
npm install next-safe-action
  1. Creating a Server Action: Next-Safe-Action allows you to define your form submission logic within server actions. Create a file, for example, `actions.js`, and define your server-side logic like this:
// actions.js
import { createServerAction } from 'next-safe-action'

export const submitForm = createServerAction(async (formData) => {
  const { name, email, password } = formData

  // Perform form validation and other backend logic here
  if (!name || !email || !password) {
    throw new Error('All fields are required.')
  }

  // Return success message
  return { success: true, message: 'Form submitted successfully!' }
})
  1. Connecting the Form to Server Actions: Modify your form to handle the submission using `next-safe-action`:
import { submitForm } from './actions'

export default function RegisterForm() {
  const handleSubmit = async (event) => {
    event.preventDefault()

    const formData = new FormData(event.target)
    try {
      const response = await submitForm(Object.fromEntries(formData))
      console.log(response.message)
    } catch (error) {
      console.error('Error submitting form:', error.message)
    }
  }

  return (
    <form
      onSubmit={handleSubmit}
      className="mx-auto max-w-lg rounded-lg bg-white p-6 shadow-md"
    >
      {/* Form fields (same as before) */}
    </form>
  )
}

Explanation

  • Server Action: The `submitForm` action is triggered when the form is submitted. It takes the form data as input and performs necessary validation or backend operations.
  • Form Handling: On form submission, we prevent the default action and use the `submitForm` server action to process the data. This ensures the form submission is secure and server-side logic is separated from the frontend.

Error Handling and Success Messages

To provide a better user experience, you can add error handling and display success messages within the form itself:

import { useState } from 'react'
import { submitForm } from './actions'

export default function RegisterForm() {
  const [errorMessage, setErrorMessage] = useState('')
  const [successMessage, setSuccessMessage] = useState('')

  const handleSubmit = async (event) => {
    event.preventDefault()

    const formData = new FormData(event.target)
    try {
      const response = await submitForm(Object.fromEntries(formData))
      setSuccessMessage(response.message)
      setErrorMessage('')
    } catch (error) {
      setErrorMessage(error.message)
      setSuccessMessage('')
    }
  }

  return (
    <form
      onSubmit={handleSubmit}
      className="mx-auto max-w-lg rounded-lg bg-white p-6 shadow-md"
    >
      {/* Form fields (same as before) */}
      {errorMessage && <p className="text-red-500">{errorMessage}</p>}
      {successMessage && <p className="text-green-500">{successMessage}</p>}
    </form>
  )
}

Benefits of Using Next-Safe-Action

  • Server-side Validation: Ensures form data is processed and validated securely on the server, reducing the risk of client-side manipulation.
  • Separation of Concerns: Keeps server-side logic separate from the frontend code, leading to cleaner, more maintainable code.
  • Security: Built-in protections against common web vulnerabilities like XSS and CSRF.

Conclusion

Building forms with TailwindCSS and securing them using `next-safe-action` is a powerful combination for creating stylish, responsive, and secure forms in Next.js applications. By combining TailwindCSS's utility-first approach with the secure handling capabilities of Next-Safe-Action, you can ensure your forms are both user-friendly and protected against vulnerabilities.

Next time you build a form, you'll have the tools to do it right—looking sharp with TailwindCSS and keeping things locked down with Next-Safe-Action.