Register Page React block for Tailwind CSS v4
v1.1.0Updated in 1.9.0
A React register page for a CRM sign-up: an account with password rules, company details from the CUI, an email code and a welcome step.
Sign up in up to three steps shown as bars above the form; completed bars are buttons that go back, and each change is announced ("Step 2 of 3: Company"). Account: "Sign up with Google" (Apple, Microsoft) spins on the pressed button and skips the email check; name, work email (a gmail, yahoo, outlook, hotmail or icloud address shows a warning to use the company address), a password with a strength meter and a rules checklist that opens on focus, the required terms checkbox with its links, the optional product news checkbox and Continue. Fields validate when you leave them and as you fix them; submitting empty shows every error and focuses the first. An email that already has an account (emma.carter@acme.com in the demo) shows a red alert with Sign in and Forgot password?. Company: type a CUI with or without RO and press Enter or Search; an invalid control digit is an error and never calls the lookup, the button spins while the ANAF lookup runs, a match fades in the name, the address and a VAT registered badge (Edit switches to manual fields), no match asks for manual entry and a failed lookup offers Try again and Fill in by hand. Pick a role (a bottom sheet on phones) and a team size, then Continue, or Skip. Verify: type or paste the 6 digit code and the sixth digit submits (123456 passes), a wrong code shakes the cells and shows an alert, Resend the code waits with a live countdown, Change the email goes back with the email selected. With verify link the step offers Open Gmail or Outlook for those domains and I confirmed my address. Done: a bouncy check, three next step rows and Open Acme CRM. Going back keeps what you typed. Steps slide in from the side they belong to and focus moves to the step title; on phones the form fills the screen with 48px fields and the hero is gone; with reduced motion steps cross-fade.
Register Page is a Pro React block in the React blocks category, written in TypeScript for React 19 and Tailwind CSS v4. It installs as source with npx wingo-ui@latest add register-page, together with Marketing Section, Alert, Badge, Button, Checkbox and 16 more and the npm packages motion, lucide-react, react-hook-form and zod.
Built with
The sections this page is made of. In the full-screen preview, hold Alt to outline each one on the page.
Add to a project
Requirements: React 19 and Tailwind CSS v4, in Next.js (App Router or Pages), Vite or React Router. Installation guide · Next.js setup · Vite setup
npx wingo-ui@latest add register-pageRegister Page is part of Pro, with 298 more Pro items: $8 a month or $150 once. 14-day refund before you download any Pro item. See plans
Usage
Import RegisterPage from @/components/blocks/register-page.
// app/(auth)/sign-up/page.tsx
"use client";
import { useRouter } from "next/navigation";
import { RegisterPage } from "@/components/blocks/register-page";
export default function Page() {
const router = useRouter();
return (
<RegisterPage
heroImage="/images/office.jpg"
onRegister={async (values) => {
const response = await fetch("/api/register", { method: "POST", body: JSON.stringify(values) });
if (response.status === 409) throw Object.assign(new Error("There is already an account with this email"), { code: "email-taken" });
if (!response.ok) throw new Error("We could not create the account");
}}
onLookupCui={async (cui) => {
const response = await fetch(`/api/anaf?cui=${cui}`);
return response.ok ? response.json() : null;
}}
onVerify={async (code) => {
const response = await fetch("/api/verify", { method: "POST", body: JSON.stringify({ code }) });
if (!response.ok) throw new Error("That code is not right");
}}
onDone={() => router.push("/")}
/>
);
}Props
defaultStepdefault"account"RegisterStepThe step shown first (uncontrolled); step / onStepChange control it. A step the flow does not have shows account.
stepRegisterStepThe current step, controlled: "account" | "company" | "verify" | "done".
onStepChange(step: RegisterStep) => voidRuns on every step change (mirror it to the URL or the router).
companyStepdefaulttruebooleanThe optional company step: CUI lookup, role and team size, with Skip.
verifydefault"code""code" | "link" | "none"code: a 6 digit code step; link: a check your email step with a confirm button; none: straight to done.
providersAuthProvider[]Social sign-up buttons, default REGISTER_PROVIDERS (Google, Apple, Microsoft); [] hides them and the divider.
showProvidersdefaulttruebooleanShortcut for providers={[]} when false.
plandefault"Pro · 14 days free, no card"ReactNodeThe badge above the account title (labels.plan by default); a node replaces the badge, null or an empty string hides it.
passwordMinLengthdefault8numberMinimum password length: the rule, the checklist and the strength meter.
passwordMinScoredefault2numberThe lowest scorePassword result (0 to 4) the password must reach; 0 accepts any password of the minimum length.
freeMailWarningdefaulttruebooleanA warning (not an error) under the email for gmail.com, yahoo.com, yahoo.ro, outlook.com, hotmail.com and icloud.com.
defaultValuesPartial<RegisterValues>Prefills every step (name, email, password, terms, marketing, company).
defaultCompanyCompanyLookup | nullA lookup result the company step opens with (name, address, vatPayer).
onRegister(values: RegisterValues) => (void | Promise<unknown>)After the account step: create the account and send the code. Default: simulated, rejects "There is already an account with this email" for emma.carter@acme.com; a rejection with that message or code "email-taken" shows the sign-in and password links.
onLookupCui(cui: string) => Promise<CompanyLookup | null>Looks up a valid CUI (normalized with formatCui). Default: the REGISTER_PAGE_SAMPLE.companies table (Tech Solutions SRL for RO12345674 and the other sample clients) after 900 ms; null asks for manual entry, a rejection offers a retry.
onCompany(company: RegisterCompany) => (void | Promise<unknown>)Saves the company step (name, cui, role, teamSize, address, vatPayer). Default: simulated.
onVerify(code: string) => (void | Promise<unknown>)Checks the 6 digit code. Default: 123456 passes, anything else rejects "That code is not right".
onResend() => (void | Promise<unknown>)Sends the code or the link again; the button then waits resendSeconds. Default: simulated.
onProvider(id: string) => (void | Promise<unknown>)Starts a social sign-up; the button spins until it settles, then the flow skips to the company step (or done). Default: simulated for 1.2 s.
onDone() => voidThe Open Acme CRM button. Default: the toast "Welcome to Acme CRM" (the page mounts its own Toaster then).
resendSecondsdefault30numberWait before the code or the link can be sent again (use-cooldown).
layoutdefault"split""split" | "centered" | "card"split: the form beside a hero from 1024px; centered: no hero, the form in a card from 640px; card: no hero, the form in a raised card at every width, centered on the page background (dots unless background is set) with the logo above and the links below.
heroSidedefault"end""start" | "end"Which side the hero sits on in the split layout.
backgrounddefault"glow""plain" | "soft" | "glow" | "aurora" | "grid" | "dots"The page background: plain is the bare page color; the others tint the page and add a glow, an aurora, a grid or dots over the first screen. The layout picks one unless you set it (split: glow; centered: glow; card: dots).
backgroundColordefault"oklch(0.62 0.14 275)"stringThe tint and glow color of the page background.
heroImagedefault""stringA photo behind the hero with a dark scrim and white text; empty keeps the neutral card hero. The demo passes /demo/laptop.jpg.
heroReactNodeReplaces the hero content (badge, title, feature checklist and customer names).
logoReactNodeTop-left of the form column; default the Acme CRM mark and name.
sizedefault"lg""md" | "lg"Fields and buttons: lg is 48px, md 40px (44px on touch); the code cells stay 48px.
loginHrefdefault"/sign-in"stringThe "Sign in" links (footer and the email taken alert); "" hides them.
forgotHrefdefault"/sign-in#forgot"stringThe "Forgot password?" link of the email taken alert; "" hides it.
termsHrefdefault"/terms"stringThe terms link in the checkbox and the footer; "" leaves plain text.
privacyHrefdefault"/privacy"stringThe privacy link in the checkbox and the footer; "" leaves plain text.
tonedefault"neutral"ToneThe primary buttons, the steps, the checkboxes, the team size thumb and the plan badge.
radiusdefault"md""sm" | "md" | "lg"The hero, the card, the tiles and the controls' corners.
animateIndefaulttruebooleanThe logo, form, footer and hero rise in once when the page mounts on the client (server html is already final).
labelsPartial<RegisterPageLabels>Every visible string, English by default (DEFAULT_REGISTER_PAGE_LABELS); spread it and override what you translate; steps takes the steps indicator strings, validation the form-validation messages.
localedefault"en-US"stringSets the page language (lang).
linkComponent(props: LinkComponentProps) => ReactNodeThe router link for the sign-in, legal and next step links (next/link); default <a>.
classNamesPartial<Record<RegisterPageSlot, string>>Classes for formColumn, header, body, footer, hero, steps, step, title and form.
Parts
DEFAULT_REGISTER_PAGE_LABELS
constantEvery English string of the account, company, verify and done steps, the hero and the footer. Spread it and override what you translate.
REGISTER_PAGE_LABELS_EN
constantAn alias of DEFAULT_REGISTER_PAGE_LABELS, kept so older imports keep working.
REGISTER_PROVIDERS
constantThe default social sign-up buttons: Google, Apple and Microsoft with their marks. Filter it or add your own { id, label, icon }.
REGISTER_PAGE_SAMPLE
constantThe demo content: the person who signs up, the hero copy and customers, roles and team sizes, the welcome checklist, the simulated CUI register and the code that passes.
Examples
Company, found by CUI
The company step after an ANAF lookup of RO12345674: name, address and the VAT badge, then role and team size.
Verification code
Six digit code sent to the email (123456 passes), a resend that waits 30 s and Change the email.
Welcome
The last step: the bouncy check, the first steps as rows and the way into the app.
No company step, email link
companyStep={false} and verify="link": two steps, the second a check your email view.
Centered card, brand
layout="centered" with tone="brand" on the primary actions, the steps and the checkboxes.
Card layout
layout="card": every step in a raised card on a dotted page background, the logo above it and the sign-in link below.
Neutral hero
locale en-GB and the neutral hero (no photo).
Dependencies
Files
- components/blocks/register-page.tsx
- components/blocks/register-page-data.ts
FAQ
Is the React Register Page block free?
The preview, props and docs are free; copying the source needs a Pro plan. See plans.
How do I install Register Page?
Run npx wingo-ui@latest add register-page. It also adds the Wingo UI items it builds on (Marketing Section, Alert, Badge, Button, Checkbox and 16 more) and the npm packages motion, lucide-react, react-hook-form and zod. With shadcn, add the @wingo-ui registry with your API key, then run npx shadcn@latest add @wingo-ui/register-page.
How does Register Page behave on phones?
Pick a role (a bottom sheet on phones) and a team size, then Continue, or Skip. Steps slide in from the side they belong to and focus moves to the step title; on phones the form fills the screen with 48px fields and the hero is gone; with reduced motion steps cross-fade.
See also
More React blocks
Articles using this component
- Shadcn Password Input: Show/Hide, Strength Meter, Caps Lock
Component guides9 min read
- Shadcn Login Page: Magic Link, Codes, 2FA and Recovery
Build it: screens and apps11 min read
- Romanian CUI Validation in TypeScript, Zod and React
Component guides11 min read