Skip to main content
RapidDev - Software Development Agency
V0 TemplatesAuth & FormsBeginner to customize

Two-Column Login Card V0 Template: Testimonial + Auth Form, Forked in Minutes

The Two-Column Login Card template pairs a shadcn/ui Card on the left (testimonial quote, customer avatar, or brand illustration) with a shadcn/ui Card on the right (email input, password input, remember-me checkbox, sign-in button). Built with react-hook-form and Zod on Next.js, it's the cleaner card-style alternative to the full-bleed hero panel login. Fork it, update the testimonial, and use the prompt pack to wire it to Clerk or Supabase in under an hour.

Auth & FormsBeginner~5 minutes

Best for

Founders who want a card-style split login — testimonial or illustration left, form right — for a polished SaaS first impression

Stack

Next.jsTypeScriptTailwind CSSshadcn/uireact-hook-formzod

A ready-made Two-Column Login Card UI you can fork, run, and customize with the prompt pack below.

What's actually inside

The honest engineer's breakdown — what the Two-Column Login Cardtemplate does, how it's wired, and where it's opinionated.

This template arranges two shadcn/ui Cards side by side. The Left Card Panel contains a testimonial quote, customer name, role, and avatar — or you can swap it for a brand illustration. This structured card approach feels more constrained and premium than a full-bleed hero image, making it well-suited for B2B SaaS products where trust signals (quotes from real customers) matter on the login page.

The Right Card Form mirrors the card aesthetic with shadcn/ui Input fields for email and password (with a show/hide eye toggle), a shadcn/ui Checkbox for 'Remember me', and a Sign-in Button that enters a loading state during submission. Both cards share the same shadcn/ui Card border and background, giving the page a cohesive, intentionally designed appearance. Zod and react-hook-form are wired but validation errors only surface on submit by default — not on blur.

Honest caveats: the two-column card grid collapses incorrectly on mobile on first fork — the left card stays visible and takes up too much vertical space. You need to change grid-cols-2 to grid-cols-1 md:grid-cols-2 and add hidden md:block to the left card. The Remember Me checkbox causes an SSR error if V0 places the localStorage.getItem call in the component render body rather than a useEffect. And like all shadcn/ui checkbox installs, the registry path may have changed — npx shadcn add checkbox may be required.

Key UI components

Left Card Panel

shadcn/ui Card with testimonial quote, customer avatar, name, and role

Right Card Form

shadcn/ui Card with email input, password input, remember-me checkbox, and sign-in button

Email Input

shadcn/ui Input with Label, controlled by react-hook-form

Password Input

shadcn/ui Input type='password' with Eye icon show/hide toggle

Remember Me Checkbox

shadcn/ui Checkbox registered with react-hook-form for email persistence

Sign-in Button

shadcn/ui Button showing loading state during form submission

Libraries it leans on

react-hook-form

Form state, field registration, Checkbox registration, and isSubmitting loading state

zod

Email format and password minimum-length validation schema via zodResolver

Fork it and get it running

The fork takes about 5 minutes. The highest-impact first change is swapping the left card testimonial for a real customer quote — it immediately makes the page feel production-ready.

1

Open and Fork

Go to https://v0.dev/chat/community/FcTLpL2JvgL. The preview shows two cards side-by-side: testimonial on the left, login form on the right. Click the 'Fork' button in the top-right to copy the project into your V0 account. All source files are copied and a new project opens.

Tip: You need a free V0 account to fork. Sign up at v0.dev if you haven't yet.

You should see: A new V0 project opens with the Two-Column Login Card source code and live preview.

2

Update the Testimonial in Design Mode

Press Option+D (Mac) to open Design Mode. Click the left card and update the testimonial quote text, the customer name, and their role (e.g. 'CEO, Acme Corp'). If you have a customer avatar URL, update the img src. Update the right card headline from the placeholder to your product's login heading. Design Mode changes are free — no credits consumed.

Tip: Even a fictional testimonial reads better than the placeholder. Come back and swap it for a real one after you have customers.

You should see: The preview shows your customer quote and name in the left card, and your product's login headline in the right card.

3

Add Zod Validation

Type this prompt: 'Add Zod validation for email format and password minimum 8 characters; display errors via shadcn/ui FormMessage below each field; add mode: onBlur to useForm so errors appear as users tab between fields.' V0 updates the schema, adds zodResolver, and wires FormMessage components below both inputs.

You should see: Both inputs show inline validation errors below them as users move between fields.

4

Add Auth Credentials in the Vars Panel

Click the Vars panel icon in the V0 toolbar. Add your auth provider credentials: for Clerk add NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY and CLERK_SECRET_KEY; for Supabase add NEXT_PUBLIC_SUPABASE_URL and NEXT_PUBLIC_SUPABASE_ANON_KEY. Never paste these into the chat — V0 logs chat history. Then use the auth prompt from the prompt pack below.

You should see: Auth credentials are stored as env vars, available in route handlers and Server Actions without exposing them in source code.

5

Publish to Production

