A TunnelBear-style login for React

The login where a character watches you type and covers its eyes for the password, as a finished React component with its own mascot, so you aren't shipping someone else's bear.

Shy Eyes 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 ShyEyesLogin from "@/components/ShyEyesLogin";
import { signInWithPassword } from "./actions";

export default function LoginPage() {
  const router = useRouter();
  return (
    <main className="grid min-h-dvh place-items-center p-4">
      <ShyEyesLogin
        title="Welcome back"
        // resolve false (or throw) and he shakes his head, then signInError shows
        onSubmit={async (email, password) => {
          const ok = await signInWithPassword(email, password);
          if (ok) setTimeout(() => router.push("/dashboard"), 900); // let the jump and wave play
          return ok;
        }}
        signInError="That email and password don't match."
      />
    </main>
  );
}

app/login/actions.ts

"use server";

// Call the auth you already use here: Supabase, Auth.js, Clerk, Firebase or your own API.
// Return true when the password is right. Set the session cookie before you return.
export async function signInWithPassword(email: string, password: string): Promise<boolean> {
  const res = await fetch(`${process.env.AUTH_API_URL}/login`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ email, password }),
    cache: "no-store",
  });
  return res.ok;
}

Good to know

  • TunnelBear's bear is their brand's own artwork. The well-known open source repro (addyosmani/tunnel-bear-login) plays image sequences of that bear, which makes it a nice project to learn from rather than art you can put in your own product.
  • The Rive teddy login is a .riv file played by Rive's runtime. If you want that exact bear, Rive is the right tool: load the file with @rive-app/react-canvas and drive its state machine from your inputs' focus and change events. Check the licence of the community file you pick.
  • Shy Eyes Login is drawn with HTML and CSS and moved with Framer Motion, so there's no runtime or asset file to load. His eyes follow the pointer and the caret in the email field, he covers his eyes for the password and peeks through his fingers when the visitor shows it.
  • A wrong password (onSubmit resolves false or throws) gets a head shake and signInError under the form. A right one gets a jump and a wave. The head shake is skipped when the visitor has Reduce Motion on.
  • The actions.ts above is a placeholder for your own auth. For ready wiring, see the Auth.js credentials, Convex Auth and Supabase login guides.

Install

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

Props

onSubmit
email + password; resolve false or throw for a wrong password
signInError
message after a failed sign-in
error
an error you control, e.g. from the URL
bodyColors / handColors
the mascot's colours

How qodesign compares

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

Questions

Is the mascot a bear?

No. He's qodesign's own round character with an antenna. bodyColors, handColors and antennaColor change how he looks, and every label is a prop.

Does it need Rive or Lottie?

No. It's one React component with a CSS file next to it. The only package it adds is framer-motion.

Does the login work in Next.js?

Yes, as a client component. Keep "use client" at the top of the file that renders it, as in the snippet above. App Router and Pages Router both work.

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.