# Auth card

Auth card is a ready-made neobrutalist section (block) from Cruise UI, built from its components. An auth card block with variants login (email or phone), signup, forgot-password and verify-otp (OTP with a resend countdown). Inline field errors, a show-password toggle and optional Google / Apple buttons; typed onSubmit per variant, no auth logic.

Install (with the @cruiseui registry in components.json, see Installation):

```bash
npx shadcn@latest add @cruiseui/cruise-auth-card
```

Import: `import { CruiseAuthCard } from "@/components/cruise/blocks/auth-card";`

## When to use

Login, sign-up, password reset and one-time-code screens.

## When not to

Collecting payment details (use your payment provider's own form).

## Example (React)

```tsx
"use client";

import { useState } from "react";
import { CruiseAuthCard, type CruiseAuthVariant } from "@/components/cruise/blocks/auth-card";
import { CruiseToggleButtonGroup } from "@/components/cruise/toggle-button-group";

export default function AuthCardExample() {
  const [variant, setVariant] = useState<CruiseAuthVariant>("login");
  return (
    <div className="flex flex-col gap-6">
      <CruiseToggleButtonGroup<CruiseAuthVariant>
        label="Auth card variant"
        value={variant}
        onChange={setVariant}
        options={[
          { value: "login", label: "Log in" },
          { value: "signup", label: "Sign up" },
          { value: "forgot-password", label: "Forgot" },
          { value: "verify-otp", label: "OTP" },
        ]}
      />
      {variant === "login" && <CruiseAuthCard variant="login" headingLevel={2} phoneLogin social={["google", "apple"]} onSubmit={(v) => console.log(v)} />}
      {variant === "signup" && <CruiseAuthCard variant="signup" headingLevel={2} social={["google"]} onSubmit={(v) => console.log(v)} />}
      {variant === "forgot-password" && <CruiseAuthCard variant="forgot-password" headingLevel={2} onSubmit={(v) => console.log(v)} />}
      {variant === "verify-otp" && <CruiseAuthCard variant="verify-otp" headingLevel={2} sentTo="0801 234 5678" onSubmit={(v) => console.log(v)} />}
    </div>
  );
}
```

## Props: CruiseAuthCard

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `title?` | `ReactNode` | — | Heading text; each variant has a default. |
| `description?` | `ReactNode` | — | Line under the heading. |
| `error?` | `ReactNode` | — | An error from your server (wrong password, expired code…), shown as an Alert. |
| `pending?` | `boolean` | — | Disables the submit button while you're waiting on your API. |
| `social?` | `("google" \| "apple")[]` | — | "Continue with Google / Apple" buttons (login and signup); onSocial gets the provider. |
| `onSocial?` | `((provider: "google" \| "apple") => void)` | — | — |
| `links?` | `{ forgotPassword?: string \| undefined; signup?: string \| undefined; login?: string \| undefined; terms?: string \| undefined; }` | — | Links under the form. |
| `headingLevel?` | `2 \| 1` | — | Heading level: 1 on an auth page, 2 inside a page. |
| `className?` | `string` | — | — |
| `variant` | `"login" \| "signup" \| "forgot-password" \| "verify-otp"` | — | — |
| `onSubmit?` | `((values: { method: "email" \| "phone"; email?: string \| undefined; phone?: string \| undefined; password: string; remember: boolean; }) => void) \| ((values: { name: string; email: string; password: string; acceptTerms: boolean; }) => void) \| ((values: { email: string; }) => void) \| ((values: { code: string; }) => void)` | — | — |
| `phoneLogin?` | `boolean` | — | — |
| `sentTo?` | `string` | — | Where the code went, e.g. "0801 234 5678" or "ada@example.com". |
| `length?` | `4 \| 6` | — | — |
| `resendAfter?` | `number` | — | — |
| `onResend?` | `(() => void)` | — | — |

## Accessibility

- Every field has a label; errors are linked with aria-describedby and shown in words with an icon.
- The show-password button says Show / Hide password and uses aria-pressed.
- Server errors appear in a danger Alert, never alert().
