Login form example

This is a simple login form example. It has client side validation and displays an error message if the login fails.

Sign in

login-form.tsx

'use client';
 
import { RiLockPasswordLine, RiUser3Line } from '@remixicon/react';
import { redirect } from 'next/navigation';
import { Button } from '@/ui/components/button/button';
import { Checkbox } from '@/ui/components/forms/checkbox';
import { Form } from '@/ui/components/forms/form';
import { useForm } from '@/ui/components/forms/hooks/use-form';
import { TextField } from '@/ui/components/forms/text-field';
import {
  FormErrors,
  FormServerError,
  validators,
} from '@/ui/components/forms/validation';
import { loginAction } from './action';
 
export const LoginForm = () => {
  const form = useForm<{
    email: string;
    password: string;
    rememberMe: string;
  }>({
    onSubmit: async ({ values }) => {
      await loginAction(values);
      redirect('/dashboard');
    },
  });
 
  return (
    <FormRoot
      context={form}
      className="max-w-lg rounded-lg border-2 border-gray-200 p-4 shadow-xl"
    >
      <h2 id="login-form-heading" className="text-3xl font-bold">
        Sign in
      </h2>
      <FormStatus>
        {form.serverError && (
          <FormServerError
            title="Could not sign in"
            errorMessage={form.serverError}
          />
        )}
      </FormStatus>
      <Form
        className="flex flex-col gap-4"
        aria-labelledby="login-form-heading"
      >
        <TextField
          id="email"
          name="email"
          label="Email"
          type="email"
          autoComplete="email"
          icon={<RiUser3Line size={18} />}
          validate={(value) => {
            if (!value) {
              return 'Please enter your email address';
            }
 
            if (!validators.email(value)) {
              return 'Please enter a valid email address';
            }
          }}
          isRequired
        />
        <TextField
          id="password"
          name="password"
          label="Password"
          type="password"
          icon={<RiLockPasswordLine size={18} />}
          autoComplete="current-password"
          validate={(value) => {
            if (!value) {
              return 'Please enter your password';
            }
          }}
          isRequired
        />
        <Checkbox
          id="rememberMe"
          name="rememberMe"
          label="Remember me for 30 days"
        />
        <Button type="submit" loading={form.isPending}>
          Sign in
        </Button>
      </Form>
    </FormRoot>
  );
};