Centered email and password card with social sign-in shortcuts.
Install with the CLI, or add the packages and paste the source below.
Add Login to your app with its source-owned dependencies.
npx cronus-ui add login
Install the Cronus UI packages, then paste the block below.
Copy the source for Classic card. Every class is a semantic token, so it re-themes with your app.
"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><Inputid="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><Inputid="login-password"name="password"type="password"placeholder="••••••••"autoComplete="current-password"/></div><div className="flex items-center justify-between"><LabelhtmlFor="login-remember"className="flex items-center gap-2 font-normal text-fg-secondary"><Checkbox id="login-remember" defaultChecked />Remember me</Label><ahref="/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}<Buttontype="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" /></Button></div></CardContent><CardFooter className="justify-center"><p className="text-sm text-fg-secondary">Don't have an account?{" "}<ahref="/signup"className="font-medium text-primary-strong underline-offset-4 hover:underline">Sign up</a></p></CardFooter></Card></div>);}