Skip to main content

Oct 2026 · Workflow · ~10 min read

v0 by Vercel — How I Use It to Prototype React UIs in Minutes

By Safdar Ali — frontend engineer, Bengaluru

I'm Safdar Ali, a frontend engineer in Bengaluru. Last month a client asked for three dashboard mockups by Friday. Old me would have spent a day in Figma, exported assets, and still argued about spacing in the review call. New me opened v0 by Vercel, typed four prompts, and had working React components with Tailwind and ShadCN in under an hour. v0 is not a replacement for design or engineering — it's a speed layer between "I know what this should look like" and "here's code in my repo." This is my full v0 vercel react workflow, from first prompt to production deploy on safdarali.in and client projects.

What v0 actually generates

v0 is Vercel's AI UI generator. You describe a component or page in plain English; it returns React + Tailwind CSS code, usually built on ShadCN/ui primitives. Output runs in a live preview inside v0.dev before you copy anything. It understands layout, responsive breakpoints, dark mode variants, and common patterns — pricing tables, auth forms, data tables, landing hero sections.

What it does not do: connect to your API, handle auth, or know your design tokens. Treat every v0 output as a high-fidelity sketch in code form. The JSX structure is often good; the data layer, accessibility edge cases, and project-specific conventions are your job.

v0 fits early in the design-to-code pipeline — after you know what the page should do, before you wire production data. I use it in client discovery calls: share screen, prompt live, iterate in five minutes while the stakeholder watches. That beats sending Figma mockups back and forth for three days when the requirement is still moving. The output is not final code; it is a conversation starter that happens to compile.

Pricing in 2026: v0 offers free generations with limits and a paid tier for heavier use. For a freelance developer in India doing 2–3 client prototypes per month, the free tier often suffices. Heavy users — agencies prototyping daily — should budget for the paid plan. Compare that to a junior designer's day rate and the ROI is obvious for early-stage exploration.

// Typical v0 output — a pricing card section
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";

export function PricingSection() {
  const plans = [
    { name: "Starter", price: "₹999", features: ["5 projects", "Email support"] },
    { name: "Pro", price: "₹2,499", features: ["Unlimited", "Priority support"] },
  ];

  return (
    <section className="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
      {plans.map((plan) => (
        <Card key={plan.name}>
          <CardHeader><CardTitle>{plan.name}</CardTitle></CardHeader>
          <CardContent>
            <p className="text-3xl font-bold">{plan.price}/mo</p>
            <Button className="mt-4 w-full">Get started</Button>
          </CardContent>
        </Card>
      ))}
    </section>
  );
}

My prompt workflow — four passes, not one

One-shot prompts produce generic UI. I run four deliberate passes: structure, styling, responsiveness, then refinement. Each pass is a follow-up message in the same v0 chat, not a fresh generation.

Pass 1 — Structure and content

"Build a contact form section for a freelance developer portfolio. Fields: name, email, project type dropdown, budget range, message textarea. Include a submit button and a short intro paragraph." No colours yet. I want the DOM shape and field list correct first.

Pass 2 — Visual direction

"Use a neutral palette — zinc/slate. Rounded-xl inputs, subtle borders, focus rings. Match a minimal developer portfolio aesthetic, not a SaaS landing page." This pass fixes the biggest visual mismatch before I copy code.

Pass 3 — Responsive and states

"Stack fields single-column on mobile. Add loading and disabled states on the submit button. Show inline error placeholders below each field."

Pass 4 — Production hints

"Extract hardcoded text into props. Add TypeScript interface for form field config. Remove any unused imports." This makes the paste into my Next.js repo smoother.

From v0 preview to production Next.js

Copying v0 code directly into production is how you accumulate tech debt. My migration checklist takes 20–30 minutes per component and saves hours of cleanup later.

// BEFORE — pasted v0 output, hardcoded, no server integration
export function ContactForm() {
  return (
    <form onSubmit={(e) => e.preventDefault()}>
      <input placeholder="Name" />
      <button>Submit</button>
    </form>
  );
}

// AFTER — wired into Next.js with Server Action
"use client";
import { useActionState } from "react";
import { submitContact } from "@/app/actions/contact";

export function ContactForm() {
  const [state, action, pending] = useActionState(submitContact, null);

  return (
    <form action={action} className="space-y-4">
      <input name="name" required aria-label="Your name" />
      <input name="email" type="email" required aria-label="Email" />
      <button type="submit" disabled={pending}>
        {pending ? "Sending…" : "Send message"}
      </button>
      {state?.error && <p role="alert">{state.error}</p>}
    </form>
  );
}

Steps I always run: install missing ShadCN components via CLI, replace inline styles with project Tailwind config tokens, add aria labels, wire forms to Server Actions or API routes, and run eslint --fix. On a recent client dashboard, v0 gave me 80% of the layout in 15 minutes; the remaining 20% — data fetching, auth gates, error boundaries — took a normal afternoon.

Version control matters even for prototypes. I commit v0 output to a prototype/v1 branch before editing. When a client says "actually, go back to the first layout," I can diff against the original v0 paste instead of re-prompting from memory. Prompt history in v0 helps, but git is the source of truth once code enters your repo.

Accessibility is where v0 output most often fails review. Generated forms miss label associations, buttons lack descriptive text, and colour contrast sometimes fails WCAG on custom palettes. I run Lighthouse accessibility audit on every v0 migration before merge — expect 3–5 manual fixes per page. That is still faster than building the layout from scratch, but it is not zero-touch.

