Skip to content
oks-ui

Auth

Forgot password

The password-reset request step: an icon badge, one email field, and a clear primary action on a light panel, next to a dark canvas carrying a customer testimonial. Kept deliberately minimal on the form side so it reads as a focused, low-friction step.

forgot-password.tsx

How it's built

1

One field, one action — resist adding anything that competes with the primary task.

2

The testimonial panel is original, hand-written copy and an initials avatar, not a photo of a real person or a real customer quote — safe placeholder content for a pattern meant to be copy-pasted and re-branded.

3

Same split rule as the other Auth patterns: real oks-ui components (the form) live on a plain light panel; the dark canvas carries only text we colour ourselves, since oks-ui's dark theme needs `data-theme="dark"` on the document root to activate, not just a dark backdrop.

4

"Back to log in" is a real `Button variant="link"` with `startContent` for the arrow icon — not a raw anchor. Passing `href` (with no `type`) makes `Button` render as an `<a>` automatically.

5

"Forgot password?" is a real `PageTitle` (safe to use its default styling here, since this panel is genuinely light and theme-driven); the shield icon badge above it and the "MK" initials avatar on the dark testimonial canvas are both real `Avatar` components too — the badge is `isBordered`-free, using a plain `classNames={{ base: "border border-line bg-transparent" }}` override for a simple outlined square instead of oks-ui's own multi-ring bordered style.

Source

One file · copy & paste
forgot-password.tsx
import { Avatar } from "oks-ui/avatar";
import { Button } from "oks-ui/button";
import { Form, FormFieldSet } from "oks-ui/form-field-set";
import { PageTitle } from "oks-ui/page-title";
import { ShieldIcon } from "../../showcase/icons";

function ArrowLeftIcon({ size = 16 }: { size?: number }) {
  return (
    <svg width={size} height={size} viewBox="0 0 16 16" fill="none" aria-hidden="true">
      <path
        d="M13 8H3M3 8l4-4M3 8l4 4"
        stroke="currentColor"
        strokeWidth="1.6"
        strokeLinecap="round"
        strokeLinejoin="round"
      />
    </svg>
  );
}

export function ForgotPassword() {
  return (
    <div className="@container w-full bg-paper-raised">
      <div className="grid @2xl:min-h-[560px] @2xl:grid-cols-2">
        {/* form panel */}
        <div className="flex flex-col justify-center p-8 @2xl:p-14">
          <div className="mx-auto flex w-full max-w-sm flex-col gap-6">
            <span className="text-sm font-bold uppercase tracking-[0.2em] text-ink-faint">
              Brand
            </span>

            <div className="flex flex-col gap-5">
              <Avatar
                icon={<ShieldIcon size={20} />}
                radius="md"
                size="lg"
                classNames={{ base: "border border-line bg-transparent", icon: "text-accent" }}
              />
              <PageTitle
                as="h1"
                title="Forgot password?"
                subtitle="No worries, we'll send you reset instructions."
                classNames={{
                  base: "flex-col items-start",
                  title: "text-[1.6rem] font-bold tracking-tight text-ink",
                  subtitle: "mt-1.5 text-[0.9rem] text-ink-muted",
                }}
              />
            </div>

            <Form onSubmit={(data) => console.log(data)} className="flex flex-col gap-4">
              <FormFieldSet
                type="email"
                name="email"
                label="Email"
                placeholder="Enter your email"
                validation={{ rules: { required: true, email: true } }}
              />
              <Button type="submit" color="primary" fullWidth>
                Reset password
              </Button>
            </Form>

            <Button
              href="/sign-in"
              variant="link"
              size="sm"
              startContent={<ArrowLeftIcon />}
              className="h-auto justify-center p-0 text-[0.85rem] font-medium text-ink-muted no-underline"
            >
              Back to log in
            </Button>
          </div>
        </div>

        {/* testimonial panel — original copy, no photo of a real person */}
        <div className="relative hidden flex-col overflow-hidden bg-[#04151a] p-12 @2xl:flex">
          <div
            aria-hidden="true"
            className="absolute inset-0"
            style={{
              background:
                "radial-gradient(120% 90% at 85% 15%, color-mix(in oklab, #0891b2 45%, transparent) 0%, transparent 55%), " +
                "radial-gradient(90% 70% at 10% 90%, color-mix(in oklab, #0f766e 45%, transparent) 0%, transparent 60%), " +
                "linear-gradient(160deg, #04151a 0%, #04262b 55%, #062f2c 100%)",
            }}
          />
          <div
            aria-hidden="true"
            className="absolute -right-20 top-1/4 h-72 w-72 rounded-full opacity-30 blur-3xl"
            style={{ background: "#22d3ee" }}
          />

          <div className="relative z-10 flex h-full flex-col justify-center gap-6">
            <span className="text-[3rem] font-serif leading-none text-white/25" aria-hidden="true">
              &ldquo;
            </span>
            <p className="max-w-md text-[1.5rem] font-medium leading-snug tracking-tight text-white">
              We cut our onboarding time in half within the first month —
              support tickets dropped right along with it.
            </p>
            <div className="mt-2 flex items-center gap-3">
              <Avatar
                name="Maya Kessler"
                radius="full"
                classNames={{ base: "bg-white/10", name: "text-white" }}
              />
              <div>
                <p className="text-sm font-semibold text-white">Maya Kessler</p>
                <p className="text-[0.8rem] text-white/60">
                  Head of Ops, Northwind Labs
                </p>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

More patterns

Auth
Sign-in screenA split-screen sign-in with a feature panel, Google SSO, and remember-me.
Auth
Sign-up screenA dark canvas with a feature pitch, SSO row, and a real registration form.
Auth
OTP verificationFour large circular code boxes with a live resend countdown.