How to Build an Auth Flow in React (Login, Signup, OTP, Reset)
A complete guide to building authentication flows in React: login, signup, OTP verification, and password reset — all accessible, all with Ninna UI components.
By Ninna UI Team
Authentication flows are one of the most common UI patterns — and one of the most accessibility-critical. Every form needs labels, error messages, focus management, and keyboard navigation. Let's build a complete auth flow with Ninna UI.
1. Login form
import { Button, Heading } from "@ninna-ui/primitives";import { Input, Field, Checkbox } from "@ninna-ui/forms";import { VStack } from "@ninna-ui/layout";
export function LoginForm() { return ( <VStack gap="4" as="form"> <Heading as="h1" size="2xl">Welcome back</Heading> <Field label="Email" htmlFor="email" error="Invalid email" invalid> <Input id="email" type="email" placeholder="you@example.com" /> </Field> <Field label="Password" htmlFor="password"> <Input id="password" type="password" /> </Field> <Checkbox>Remember me</Checkbox> <Button type="submit" color="primary" fullWidth>Log in</Button> </VStack> );}The Field component automatically wires aria-labelledby, aria-describedby, and aria-invalid to the input. You don't need to add any ARIA attributes manually.
2. Signup form
export function SignupForm() { return ( <VStack gap="4" as="form"> <Heading as="h1" size="2xl">Create account</Heading> <Field label="Name" htmlFor="name"> <Input id="name" placeholder="Jane Doe" /> </Field> <Field label="Email" htmlFor="email"> <Input id="email" type="email" /> </Field> <Field label="Password" htmlFor="password" description="At least 8 characters"> <Input id="password" type="password" /> </Field> <Button type="submit" color="primary" fullWidth>Sign up</Button> </VStack> );}3. OTP verification
Use the PinInput component for OTP codes. It handles individual digit inputs, auto-advance, and paste:
import { PinInput } from "@ninna-ui/forms";
export function OtpVerify() { return ( <VStack gap="4" as="form"> <Heading as="h1" size="2xl">Verify your email</Heading> <Text>Enter the 6-digit code we sent to your email.</Text> <PinInput length={6} /> <Button type="submit" color="primary">Verify</Button> </VStack> );}4. Password reset
export function ResetPassword() { return ( <VStack gap="4" as="form"> <Heading as="h1" size="2xl">Reset password</Heading> <Field label="New password" htmlFor="password" description="At least 8 characters"> <Input id="password" type="password" /> </Field> <Field label="Confirm password" htmlFor="confirm" error="Passwords do not match" invalid> <Input id="confirm" type="password" /> </Field> <Button type="submit" color="primary">Reset password</Button> </VStack> );}5. Ready-made auth blocks
Ninna UI ships production-ready auth blocks you can copy: login, signup, magic link, OTP verify, reset password, and social wall. Browse them at /blocks and filter by the Authentication category.
These blocks include responsive layout, social login buttons, and consistent styling — all accessible by default. Copy the code and adapt it to your auth provider.