v0 vs hand-coding vs Figma — honest comparison

Criteriav0 by VercelHand-coded ReactFigma mockup
Time to first visual2–5 minutes30–60 minutes1–3 hours
Runnable codeYes, immediatelyYesNo — dev implements
Custom design system fitNeeds manual alignmentPerfectGood if tokens match
Client review speedExcellent — live URLGood on stagingStatic images only
Production-ready out of boxNoIf you write it rightN/A
Best forRapid UI explorationFinal production codeBrand-heavy marketing

v0 wins the first hour. Hand-coding wins the last mile. Figma still matters when brand guidelines, illustration, and marketing stakeholders need pixel-perfect sign-off before any code exists.

What I keep from v0 output vs what I rewrite

Keep: layout structure (grid/flex patterns), Tailwind spacing scale, ShadCN component composition, responsive breakpoint choices. Rewrite: hardcoded copy (move to CMS or i18n), fake data arrays (connect to API), event handlers (wire to real logic), accessibility gaps (add labels, focus management), and any inline styles that fight my Tailwind config.

// v0 often generates this — pretty but not production-safe
<img src="https://images.unsplash.com/photo-..." alt="hero" />

// My rewrite — next/image + local asset + proper alt
import Image from "next/image";

<Image
  src="/images/hero-dashboard.webp"
  alt="Analytics dashboard showing monthly revenue chart"
  width={1200}
  height={630}
  priority
/>

ShadCN setup so v0 code drops in cleanly

v0 assumes ShadCN/ui is installed. Before your first v0 session, run the ShadCN init in your Next.js project and add the components v0 commonly uses: Button, Card, Input, Label, Select, Dialog, Tabs. Missing components cause copy-paste failures that look like import errors but are really setup gaps.

# One-time setup in your Next.js App Router project
npx shadcn@latest init
npx shadcn@latest add button card input label select dialog tabs

# Match v0's default — tailwind.config should include:
# content: ["./app/**/*", "./components/**/*"]
# darkMode: ["class"]

I keep a starter branch in my GitHub with ShadCN pre-installed. New client prototypes start from that branch, v0 output lands in components/prototypes/, and I promote to components/ only after review.

Where v0 fails — set expectations early

Complex data tables with sorting, filtering, and pagination — v0 gives you the shell, not the logic. Multi-step wizards with conditional steps. Animations beyond basic Tailwind transitions. Anything requiring real API integration. Accessibility beyond baseline — always audit with axe or Lighthouse after migration.

v0 also does not know your existing components. If your design system has a custom <PrimaryButton>, say so in the prompt: "Use our PrimaryButton from @/components/ui/primary-button instead of default Button." Otherwise you refactor imports later.

The prototype-to-production path I recommend: v0 for layout → paste into components/prototypes/ → client review on preview deploy → promote to components/ after wiring data → delete prototype folder. Never let prototypes sit in production routes unmodified for more than a sprint — they accumulate security and maintenance debt fast.

Combine v0 with Cursor for the production pass: v0 generates the UI shell, Cursor agent wires Server Actions, adds TypeScript strict types, and runs the build. That pairing is how I hit Friday deadlines without shipping unaudited generated code. v0 is the sketch; Cursor plus your review is the engineering.

My prompt library — copy and adapt

These prompts work consistently in v0 for React/Next.js UIs. Replace bracketed sections with your specifics.

// Dashboard stat row
"Build a responsive stat row with 4 cards: total users, revenue (INR),
 active sessions, conversion rate. Each card has label, big number,
 and percentage change with green/red. Use ShadCN Card, dark mode support."

// Pricing section
"3-tier pricing table: Starter ₹999, Pro ₹2499 (highlighted), Enterprise custom.
 Monthly/yearly toggle. Feature list with checkmarks. CTA buttons per tier."

// Auth form
"Split login/signup tabs. Email + password fields, Google OAuth button placeholder,
 forgot password link. Minimal zinc palette, mobile-first."

// Data table shell
"Sortable table with columns: name, status badge, date, actions dropdown.
 Pagination footer. Empty state illustration placeholder."

Save prompts that work in a personal Notion or GitHub gist. v0 output quality correlates directly with prompt specificity — "build a form" produces generic slop; "contact form with name, email, project type select, budget range, message, zinc palette, rounded-xl inputs" produces something you can actually show a client.

The single takeaway

v0 vercel react prototyping is real productivity — not magic. Use it to collapse the gap between idea and clickable UI, then apply your engineering standards before merge. Four-pass prompts, ShadCN pre-setup, and a clear keep/rewrite checklist turn v0 from a toy into a tool I reach for weekly.

The developers who get the most from v0 are the ones who already know React — they evaluate output critically instead of accepting the first generation. If you are learning React, use v0 to study generated patterns, then rewrite by hand until you understand every line. If you are shipping client work, use v0 for speed on layout and spend saved time on data wiring, accessibility, and performance — the parts that actually determine whether a site converts.

Related: safdarali.in/projects for client work built with this workflow. More guides: safdarali.in/blog. Questions: safdarali.in/contact.

If this helped you

I publish free tutorials and write-ups like this in my spare time — no paywall on the guides. If it saved you an afternoon of trial and error, you can support the work:

More guides on safdarali.in — same author, production-focused.

"Talk is cheap. Show me the code."