Click Share → Publish → 'Publish to Production.' Vercel builds and deploys in under 60 seconds and provides a live Vercel subdomain URL. Test the full login flow — including the Remember Me checkbox and any OAuth buttons — on the deployed URL, not the V0 sandbox preview. OAuth redirects require a real domain to test.

You should see: A live URL loads the Two-Column Login Card. Signing in with valid credentials redirects to /dashboard.

6

Update Callback URLs

If you added Google OAuth or any social login, update your auth provider's allowed callback URLs to include the Vercel production domain. For Supabase: Supabase Dashboard → Auth → URL Configuration → Redirect URLs. For Clerk: Clerk Dashboard → Domains. If you later attach a custom domain via Vercel Dashboard → Settings → Domains, add that domain to the provider's list too.

You should see: OAuth logins succeed on the production domain without redirect URI mismatch errors.

The prompt pack

Copy-paste these straight into v0's chat to customize the Two-Column Login Cardtemplate. Each one names this template's own components — no generic filler.

1

Swap testimonial for a feature list

Replaces the testimonial with a product benefit list for products that don't yet have customer quotes to show.

Quick win
Paste into v0 chat
Replace the left card testimonial block with a vertical list of 4 feature bullets. Use shadcn/ui CheckIcon items for each bullet. Add a 'Trusted by 500+ teams' social proof line with a text-muted-foreground style below the list. Keep the left card background gradient and shadcn/ui Card border unchanged. Remove the customer avatar and name/role block.
2

Add a Sign Up tab to the right card

Combines sign-in and sign-up into a single card using tabs, removing the need for a separate /signup page.

Quick win
Paste into v0 chat
Add shadcn/ui Tabs above the right card form with 'Sign in' and 'Sign up' tab options. The 'Sign in' tab shows the existing email and password form. The 'Sign up' tab shows email, password, and confirm-password fields with a Zod refinement that ensures passwords match: z.object({ password: z.string().min(8), confirmPassword: z.string() }).refine(d => d.password === d.confirmPassword, { message: 'Passwords do not match', path: ['confirmPassword'] }). Both tabs use the same right Card wrapper with a shared Sign-in / Sign-up Button that changes label based on the active tab.
3

Add Google Sign-In button

Adds Google Sign-In as the primary auth option in the right card with email and password as the fallback.

Medium
Paste into v0 chat
Add a shadcn/ui Button variant='outline' with a Google SVG icon inline and the label 'Continue with Google' at the top of the right card, above the email input. Add a horizontal 'or continue with email' divider below it. Wire the Google button to your provider's OAuth flow: for Supabase use supabase.auth.signInWithOAuth({ provider: 'google', options: { redirectTo: process.env.NEXT_PUBLIC_SITE_URL + '/auth/callback' } }); for Clerk use the useOAuth hook from @clerk/nextjs.
4

Wire to Clerk auth

Connects the right card form to Clerk sign-in, with redirect for already-authenticated users.

Medium
Paste into v0 chat
Install @clerk/nextjs. Add ClerkProvider to the root layout using NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY from the Vars panel. In the right card form component (marked 'use client'), import useSignIn and useSignUp from @clerk/nextjs. For the Sign in tab, call signIn.create({ identifier: email, password }) on submit; on the returned createdSessionId call setActive then redirect to /dashboard. Display error.message in a shadcn/ui Alert below the form. Use useUser to redirect already-logged-in users away from the page.
5

Wire to Supabase Auth with cookie-based session

Wires the right card form to Supabase Auth with a secure Server Action, cookie-based session management, and route protection middleware.

Advanced
Paste into v0 chat
Install @supabase/supabase-js and @supabase/ssr. Create lib/supabase-server.ts with a factory function using createServerClient from @supabase/ssr. Create a Server Action in app/actions/login.ts with 'use server': call supabase.auth.signInWithPassword({ email, password }) using the server client; set cookies via the Response object; return { error: error.message } on failure. In the right card client component, call the action on submit and display the returned error in a shadcn/ui Alert. Add middleware.ts that checks supabase.auth.getUser() and redirects unauthenticated requests to /login.
6

Animate the left card testimonial on repeat

Rotates through multiple customer testimonials in the left card automatically, maximizing the trust-signal surface area.

Advanced
Paste into v0 chat
Install framer-motion. Wrap the left card content (quote text, customer name, role, avatar) in an AnimatePresence with a motion.div using initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} exit={{ opacity: 0 }} transition={{ duration: 0.5 }}. Create an array of 3 testimonials in a testimonials.ts file and use a useEffect with setInterval to cycle through them every 5 seconds, updating the active index in useState. The left card shows a new testimonial every 5 seconds with a fade-slide transition.

Gotchas when you extend it

The failures people actually hit when they push this template past its defaults — and the exact fix for each.

Remember Me stores email in localStorage causing `ReferenceError: localStorage is not defined`

Why: V0 may write the localStorage.setItem and getItem calls in the component render scope, which runs during Next.js server-side rendering where localStorage doesn't exist.

Fix: Move all localStorage calls for the Remember Me email storage into a useEffect hook that runs only after component mount.

