# v0 clone URL: /examples/v0 --- title: v0 clone description: An example of how to use the AI Elements to build a v0 clone. --- An example of how to use the AI Elements to build a v0 clone. ## Tutorial Let's walk through how to build a v0 clone using AI Elements and the [v0 Platform API](https://v0.dev/docs/api/platform). ### Setup First, set up a new Next.js repo and cd into it by running the following command (make sure you choose to use Tailwind the project setup): ```bash title="Terminal" npx create-next-app@latest v0-clone && cd v0-clone ``` Run the following command to install shadcn/ui and AI Elements. ```bash title="Terminal" npx shadcn@latest init && npx ai-elements@latest ``` Now, install the v0 sdk: ```package-install npm i v0-sdk ``` In order to use the providers, let's configure a v0 API key. Create a `.env.local` in your root directory and navigate to your [v0 account settings](https://v0.dev/chat/settings/keys) to create a token, then paste it in your `.env.local` as `V0_API_KEY`. We're now ready to start building our app! ### Client In your `app/page.tsx`, replace the code with the file below. Here, we use `Conversation` to wrap the conversation code, and the `WebPreview` component to render the URL returned from the v0 API. ```tsx title="app/page.tsx" "use client"; import { useState } from "react"; import { PromptInput, type PromptInputMessage, PromptInputSubmit, PromptInputTextarea } from "@/components/ai-elements/prompt-input"; import { Message, MessageContent } from "@/components/ai-elements/message"; import { Conversation, ConversationContent } from "@/components/ai-elements/conversation"; import { WebPreview, WebPreviewNavigation, WebPreviewUrl, WebPreviewBody } from "@/components/ai-elements/web-preview"; import { Loader } from "@/components/ai-elements/loader"; import { Suggestions, Suggestion } from "@/components/ai-elements/suggestion"; interface Chat { id: string; demo: string; } export default function Home() { const [message, setMessage] = useState(""); const [currentChat, setCurrentChat] = useState(null); const [isLoading, setIsLoading] = useState(false); const [chatHistory, setChatHistory] = useState< Array<{ type: "user" | "assistant"; content: string; }> >([]); const handleSendMessage = async (promptMessage: PromptInputMessage) => { const hasText = Boolean(promptMessage.text); const hasAttachments = Boolean(promptMessage.files?.length); if (!(hasText || hasAttachments) || isLoading) return; const userMessage = promptMessage.text?.trim() || "Sent with attachments"; setMessage(""); setIsLoading(true); setChatHistory((prev) => [...prev, { type: "user", content: userMessage }]); try { const response = await fetch("/api/chat", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ message: userMessage, chatId: currentChat?.id, }), }); if (!response.ok) { throw new Error("Failed to create chat"); } const chat: Chat = await response.json(); setCurrentChat(chat); setChatHistory((prev) => [ ...prev, { type: "assistant", content: "Generated new app preview. Check the preview panel!", }, ]); } catch (error) { console.error("Error:", error); setChatHistory((prev) => [ ...prev, { type: "assistant", content: "Sorry, there was an error creating your app. Please try again.", }, ]); } finally { setIsLoading(false); } }; return (
{/* Chat Panel */}
{/* Header */}

v0 Clone

{chatHistory.length === 0 ? (

What can we build together?

) : ( <> {chatHistory.map((msg, index) => ( {msg.content} ))} {isLoading && (
Creating your app...
)} )}
{/* Input */}
{!currentChat && ( setMessage("Create a responsive navbar with Tailwind CSS")} suggestion="Create a responsive navbar with Tailwind CSS" /> setMessage("Build a todo app with React")} suggestion="Build a todo app with React" /> setMessage("Make a landing page for a coffee shop")} suggestion="Make a landing page for a coffee shop" /> )}
setMessage(e.target.value)} value={message} className="pr-12 min-h-[60px]" />
{/* Preview Panel */}
); } ``` In this case, we'll also edit the base component `components/ai-elements/web-preview.tsx` in order to best match with our theme. ```tsx title="components/ai-elements/web-preview.tsx" highlight="5,24" return (
{children}
); }; export type WebPreviewNavigationProps = ComponentProps<'div'>; export const WebPreviewNavigation = ({ className, children, ...props }: WebPreviewNavigationProps) => (
{children}
); ``` ### Server Create a new route handler `app/api/chat/route.ts` and paste in the following code. We use the v0 SDK to manage chats. ```ts title="app/api/chat/route.ts" import { NextRequest, NextResponse } from "next/server"; import { v0 } from "v0-sdk"; export async function POST(request: NextRequest) { try { const { message, chatId } = await request.json(); if (!message) { return NextResponse.json({ error: "Message is required" }, { status: 400 }); } let chat; if (chatId) { // continue existing chat chat = await v0.chats.sendMessage({ chatId: chatId, message, }); } else { // create new chat chat = await v0.chats.create({ message, }); } return NextResponse.json({ id: chat.id, demo: chat.demo, }); } catch (error) { console.error("V0 API Error:", error); return NextResponse.json({ error: "Failed to process request" }, { status: 500 }); } } ``` To start your server, run `pnpm dev`, navigate to `localhost:3000` and try building an app! You now have a working v0 clone you can build off of! Feel free to explore the [v0 Platform API](https://v0.dev/docs/api/platform) and components like [`Reasoning`](/elements/components/reasoning) and [`Task`](/elements/components/task) to extend your app, or view the other examples.