How to Use Pre-Built Validation Schemas (loginSchema & registerSchema) in refine-shadcn
Import loginSchema or registerSchema from @/lib/validation, pass them to zodResolver in your useForm hook, and receive fully-typed, validated form data for authentication flows without writing custom Zod logic.
The refine-shadcn repository provides production-ready authentication components backed by strict validation rules. These rules live as Zod schemas in packages/auth/src/lib/validation.ts, offering a single source of truth for login and registration validation that propagates TypeScript types throughout your application.
Where the Pre-Built Schemas Live
All validation logic is centralized in packages/auth/src/lib/validation.ts. This file exports two primary schemas and their inferred types:
loginSchema– Validates email format and password length (minimum 6 characters)registerSchema– Validates name, email, password strength, password confirmation matching, and terms acceptanceLoginFormData– TypeScript type derived fromloginSchemaRegisterFormData– TypeScript type derived fromregisterSchema
The repository exposes these through a path alias @/lib/validation, allowing you to import them cleanly from any component without relative path navigation.
Understanding the Schema Definitions
Login Validation Rules
The loginSchema enforces two fields with specific constraints. According to the source in packages/auth/src/lib/validation.ts, it requires a valid email address and a password of at least 6 characters:
// packages/auth/src/lib/validation.ts
export const loginSchema = z.object({
email: z.string().email("Invalid email address").min(1, "Email is required"),
password: z.string().min(6, "Password must be at least 6 characters").min(1, "Password is required"),
});
Registration Validation Rules
The registerSchema handles complex multi-field validation including password confirmation. It uses Zod's .refine() method to ensure confirmPassword matches password and that acceptTerms is true:
// packages/auth/src/lib/validation.ts
export const registerSchema = z.object({
name: z.string().min(2, "Name must be at least 2 characters"),
email: z.string().email("Invalid email address"),
password: z.string().min(8, "Password must be at least 8 characters"),
confirmPassword: z.string(),
acceptTerms: z.boolean(),
}).refine((data) => data.password === data.confirmPassword, {
message: "Passwords don't match",
path: ["confirmPassword"],
}).refine((data) => data.acceptTerms === true, {
message: "You must accept the terms",
path: ["acceptTerms"],
});
Integrating with react-hook-form
To activate validation in your components, wire the schemas into react-hook-form using @hookform/resolvers/zod. This bridges Zod's parsing logic with the form's state management.
Basic Login Form Setup
Import the schema and type, then pass them to useForm:
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { loginSchema, type LoginFormData } from "@/lib/validation";
const form = useForm<LoginFormData>({
resolver: zodResolver(loginSchema),
defaultValues: { email: "", password: "" },
});
Basic Registration Form Setup
The pattern is identical for registration, using the richer registerSchema:
import { registerSchema, type RegisterFormData } from "@/lib/validation";
const form = useForm<RegisterFormData>({
resolver: zodResolver(registerSchema),
defaultValues: {
name: "",
email: "",
password: "",
confirmPassword: "",
acceptTerms: false,
},
});
Complete Component Examples
Login Form Implementation
The packages/auth/src/components/login-form.tsx file demonstrates the canonical implementation. It combines the schema with shadcn/ui form primitives to render validation errors automatically:
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { loginSchema, type LoginFormData } from "@/lib/validation";
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@ferdiunal/refine-shadcn/ui/form";
import { Input } from "@ferdiunal/refine-shadcn/ui/input";
import { Button } from "@ferdiunal/refine-shadcn/ui/button";
export function LoginForm({ onSubmit }: { onSubmit: (data: LoginFormData) => void }) {
const form = useForm<LoginFormData>({
resolver: zodResolver(loginSchema),
defaultValues: { email: "", password: "" },
});
return (
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
<FormField
control={form.control}
name="email"
render={({ field }) => (
<FormItem>
<FormLabel>Email</FormLabel>
<FormControl>
<Input type="email" placeholder="you@example.com" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="password"
render={({ field }) => (
<FormItem>
<FormLabel>Password</FormLabel>
<FormControl>
<Input type="password" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<Button type="submit" disabled={form.formState.isSubmitting}>
Sign In
</Button>
</form>
</Form>
);
}
Registration Form Implementation
The registration form in packages/auth/src/components/register-form.tsx follows the same architecture but includes additional fields for name, confirm password, and terms acceptance. The FormMessage component automatically displays errors from the schema's .refine() calls, such as mismatched passwords or unchecked terms boxes.
Customizing the Schemas
Because validation is centralized in packages/auth/src/lib/validation.ts, you can modify authentication rules globally. For example, to require stronger passwords across your entire application:
-
Update the password field in both schemas:
password: z.string().min(12, "Password must be at least 12 characters").regex(/[A-Z]/, "Must contain uppercase"), -
Save the file—all forms using these schemas immediately enforce the new rules without component-level changes.
Summary
- Centralized location: All pre-built validation schemas live in
packages/auth/src/lib/validation.tsand export via@/lib/validation. - Two primary exports:
loginSchema(email + 6-char password) andregisterSchema(name, email, password match, terms). - Type inference: Import
LoginFormDataandRegisterFormDatato type your form hooks and submit handlers. - react-hook-form integration: Use
zodResolver(loginSchema)inuseFormto activate validation. - Automatic UI feedback: Form primitives from
@ferdiunal/refine-shadcn/uiconsume the validation state and render errors via<FormMessage />.
Frequently Asked Questions
How do I access the validated data after form submission?
When form.handleSubmit executes, react-hook-form passes the validated data to your callback function with the exact shape defined by the schema. For example, if using registerSchema, your onSubmit handler receives a RegisterFormData object containing { name, email, password, confirmPassword, acceptTerms }, all guaranteed to meet the validation rules defined in packages/auth/src/lib/validation.ts.
Can I extend the pre-built schemas for additional fields?
Yes. Import the base schema and use Zod's .extend() method to add new fields, or compose a new schema that merges the existing one. Because the schemas are standard Zod objects, you can chain methods like .pick(), .omit(), or .merge() to create variations for different authentication flows while keeping the core validation logic intact.
What happens if I don't use the default UI components?
The schemas work with any react-hook-form implementation. Even without @ferdiunal/refine-shadcn/ui primitives, passing zodResolver(loginSchema) to useForm still provides type-safe validation state via form.formState.errors. You can display these errors manually by accessing form.formState.errors.email?.message or similar properties in your custom input components.
Do these schemas support internationalization?
The raw schemas in packages/auth/src/lib/validation.ts contain hardcoded English error messages. To support multiple languages, either override the error messages when instantiating the resolver or wrap the validation logic in a factory function that accepts translation helpers. The repository's own login and register components demonstrate integration with translation hooks for message customization.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →