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 it with npx shadcn@latest add @cruiseui/cruise-auth-card.
Install
Terminal
npx shadcn@latest add @cruiseui/cruise-auth-cardFirst time? Installation shows the one-off components.json setup (the @cruiseui registry) and how to turn the theme on.
Example
Corners
Log in
New here? Create an account
"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>
);
}
When to use it
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).
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().