# Login

A centered authentication card with email + social login.

- Category: Auth
- Interactive preview: https://aicronus.com/blocks/login

## Install

```bash
npx cronus-ui add login
```

Package dependencies: `@cronus-ui/ui@0.7.6`, `lucide-react@^0.577.0`.

Registry dependencies (installed automatically): `auth-adapter`.

## Variants

- Classic card (`classic`): Centered email and password card with social sign-in shortcuts.
- Split panel (`split`): Brand gradient panel with a customer testimonial beside the sign-in form.
- Social first (`social-first`): Google, GitHub, and Apple buttons stacked above the email fallback.
- Minimal (`minimal`): Ultra-clean logo mark, email, and continue button with quiet footer links.

## Source

The exact files the CLI installs.

### login.tsx

```tsx
"use client";

import {
  Button,
  Card,
  CardContent,
  CardFooter,
  CardHeader,
  CardTitle,
  Checkbox,
  Input,
  Label,
  Separator,
} from "@cronus-ui/ui";
import { signInEmail } from "../lib/auth-adapter.js";
import { ChartColumnIncreasing, Chrome, Github } from "lucide-react";
import { type FormEvent, useEffect, useState } from "react";

const INVITE_STORAGE_KEY = "cronus-invitation";

function readSignupInvitation(): boolean {
  if (typeof window === "undefined") return false;
  try {
    const fromUrl = new URLSearchParams(window.location.search).get("invitation");
    if (fromUrl) {
      sessionStorage.setItem(INVITE_STORAGE_KEY, fromUrl);
      return true;
    }
    return Boolean(sessionStorage.getItem(INVITE_STORAGE_KEY));
  } catch {
    return false;
  }
}

export function LoginBlock() {
  const [pending, setPending] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [joining, setJoining] = useState(false);
  useEffect(() => {
    setJoining(readSignupInvitation());
  }, []);

  async function onSubmit(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
    const form = new FormData(event.currentTarget);
    const email = String(form.get("email") ?? "");
    const password = String(form.get("password") ?? "");
    setError(null);
    setPending(true);
    try {
      await signInEmail({ email, password });
    } catch (err) {
      setError(err instanceof Error ? err.message : "Something went wrong.");
    } finally {
      setPending(false);
    }
  }

  return (
    <div className="flex w-full items-center justify-center py-4">
      <Card className="w-full max-w-sm gap-6 shadow-lg">
        <CardHeader className="flex flex-col items-center gap-3 text-center">
          <span className="inline-flex size-11 items-center justify-center rounded-xl bg-gradient-primary text-primary-foreground shadow-glow">
            <ChartColumnIncreasing className="size-5" aria-hidden="true" />
          </span>
          <div className="flex flex-col gap-1">
            <CardTitle className="font-display text-xl">
              {joining ? "Join the workspace" : "Welcome back"}
            </CardTitle>
            <p className="text-sm text-fg-secondary">
              {joining
                ? "Sign in to accept the invitation."
                : "Sign in to your Cronus workspace"}
            </p>
          </div>
        </CardHeader>

        <CardContent className="flex flex-col gap-4">
          <form onSubmit={onSubmit} className="flex flex-col gap-4" aria-busy={pending}>
            <div className="flex flex-col gap-2">
              <Label htmlFor="login-email">Email</Label>
              <Input
                id="login-email"
                name="email"
                type="email"
                placeholder="you@company.com"
                autoComplete="email"
              />
            </div>

            <div className="flex flex-col gap-2">
              <Label htmlFor="login-password">Password</Label>
              <Input
                id="login-password"
                name="password"
                type="password"
                placeholder="••••••••"
                autoComplete="current-password"
              />
            </div>

            <div className="flex items-center justify-between">
              <Label
                htmlFor="login-remember"
                className="flex items-center gap-2 font-normal text-fg-secondary"
              >
                <Checkbox id="login-remember" defaultChecked />
                Remember me
              </Label>
              <a
                href="/forgot-password"
                className="text-sm font-medium text-primary-strong underline-offset-4 hover:underline"
              >
                Forgot password?
              </a>
            </div>

            {error ? (
              <p role="alert" className="text-sm text-error-strong">
                {error}
              </p>
            ) : null}

            <Button
              type="submit"
              variant="primary"
              size="lg"
              className="w-full"
              disabled={pending}
              aria-busy={pending}
            >
              {pending
                ? joining
                  ? "Joining…"
                  : "Signing in…"
                : joining
                  ? "Join workspace"
                  : "Sign in"}
            </Button>
          </form>

          <div className="flex items-center gap-3">
            <Separator className="flex-1" />
            <span className="text-xs text-fg-tertiary">or continue with</span>
            <Separator className="flex-1" />
          </div>

          <div className="grid grid-cols-2 gap-3">
            <Button type="button" variant="outline">
              <Github className="size-4" aria-hidden="true" />
              GitHub
            </Button>
            <Button type="button" variant="outline">
              <Chrome className="size-4" aria-hidden="true" />
              Google
            </Button>
          </div>
        </CardContent>

        <CardFooter className="justify-center">
          <p className="text-sm text-fg-secondary">
            Don&apos;t have an account?{" "}
            <a
              href="/signup"
              className="font-medium text-primary-strong underline-offset-4 hover:underline"
            >
              Sign up
            </a>
          </p>
        </CardFooter>
      </Card>
    </div>
  );
}
```

---

Live preview: https://aicronus.com/blocks/login