Fix prompt — paste into v0
Move all localStorage calls for 'remember me' email storage into a useEffect that runs only after component mount: useEffect(() => { const saved = localStorage.getItem('saved-email'); if (saved) form.setValue('email', saved); }, []).
`The component at https://ui.shadcn.com/r/styles/new-york-v4/checkbox.json was not found`

Why: V0 may reference the Checkbox component via a direct registry URL that has changed in the new-york-v4 release of shadcn/ui.

Fix: Run npx shadcn add checkbox in your local project. If that fails, ask V0 to rebuild the Checkbox inline using an HTML input type='checkbox' styled with Tailwind.

Fix prompt — paste into v0
Replace the Checkbox registry import with npx shadcn add checkbox; if that fails, ask V0 to rebuild the checkbox using an HTML input type='checkbox' with className='h-4 w-4 rounded border border-input' styled with Tailwind.
Two-column card collapses to one column on mobile with the left card taking too much space

Why: Tailwind's grid-cols-2 without a responsive prefix applies on all screen sizes, stacking both cards vertically on mobile with the left testimonial card consuming unnecessary space.

Fix: Change the grid to grid-cols-1 md:grid-cols-2 and add hidden md:block to the left card so it only shows on desktop and larger.

Fix prompt — paste into v0
Update the grid from grid-cols-2 to grid-cols-1 md:grid-cols-2 and add hidden md:block to the left testimonial card to fix the mobile layout.
Sign-in button stays in loading state on network error

Why: If the auth call throws (network timeout, provider outage), react-hook-form's isSubmitting state never resets and the Sign-in Button spinner keeps spinning indefinitely.

Fix: Wrap the auth call in try/catch; call form.setError('root', { message: err.message }) in the catch block — this also resets the button out of its loading state.

Fix prompt — paste into v0
Wrap the auth call in try/catch and call form.setError('root', { message: err.message }) in the catch block to reset the Sign-in Button loading state on any network or auth error.

Template vs. custom — the honest call

A forked template gets you far, fast. Here's where it holds up, and where you'll outgrow it.

The template is enough when

  • SaaS login page where a customer testimonial is the strongest conversion element
  • Early-stage startup login during onboarding testing that needs social proof
  • Product with a strong customer quote that founders want visible at every login
  • Design system component demo showing a card-layout auth pattern for a client

Go custom when

  • You need passkeys (WebAuthn) as the primary authentication method
  • Enterprise SSO with SAML for workspace-scoped identity via Okta or Azure AD
  • Complex multi-step MFA/TOTP login with time-based one-time codes
  • Org-scoped login where different workspaces have different auth logic or providers

RapidDev wires this V0 login card to your auth provider of choice, adds route protection, and ships it — typically in 1 day.

Frequently asked questions

Is the Two-Column Login Card v0 template free?

Yes. Fork it for free with a free V0 account. The generated code is yours with no licensing fees. shadcn/ui, react-hook-form, and Zod are all MIT-licensed open-source libraries.

Can I use this template commercially in a product I sell?

Yes. The code V0 generates is yours to use in any commercial product without restriction. Don't republish the template on v0.dev community as your own creation.

Why does my fork show a blank preview after I add Supabase?

V0's preview sandbox resolves npm packages through esm.sh. @supabase/ssr sometimes fails there with 'Import Error | Failed to load from blob...'. This is a preview sandbox limitation only — click Share → Publish to Production and test on the Vercel deployment where the package resolves correctly.

Why is the Remember Me checkbox causing a server error?

V0 sometimes places localStorage.getItem() directly in the component render body, which runs during Next.js SSR in Node.js where localStorage doesn't exist. Move all localStorage reads and writes into a useEffect hook — this ensures they only run in the browser after the component mounts.

How do I fix the mobile layout where both cards stack vertically?

Change the grid from grid-cols-2 to grid-cols-1 md:grid-cols-2 and add hidden md:block to the left testimonial card. On screens smaller than the md breakpoint (768px), only the right form card shows. Add max-w-sm mx-auto to the right card so it doesn't stretch too wide on tablets.

What's the difference between this and the Two-Column Login template?

This template uses a shadcn/ui Card on the left with a testimonial — more structured and constrained. The Two-Column Login template uses a full-height image panel with marketing copy overlaid on it — more visual impact. Both share the same right-column auth form. Choose card for B2B SaaS trust signals; choose image panel for consumer apps.

Can RapidDev wire this login card to Clerk or Supabase for me?

Yes. RapidDev wires this V0 login card to your auth provider, adds protected route middleware, configures OAuth callbacks, and ships the complete auth flow — typically in 1 day.

How do I cycle through multiple testimonials in the left card?

Use the 'Animate the left card testimonial on repeat' prompt from the prompt pack above. It installs framer-motion, creates a testimonials array, and uses setInterval in a useEffect to rotate through them every 5 seconds with a fade-slide transition — no page reload required.

Outgrowing the template?

RapidDev turns v0 prototypes into production apps — real auth, database, and payments — at $13K–$25K.

Book a free consultation

30-min call. No commitment.

Want this built for you?

We ship production apps at a fixed price — $13K–$25K, 6–10 weeks, source code yours. You've seen what it takes; we do it every week.

Get a fixed-price quote

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.