Login Form

Clean sign-in form with email, password, remember-me checkbox, and inline validation. Built with react-hook-form and Zod for type-safe schema validation — errors appear instantly on blur.

Welcome back

Sign in to your account to continue

No account? Create one

import { LoginForm } from "@aetherstack/patterns"

Installation

terminal
pnpm add react-hook-form zod @hookform/resolvers

Import

import.tsx
import { useForm } from "react-hook-form"
import { zodResolver } from "@hookform/resolvers/zod"
import { z } from "zod"
import { Button, Input, Label, Checkbox } from "@aetherstack/ui"
import { toast } from "@aetherstack/ui"

Usage

login-form.tsx
const schema = z.object({
  email: z.string().email("Enter a valid email address"),
  password: z.string().min(8, "Password must be at least 8 characters"),
  remember: z.boolean().optional(),
})

type FormValues = z.infer<typeof schema>

export function LoginForm() {
  const {
    register,
    handleSubmit,
    formState: { errors, isSubmitting },
  } = useForm<FormValues>({
    resolver: zodResolver(schema),
  })

  async function onSubmit(data: FormValues) {
    await signIn(data.email, data.password)
    toast({ variant: "success", title: "Signed in", description: `Welcome back, ${data.email}` })
  }

  return (
    <form onSubmit={handleSubmit(onSubmit)} className="space-y-4" noValidate>
      <div className="space-y-1.5">
        <Label htmlFor="email">Email</Label>
        <Input id="email" type="email" placeholder="you@example.com" {...register("email")} />
        {errors.email && <p className="text-xs text-destructive">{errors.email.message}</p>}
      </div>

      <div className="space-y-1.5">
        <Label htmlFor="password">Password</Label>
        <Input id="password" type="password" placeholder="••••••••" {...register("password")} />
        {errors.password && <p className="text-xs text-destructive">{errors.password.message}</p>}
      </div>

      <div className="flex items-center gap-2">
        <Checkbox id="remember" {...register("remember")} />
        <Label htmlFor="remember" className="font-normal">Remember me</Label>
      </div>

      <Button type="submit" className="w-full" disabled={isSubmitting}>
        {isSubmitting ? "Signing in…" : "Sign in"}
      </Button>
    </form>
  )
}

Props

PropTypeDefaultDescription
schemaZodObjectZod validation schema. Email must be a valid address; password requires minimum 8 characters.
registerUseFormRegister<FormValues>react-hook-form register function — wires native inputs to the form state.
handleSubmit(handler) => FormEventHandlerWraps your submit handler to run validation first and only call your function when the form is valid.
errorsFieldErrors<FormValues>Validation error messages keyed by field name, displayed as red helper text beneath each input.
isSubmittingbooleanTrue while the submit handler is pending. Used to disable the submit button and show a loading label.

* Required

Accessibility

  • All inputs have explicit <Label> elements connected via htmlFor/id pairs.
  • aria-invalid is set on inputs that have validation errors.
  • Error messages are rendered in <p> elements adjacent to the field — screen readers read them in context.
  • The submit button is disabled while submitting to prevent duplicate submissions.
  • noValidate on the form disables native browser validation so custom messages are always shown.