# Auth

> Five full sign-in and sign-up screens: a split page with an auto-playing product story, a centered card, a passwordless magic-code flow, a wide landscape card and a sign-up with SSO and a strength meter. Forms validate, swap states with blur crossfades and spring between steps.

- Collection: Pages
- Tier: pro
- Docs: https://geturui.com/docs/auth-pages
- Install: `npx shadcn@latest add @geturui-pro/auth-pages`
- Dependencies: motion, lucide-react

## Variants

### Split showcase

Sign-in form on the left; on wide containers an auto-playing product story with springing bars and progress dots on the right.

Install: `npx shadcn@latest add @geturui-pro/auth-pages-split-showcase`

```tsx
import { SplitShowcase } from "@/components/pages/auth-pages/split-showcase";

export default function SignInPage() {
  return (
    <SplitShowcase
      productName="Kestrel"
      onSubmit={async ({ email, password, remember }) => {
        await signIn({ email, password, remember });
      }}
      onForgotPassword={() => router.push("/reset")}
      onSignUp={() => router.push("/sign-up")}
    />
  );
}
```

| Prop | Type | Default | Description |
|---|---|---|---|
| productName | `string` | "Kestrel" | Shown in the logo lockup and copy. |
| heading | `string` | "Welcome back" | Form heading. |
| subheading | `string` | — | Line under the heading. |
| onSubmit | `(values: { email; password; remember }) => void | Promise<void>` | — | Runs after validation. Throw an Error to show its message above the form. |
| onForgotPassword | `() => void` | — | Forgot-password link handler. |
| onSignUp | `() => void` | — | Create-account link handler. |
| stories | `ShowcaseStory[]` | — | { metric, value, title, body, bars } slides for the story panel. |
| interval | `number` | 5200 | Milliseconds per slide. Autoplay pauses on hover/focus and under reduced motion. |
| className | `string` | — | Classes for the outer container. |

### Centered card

One card on a masked grid with a breathing glow; a gliding sign-in / create-account switch springs the name field open and resizes the card.

Install: `npx shadcn@latest add @geturui-pro/auth-pages-centered-card`

```tsx
import { CenteredCard } from "@/components/pages/auth-pages/centered-card";

export default function AuthPage() {
  return (
    <CenteredCard
      defaultMode="sign-up"
      onSubmit={async ({ mode, name, email, password }) => {
        if (mode === "sign-up") await createAccount({ name, email, password });
        else await signIn({ email, password });
      }}
      onProvider={(provider) => signInWith(provider)}
    />
  );
}
```

| Prop | Type | Default | Description |
|---|---|---|---|
| productName | `string` | "Kestrel" | Used in headings and the monogram. |
| defaultMode | `"sign-in" | "sign-up"` | "sign-in" | Tab shown first. |
| onSubmit | `(values: { mode; name?; email; password }) => void | Promise<void>` | — | Runs after validation. Throw to show an error. |
| onProvider | `(provider: "google" | "github") => void | Promise<void>` | — | Provider button handler. |
| onForgotPassword | `() => void` | — | Forgot-password handler (sign-in mode). |
| termsHref | `string` | "#terms" | Terms link. |
| privacyHref | `string` | "#privacy" | Privacy link. |
| className | `string` | — | Classes for the outer container. |

### Magic code

Passwordless flow: email, then a six-digit OTP field with a resend countdown, then success, while a shape-built envelope opens and a letter rises.

Install: `npx shadcn@latest add @geturui-pro/auth-pages-magic-code`

```tsx
import { MagicCode } from "@/components/pages/auth-pages/magic-code";

export default function MagicSignIn() {
  return (
    <MagicCode
      onSendCode={(email) => sendCode(email)}
      onVerify={async (email, code) => (await verifyCode(email, code)).ok}
      onContinue={() => router.push("/app")}
    />
  );
}
```

| Prop | Type | Default | Description |
|---|---|---|---|
| productName | `string` | "Kestrel" | Header and success button label. |
| onSendCode | `(email: string) => void | Promise<void>` | — | Sends the code. Throw to show an error. |
| onVerify | `(email: string, code: string) => boolean | Promise<boolean>` | — | Return true to sign in, false to shake and clear. Defaults to accepting any code except all zeros. |
| onContinue | `(email: string) => void` | — | Success-screen button handler. |
| resendAfter | `number` | 30 | Seconds before resend unlocks. |
| codeLength | `number` | 6 | Number of code digits. |
| className | `string` | — | Classes for the outer container. |

### Landscape card

Wide card with a landscape drawn from circles and rounded shapes (sun, drifting clouds, swaying trees) beside a form with a passkey option and stay-signed-in switch.

Install: `npx shadcn@latest add @geturui-pro/auth-pages-landscape-card`

```tsx
import { LandscapeCard } from "@/components/pages/auth-pages/landscape-card";

export default function SignIn() {
  return (
    <LandscapeCard
      onSubmit={({ email, password, staySignedIn }) => signIn({ email, password, staySignedIn })}
      onPasskey={() => signInWithPasskey()}
    />
  );
}
```

| Prop | Type | Default | Description |
|---|---|---|---|
| productName | `string` | "Kestrel" | Brand chip over the illustration. |
| heading | `string` | "Sign in to Kestrel" | Form heading. |
| subheading | `string` | — | Line under the heading. |
| caption | `string` | — | Large caption over the illustration on wide containers. |
| onSubmit | `(values: { email; password; staySignedIn }) => void | Promise<void>` | — | Runs after validation. Throw to show an error. |
| onPasskey | `() => void | Promise<void>` | — | Passkey button handler. |
| onForgotPassword | `() => void` | — | Reset-password handler. |
| onSignUp | `() => void` | — | Trial link handler. |
| className | `string` | — | Classes for the outer container. |

### Atlas split

Sign-up with a topographic map panel whose contour lines draw in, a row of SSO buttons and a password field with a four-segment strength meter and live rule checklist.

Install: `npx shadcn@latest add @geturui-pro/auth-pages-atlas-split`

```tsx
import { AtlasSplit } from "@/components/pages/auth-pages/atlas-split";

export default function SignUp() {
  return (
    <AtlasSplit
      providers={["google", "microsoft", "saml"]}
      onProvider={(p) => startSso(p)}
      onSubmit={({ name, email, password }) => createAccount({ name, email, password })}
    />
  );
}
```

| Prop | Type | Default | Description |
|---|---|---|---|
| productName | `string` | "Kestrel" | Logo lockup on the map panel. |
| heading | `string` | "Create your workspace" | Form heading. |
| subheading | `string` | — | Line under the heading. |
| quote | `{ body; name; role }` | — | Testimonial on the map panel. |
| providers | `("google" | "microsoft" | "github" | "saml")[]` | all four | SSO buttons, in order. |
| onSubmit | `(values: { name; email; password }) => void | Promise<void>` | — | Runs once fields are valid, the password meets 3 of 4 rules and terms are accepted. |
| onProvider | `(provider) => void | Promise<void>` | — | SSO button handler. |
| onSignIn | `() => void` | — | Sign-in link handler. |
| className | `string` | — | Classes for the outer container. |

## Accessibility

- Every field has a visible label; errors are tied to fields with aria-describedby and focus moves to the first invalid field on submit.
- Show-password, mode switches and story dots are real buttons with aria-pressed or tab semantics and arrow-key support.
- Step and state changes are announced through role=status regions; large motion falls back to fades under reduced motion.

## Source

Pro item — send `Authorization: Bearer <registry token>` to include the source.
