PocketBase login page for React

The spotlight lamp login on PocketBase's authWithPassword. It shows a clear message for a wrong password, sets a cookie your middleware can read, and avoids the duplicate-request cancel that trips up React apps.

Spotlight Lamp Login, preview
One payment$3

By buying you agree to the Terms.

Ready forCursorv0Lovableshadcn CLI

Full product pageReact · Tailwind · TypeScript

Use it in Next.js

app/login/page.tsx

"use client";
import { useRouter } from "next/navigation";
import { ClientResponseError } from "pocketbase";
import SpotlightLampLogin from "@/components/SpotlightLampLogin";
import { pb } from "@/lib/pocketbase";

export default function LoginPage() {
  const router = useRouter();

  return (
    <div className="h-dvh">
      <SpotlightLampLogin
        autoplayDemo={false}
        onSignIn={async (email, password) => {
          try {
            // requestKey: null stops the SDK from cancelling a repeat call (React Strict Mode, double submits).
            await pb.collection("users").authWithPassword(email, password, { requestKey: null });
            // A readable cookie so middleware and server components can see the login.
            document.cookie = pb.authStore.exportToCookie({ httpOnly: false });
            return { ok: true };
          } catch (err) {
            if (err instanceof ClientResponseError && err.status === 400) {
              return { ok: false, message: "That email and password don't match." };
            }
            return { ok: false, message: "Can't reach the server right now. Try again." };
          }
        }}
        onSuccess={() => router.push("/dashboard")}
      />
    </div>
  );
}

lib/pocketbase.ts

import PocketBase from "pocketbase";

// One client for the browser. On the server, make a new PocketBase() per request instead.
export const pb = new PocketBase(process.env.NEXT_PUBLIC_POCKETBASE_URL);

middleware.ts

import { NextResponse, type NextRequest } from "next/server";
import PocketBase from "pocketbase";

export function middleware(request: NextRequest) {
  const pb = new PocketBase(process.env.NEXT_PUBLIC_POCKETBASE_URL);
  pb.authStore.loadFromCookie(request.headers.get("cookie") ?? "");
  // isValid only checks that the token hasn't expired. Your collection API rules still guard the data.
  if (!pb.authStore.isValid) {
    return NextResponse.redirect(new URL("/login", request.url));
  }
  return NextResponse.next();
}

export const config = { matcher: ["/dashboard/:path*"] };

Good to know

  • PocketBase answers a wrong email or password with a 400. The snippet turns that into a message the lamp shows under the password field. Anything else, like the server being down, gets a different line.
  • The SDK cancels a request when an identical one is still pending. React Strict Mode and quick double clicks both trigger that, so the snippet passes requestKey: null.
  • exportToCookie defaults to httpOnly, which a browser can't set from JavaScript. httpOnly: false lets the cookie land so middleware can read it. If you need httpOnly, sign in through a route handler instead.
  • The lamp is a full-screen scene. Give it a parent with a real height (h-dvh above), or it has nothing to fill.
  • We type-checked the snippets against pocketbase 0.28 and Next.js 15. Plain React with Vite works too: keep the onSignIn part and skip the cookie and middleware.

Install

  1. Copy from the zipPut react/src/components + react/src/data into src/, then npm i framer-motion pocketbase.
  2. Or ask your AIPaste PROMPT.md into Cursor, Lovable or v0.

Props

onSignIn
(email, password) → { ok, message? }
onSuccess
runs after the light floods the screen
autoplayDemo
false for a real page
data
names shown after sign-in

How qodesign compares

All comparisons, with prices read on each library's own site.

Questions

Does it work with a username instead of an email?

Yes, if your users collection allows username as an identity field. authWithPassword takes either. The lamp's first field still checks for an email format, though, so change that check in the component.

How do I sign out?

Call pb.authStore.clear() and clear the pb_auth cookie, then send them back to /login.

Can I sign in admins with it?

Use pb.collection("_superusers") instead of users. Most apps keep admin sign-in on PocketBase's own dashboard, though.

Can Cursor or v0 add it for me?

Yes. Each download has a PROMPT.md. Paste it into Cursor, Lovable, v0 or Claude Code and it fits the piece into your app.

Can I use it in client work?

Yes, in personal and client projects. You can't resell the code itself as a kit.