Customize Sign-In
Learn how to customize the sign-in page styling, validation, and behavior
Learn how to customize Plainform's sign-in page to match your brand and add custom functionality.
Goal
By the end of this recipe, you'll have customized the sign-in page with your own styling, validation rules, and behavior.
Prerequisites
- A working Plainform installation
- Basic knowledge of React and TypeScript
- Familiarity with Tailwind CSS
Plainform uses custom sign-in forms built with Clerk's useSignIn hook, not Clerk's pre-built components. This gives you full control over the UI.
Steps
Locate the Sign-In Form
The sign-in form is located at:
components/user/SignInForm.tsxThis component uses:
useSignInhook from Clerk for authentication logicreact-hook-formfor form state management- Zod for validation
- Tailwind CSS for styling
Customize Form Styling
Update the form's appearance by modifying Tailwind classes:
export function SignInForm() {
return (
<div className="w-full max-w-md space-y-6">
{/* Update card styling */}
<Card className="border-2 border-brand shadow-xl">
<CardHeader className="space-y-2 text-center">
{/* Customize heading */}
<CardTitle className="text-3xl font-bold text-brand">
Welcome Back
</CardTitle>
<CardDescription className="text-base">
Sign in to your account to continue
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
{/* Form fields */}
</CardContent>
</Card>
</div>
);
}Common customizations:
- Change card border and shadow
- Update heading text and styling
- Modify spacing with
space-y-*classes - Add brand colors with
text-brandor custom colors
Customize Validation Rules
Update the validation schema in validationSchemas/authSchemas.ts:
import { z } from 'zod';
export const signInSchema = z.object({
identifier: z
.string()
.min(1, 'Email is required')
.email('Please enter a valid email address'),
password: z
.string()
.min(8, 'Password must be at least 8 characters')
.max(100, 'Password is too long'),
});Validation options:
- Change minimum password length
- Add custom error messages
- Add regex patterns for email format
- Add maximum length constraints
Keep validation rules consistent between sign-in and sign-up forms for better UX.
Customize Redirect Behavior
Change where users go after signing in:
if (signInAttempt.status === 'complete') {
await setActive({ session: signInAttempt.createdSessionId });
// Redirect based on user role or previous page
const redirectUrl = searchParams.get('redirect') || '/dashboard';
router.push(redirectUrl);
}Redirect options:
- Redirect to dashboard:
router.push('/dashboard') - Redirect to previous page: Use
redirectquery parameter - Role-based redirect: Check user role and redirect accordingly
Add Remember Me Functionality
Add a "Remember Me" checkbox (optional):
const [rememberMe, setRememberMe] = useState(false);
// In the form
<div className="flex items-center space-x-2">
<Checkbox
id="remember"
checked={rememberMe}
onCheckedChange={(checked) => setRememberMe(checked as boolean)}
/>
<label
htmlFor="remember"
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
>
Remember me for 30 days
</label>
</div>
// When creating session
if (signInAttempt.status === 'complete') {
await setActive({
session: signInAttempt.createdSessionId,
// Extend session if remember me is checked
beforeEmit: rememberMe ? undefined : () => {},
});
}Clerk handles session persistence automatically. The "Remember Me" option can extend the session duration.
Preview Your Changes
Start your development server:
npm run devNavigate to http://localhost:3000/sign-in to see your customized sign-in page.
Common Customizations
Change Form Layout
Switch to a horizontal layout for wider screens:
<div className="grid md:grid-cols-2 gap-6">
<div className="space-y-4">
{/* Left side: Form */}
<SignInForm />
</div>
<div className="hidden md:flex items-center justify-center bg-muted rounded-lg">
{/* Right side: Image or branding */}
<img src="/signin-illustration.svg" alt="Sign in" />
</div>
</div>Add More OAuth Providers
To add additional OAuth providers beyond Google and GitHub:
<div className="grid grid-cols-2 gap-4">
<OAuthConnection strategy="oauth_google" icon="Google">
Google
</OAuthConnection>
<OAuthConnection strategy="oauth_github" icon="Github">
GitHub
</OAuthConnection>
<OAuthConnection strategy="oauth_microsoft" icon="Microsoft">
Microsoft
</OAuthConnection>
<OAuthConnection strategy="oauth_apple" icon="Apple">
Apple
</OAuthConnection>
</div>Available OAuth providers:
oauth_google- Googleoauth_github- GitHuboauth_microsoft- Microsoftoauth_apple- Appleoauth_facebook- Facebookoauth_linkedin- LinkedInoauth_twitter- Twitter
Enable each provider in Clerk Dashboard → Social Connections before adding the button.
Common Issues
Validation Not Working
- Verify the schema is imported correctly in
SignInForm.tsx - Check that
react-hook-formresolver is configured with Zod - Ensure form fields have correct
nameattributes matching schema
Styling Not Applied
- Clear browser cache and restart dev server
- Check Tailwind CSS classes are valid
- Verify
globals.cssis imported in root layout - Run
npm run devto rebuild Tailwind
Redirect Not Working
- Verify the redirect URL is valid and accessible
- Check middleware configuration in
proxy.ts - Ensure the target route exists in your app
OAuth Buttons Not Showing
- Verify OAuth providers are enabled in Clerk Dashboard
- Check
OAuthConnectioncomponent is imported correctly - Ensure Clerk environment variables are set
Next Steps
- Add OAuth Providers - Enable Google, GitHub, and more
- Implement Roles - Add role-based access control
- Protect Routes - Secure your application routes
Related Documentation
- Authentication Overview - Learn about Clerk integration
- Usage & Integration - Authentication patterns
- Troubleshooting - Fix common issues
How is this guide ?
Last updated on