# Auth Card Social — React Auth Screen

> A centred sign-in card with generic provider buttons that show their own loading state, and an email step that unfolds a password field once the address is valid.

- Category: [Auth Screens](https://pixelpapa.com/components/auth.md)
- Tags: auth, sign-in, card, social, providers
- Dependencies: lucide-react, motion (plus React and Tailwind CSS v4)
- Last updated: 2026-11-13
- Live preview: https://pixelpapa.com/components/auth/auth-card-social

## Install

```bash
npx shadcn@latest add "https://pixelpapa.com/r/auth-card-social.json"
```

The file is written to `components/pixelpapa/auth-card-social.tsx`. To install manually, run `npm install lucide-react motion` and copy the source below into your project. It imports `cn` from `@/lib/utils`, which every shadcn project has.

## Source

```tsx
"use client";

import { ArrowRight, KeyRound, LoaderCircle } from "lucide-react";
import { AnimatePresence, motion } from "motion/react";
import { useEffect, useRef, useState, type ReactNode } from "react";

type Provider = { id: string; label: string; glyph: ReactNode; lastUsed?: boolean };

// Generic marks, deliberately not any real company's logo.
const providers: Provider[] = [
  {
    id: "prism",
    label: "Continue with Prism",
    lastUsed: true,
    glyph: (
      <svg viewBox="0 0 20 20" className="size-[18px]" aria-hidden>
        <path d="M10 2 18 16H2Z" fill="var(--chart-1)" />
        <path d="M10 2 14 9 6 9Z" fill="var(--chart-2)" />
        <path d="M6 9h8l4 7H2Z" fill="var(--chart-3)" fillOpacity="0.85" />
      </svg>
    ),
  },
  {
    id: "orbit",
    label: "Continue with Orbit",
    glyph: (
      <svg viewBox="0 0 20 20" className="size-[18px]" fill="none" aria-hidden>
        <circle cx="10" cy="10" r="4" fill="var(--chart-4)" />
        <ellipse cx="10" cy="10" rx="8.5" ry="3.6" stroke="currentColor" strokeWidth="1.5" transform="rotate(-28 10 10)" />
      </svg>
    ),
  },
  { id: "passkey", label: "Use a passkey", glyph: <KeyRound className="size-[18px]" /> },
];

export default function AuthCardSocial() {
  const [pending, setPending] = useState<string | null>(null);
  const [email, setEmail] = useState("");
  const timer = useRef<ReturnType<typeof setTimeout> | null>(null);
  const valid = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/.test(email);

  useEffect(() => () => void (timer.current && clearTimeout(timer.current)), []);

  function simulate(id: string) {
    if (pending) return;
    setPending(id);
    timer.current = setTimeout(() => setPending(null), 1600);
  }

  return (
    <section className="relative flex min-h-screen w-full items-center justify-center overflow-hidden bg-background px-6 py-16">
      <div
        aria-hidden
        className="absolute inset-0 [background-image:radial-gradient(var(--border)_1.2px,transparent_1.2px)] [background-size:22px_22px] [mask-image:radial-gradient(50%_50%_at_50%_50%,black,transparent)]"
      />
      <div aria-hidden className="absolute top-1/2 left-1/2 size-[520px] -translate-x-1/2 -translate-y-1/2 rounded-full bg-primary/10 blur-[100px]" />

      <motion.div
        initial={{ opacity: 0, y: 24, scale: 0.97 }}
        animate={{ opacity: 1, y: 0, scale: 1 }}
        transition={{ type: "spring", stiffness: 160, damping: 20 }}
        className="relative w-full max-w-[25rem] rounded-3xl border border-border bg-card p-8 shadow-2xl shadow-primary/10"
      >
        <div className="flex size-11 items-center justify-center rounded-2xl bg-foreground text-background">
          <svg viewBox="0 0 24 24" className="size-5" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" aria-hidden>
            <path d="M5 17c3-9 11-9 14 0M8 17c2-5 6-5 8 0" />
          </svg>
        </div>
        <h1 className="mt-5 text-2xl font-semibold tracking-tight text-card-foreground">Sign in to Archway</h1>
        <p className="mt-1.5 text-sm text-muted-foreground">Pick up your drafts on any device.</p>

        <motion.div initial="hidden" animate="shown" transition={{ staggerChildren: 0.07, delayChildren: 0.2 }} className="mt-7 space-y-2.5">
          {providers.map((p) => (
            <motion.button
              key={p.id}
              type="button"
              variants={{ hidden: { opacity: 0, x: -12 }, shown: { opacity: 1, x: 0 } }}
              whileTap={{ scale: 0.98 }}
              onClick={() => simulate(p.id)}
              disabled={pending !== null && pending !== p.id}
              className="relative flex h-11 w-full items-center justify-center gap-2.5 rounded-xl border border-border bg-background text-sm font-medium text-foreground transition-colors hover:bg-muted disabled:opacity-50"
            >
              <span className="flex size-5 items-center justify-center">
                {pending === p.id ? <LoaderCircle className="size-4 animate-spin text-muted-foreground" /> : p.glyph}
              </span>
              {pending === p.id ? "Connecting…" : p.label}
              {p.lastUsed && (
                <span className="absolute -top-2 right-3 rounded-full border border-border bg-card px-1.5 py-px text-[10px] font-medium text-muted-foreground">
                  Last used
                </span>
              )}
            </motion.button>
          ))}
        </motion.div>

        <div className="my-6 flex items-center gap-3 text-xs text-muted-foreground">
          <span className="h-px flex-1 bg-border" /> or with email <span className="h-px flex-1 bg-border" />
        </div>

        <form onSubmit={(e) => (e.preventDefault(), simulate("email"))}>
          <label htmlFor="auth-card-social-email" className="sr-only">
            Email address
          </label>
          <input
            id="auth-card-social-email"
            type="email"
            value={email}
            onChange={(e) => setEmail(e.target.value)}
            placeholder="you@example.com"
            autoComplete="email"
            className="h-11 w-full rounded-xl border border-input bg-background px-3.5 text-sm text-foreground outline-none transition-shadow placeholder:text-muted-foreground focus:border-primary focus:ring-4 focus:ring-primary/15"
          />
          <AnimatePresence initial={false}>
            {valid && (
              <motion.div
                initial={{ height: 0, opacity: 0 }}
                animate={{ height: "auto", opacity: 1 }}
                exit={{ height: 0, opacity: 0 }}
                transition={{ type: "spring", stiffness: 300, damping: 30 }}
                className="overflow-hidden"
              >
                <label htmlFor="auth-card-social-password" className="sr-only">
                  Password
                </label>
                <input
                  id="auth-card-social-password"
                  type="password"
                  placeholder="Password"
                  autoComplete="current-password"
                  className="mt-2.5 h-11 w-full rounded-xl border border-input bg-background px-3.5 text-sm text-foreground outline-none transition-shadow placeholder:text-muted-foreground focus:border-primary focus:ring-4 focus:ring-primary/15"
                />
              </motion.div>
            )}
          </AnimatePresence>
          <button
            type="submit"
            disabled={!valid || pending !== null}
            className="group mt-3 flex h-11 w-full items-center justify-center gap-2 rounded-xl bg-primary text-sm font-medium text-primary-foreground shadow-lg shadow-primary/25 transition-opacity disabled:opacity-50 disabled:shadow-none"
          >
            {pending === "email" ? (
              <LoaderCircle className="size-4 animate-spin" />
            ) : (
              <>
                Continue <ArrowRight className="size-4 transition-transform group-hover:translate-x-0.5" />
              </>
            )}
          </button>
        </form>

        <p className="mt-6 text-center text-xs leading-relaxed text-muted-foreground">
          No account yet? <a href="#" className="font-medium text-foreground underline underline-offset-2">Create one</a>. By continuing you agree to
          the <a href="#" className="underline underline-offset-2">terms</a>.
        </p>
      </motion.div>
    </section>
  );
}
```

## AI prompt

```text
Add the "Auth Card Social" component from PixelPapa UI to this project.

What it is: A centred sign-in card with generic provider buttons that show their own loading state, and an email step that unfolds a password field once the address is valid.
Category: Auth Screens. Depends on: lucide-react, motion.

1. Install it with the shadcn CLI:
   npx shadcn@latest add "https://pixelpapa.com/r/auth-card-social.json"
   (If the CLI is unavailable, fetch that URL, write files[0].content to components/pixelpapa/auth-card-social.tsx and install the listed dependencies.)
2. Import it from "@/components/pixelpapa/auth-card-social" and place it where I describe below.
3. Keep its animation timings and accessibility attributes. Replace the demo copy and data with content that fits my product, and use my existing theme tokens (bg-background, text-foreground, bg-primary, border-border) rather than hard-coded colours.

Where to use it: <describe the page and position here>
```

## More auth screens

- [Auth Magic Link Sent](https://pixelpapa.com/components/auth/auth-magic-link-sent.md): A check-your-inbox screen: an envelope opens and its letter lifts on a loop, a ring counts down to when resend unlocks, and the address can be changed in place.
- [Auth OTP Verify](https://pixelpapa.com/components/auth/auth-otp-verify.md) (Pro): A six-box verification screen with auto-advance, backspace, arrow keys and paste; digits pop in, a wrong code shakes and clears, the right one ripples green.
- [Auth Password Strength](https://pixelpapa.com/components/auth/auth-password-strength.md): A set-password screen with a four-segment meter that fills and recolours as you type, a requirements checklist that ticks off live and a one-click strong suggestion.
- [Auth Signup Steps](https://pixelpapa.com/components/auth/auth-signup-steps.md) (Pro): A three-step sign-up card with a filling progress rail, steps that slide in the direction of travel, a live workspace URL preview and a celebratory finish.
- [Auth Split Brand Panel](https://pixelpapa.com/components/auth/auth-split-brand-panel.md) (Pro): Sign-in form on one side and a brand panel on the other, where collaborators orbit a logo on slow rings and customer quotes rotate on a timer.
