- Learn
- AI App Builders
- v0
- Integrating v0 Output
Learn how to properly integrate v0-generated components into your React and Next.js projects.
Integrating v0 Output
v0 generates beautiful components, but they need a home. This lesson covers how to properly integrate v0 output into your React or Next.js projects—handling dependencies, adapting code, and maintaining consistency.
Prerequisites for Integration
Project Setup
Before using v0 components, ensure your project has:
Required:
- React 18+
- TypeScript (strongly recommended)
- Tailwind CSS configured
Recommended:
- Next.js 14+ (App Router)
- shadcn/ui installed
Installing shadcn/ui
If you haven't set up shadcn/ui:
# In your Next.js project
npx shadcn@latest init
Follow the prompts:
- Style: Default or New York
- Base color: Choose your preference
- CSS variables: Yes (recommended)
Understanding the Output
v0 generates code that assumes shadcn/ui is installed:
import { Button } from "@/components/ui/button"
import { Card, CardContent } from "@/components/ui/card"
These imports reference components in your components/ui folder.
Step-by-Step Integration
Step 1: Copy the v0 Code
Click the copy button in v0's code panel. You get something like:
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
import { Button } from "@/components/ui/button"
import { Card, CardContent, CardHeader } from "@/components/ui/card"
export default function ProfileCard() {
return (
<Card>
<CardHeader>
<Avatar>
<AvatarImage src="/placeholder.jpg" />
<AvatarFallback>JD</AvatarFallback>
</Avatar>
</CardHeader>
<CardContent>
<h3 className="font-semibold">Jane Doe</h3>
<p className="text-muted-foreground">Product Designer</p>
<Button className="mt-4 w-full">Follow</Button>
</CardContent>
</Card>
)
}
Step 2: Check for Missing Components
Identify which shadcn/ui components are needed:
// This component uses:
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
import { Button } from "@/components/ui/button"
import { Card, CardContent, CardHeader } from "@/components/ui/card"
Step 3: Install Missing Components
Use the shadcn CLI to add them:
npx shadcn@latest add avatar
npx shadcn@latest add button
npx shadcn@latest add card
Or install multiple at once:
npx shadcn@latest add avatar button card
Step 4: Create the Component File
Save in your components folder:
components/
├── ui/ # shadcn components
├── profile-card.tsx # Your v0 component
└── ...
Step 5: Adapt for Your Needs
Replace placeholders with real data:
interface ProfileCardProps {
name: string
role: string
avatarUrl?: string
onFollow?: () => void
}
export function ProfileCard({
name,
role,
avatarUrl,
onFollow
}: ProfileCardProps) {
return (
<Card>
<CardHeader>
<Avatar>
<AvatarImage src={avatarUrl} alt={name} />
<AvatarFallback>{name.slice(0, 2).toUpperCase()}</AvatarFallback>
</Avatar>
</CardHeader>
<CardContent>
<h3 className="font-semibold">{name}</h3>
<p className="text-muted-foreground">{role}</p>
<Button className="mt-4 w-full" onClick={onFollow}>
Follow
</Button>
</CardContent>
</Card>
)
}
Step 6: Use in Your App
// app/page.tsx
import { ProfileCard } from '@/components/profile-card'
export default function HomePage() {
return (
<div className="p-8">
<ProfileCard
name="Jane Doe"
role="Product Designer"
avatarUrl="/images/jane.jpg"
onFollow={() => console.log('Followed!')}
/>
</div>
)
}
Common Integration Patterns
Pattern 1: Direct Usage
For simple, static components:
// Copy directly, minimal changes
export default function HeroSection() {
// v0 code works as-is
}
Pattern 2: Props Extraction
For reusable components:
// Extract all dynamic content as props
interface StatsCardProps {
title: string
value: string | number
change?: number
icon?: React.ReactNode
}
export function StatsCard({ title, value, change, icon }: StatsCardProps) {
// Use props instead of hardcoded values
}
Pattern 3: Composition
For complex components:
// Break into composable parts
export function DataTable({ columns, data, onRowClick }: DataTableProps) {
return (
<Table>
<DataTableHeader columns={columns} />
<DataTableBody data={data} columns={columns} onRowClick={onRowClick} />
<DataTablePagination totalPages={10} />
</Table>
)
}
Pattern 4: Wrapper Components
For extending v0 output:
// Wrap with additional functionality
import { BaseCard } from './base-card' // v0 component
export function ClickableCard({ onClick, ...props }: ClickableCardProps) {
return (
<div
onClick={onClick}
className="cursor-pointer transition-transform hover:scale-[1.02]"
>
<BaseCard {...props} />
</div>
)
}
Handling Dependencies
Checking Import Paths
v0 uses the @/ alias. Ensure your tsconfig.json has:
{
"compilerOptions": {
"paths": {
"@/*": ["./src/*"]
// or "./*" depending on your structure
}
}
}
Missing Icon Libraries
v0 often uses Lucide icons:
npm install lucide-react
Usage:
import { Home, Settings, User } from "lucide-react"
Utility Functions
v0 may reference a cn utility for class merging:
// lib/utils.ts
import { clsx, type ClassValue } from "clsx"
import { twMerge } from "tailwind-merge"
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}
Install dependencies:
npm install clsx tailwind-merge
Adapting for State Management
Adding Local State
'use client' // Required for useState in App Router
import { useState } from 'react'
export function ToggleCard() {
const [isActive, setIsActive] = useState(false)
return (
<Card className={isActive ? 'border-primary' : ''}>
<CardContent>
<Switch
checked={isActive}
onCheckedChange={setIsActive}
/>
</CardContent>
</Card>
)
}
Connecting to Context
'use client'
import { useUser } from '@/context/user-context'
export function UserMenu() {
const { user, logout } = useUser()
return (
<DropdownMenu>
<DropdownMenuTrigger>
<Avatar>
<AvatarImage src={user.avatar} />
</Avatar>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem onClick={logout}>
Sign out
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
)
}
API Integration
'use client'
import { useEffect, useState } from 'react'
interface User {
id: string
name: string
email: string
}
export function UserList() {
const [users, setUsers] = useState<User[]>([])
const [loading, setLoading] = useState(true)
useEffect(() => {
fetch('/api/users')
.then(res => res.json())
.then(data => {
setUsers(data)
setLoading(false)
})
}, [])
if (loading) return <Skeleton /> // v0 loading state
return (
<div>
{users.map(user => (
<UserCard key={user.id} user={user} />
))}
</div>
)
}
File Organization
Recommended Structure
src/
├── components/
│ ├── ui/ # shadcn/ui base components
│ │ ├── button.tsx
│ │ ├── card.tsx
│ │ └── ...
│ ├── features/ # Feature-specific components
│ │ ├── auth/
│ │ │ ├── login-form.tsx
│ │ │ └── signup-form.tsx
│ │ └── dashboard/
│ │ ├── stats-cards.tsx
│ │ └── recent-activity.tsx
│ └── layouts/ # Layout components
│ ├── header.tsx
│ ├── sidebar.tsx
│ └── footer.tsx
├── lib/
│ └── utils.ts # cn() and other utilities
└── app/
└── ...
Naming Conventions
# Component files
profile-card.tsx # kebab-case file names
ProfileCard # PascalCase component names
# Feature organization
features/auth/login-form.tsx
features/dashboard/stats-grid.tsx
Troubleshooting Common Issues
"Module not found" Errors
Check your import paths match your project structure:
// v0 generates:
import { Button } from "@/components/ui/button"
// Might need to be:
import { Button } from "../../components/ui/button"
// or configure @ alias properly
Type Errors
v0 sometimes generates loose TypeScript. Fix with proper types:
// Before
function handleClick(item) {
// ...
}
// After
function handleClick(item: ItemType) {
// ...
}
Style Conflicts
If Tailwind styles don't apply:
- Check Tailwind content paths in
tailwind.config.js - Ensure CSS import order is correct
- Check for conflicting styles
Server/Client Component Issues
In Next.js App Router, add 'use client' when using:
- useState, useEffect, other hooks
- Event handlers (onClick, onChange)
- Browser APIs
Maintaining Consistency
Create a Component Pattern
Document how you adapt v0 components:
// Component template
interface ComponentNameProps {
// Always define explicit props
}
export function ComponentName(props: ComponentNameProps) {
// Destructure props
const { prop1, prop2 } = props
// Component logic
return (
// JSX
)
}
Consistent Export Style
Pick one and stick with it:
// Named exports (recommended)
export function ProfileCard() { }
// Default exports
export default function ProfileCard() { }
Theme Alignment
Ensure v0 output matches your theme:
// If v0 uses blue-500 but your theme uses indigo
// Global find/replace or configure in Tailwind theme
Summary
- Install shadcn/ui components before using v0 output
- Extract props to make components reusable
- Add state and effects with
'use client'directive - Organize files by feature or component type
- Fix types and handle client/server component rules
- Maintain consistency across your codebase
Next Steps
You can now integrate v0 components seamlessly. Let's cover best practices for using v0 effectively in your workflow.