How to Build an AI Chat App Interface With the Vercel AI SDK and Shadcn/ui — Opportunihub
Course Remote

How to Build an AI Chat App Interface With the Vercel AI SDK and Shadcn/ui

Vaibhav Gupta · Remote

At a glance

Type
Course
Organisation
Vaibhav Gupta
Location
Remote
Work mode
Remote
Deadline
Rolling / not stated
Posted
11 Sep 2026

About this course

<p>Every other AI product you open today has the same screen: a message list, a text box at the bottom, and words that stream in one token at a time. It looks simple, but it's not simple to build well.</p> <p>You have to manage streaming state, partial tokens, tool calls, retries, markdown rendering, scroll position, and a dozen small UX details...all while keeping the interface accessible and fast. Do it with the wrong tools, and you'll spend more time fighting state bugs than building your actual product.</p> <p>In this tutorial, you'll build a real AI chat interface using two tools that were basically made for each other: the Vercel AI SDK for the streaming and model logic, and shadcn/ui for the interface itself.</p> <p>By the end, you'll have a working chat screen that streams responses, renders markdown, and looks like something you would actually ship.</p> <p>You'll also see how to speed up the UI side of this even further using an MCP server, and where to grab a production-ready chat template if you'd rather skip the setup entirely.</p> <img src="https://cdn.hashnode.com/uploads/covers/5e1e335a7a1d3fcc59028c64/1d8974cc-4cc4-41e9-a1b0-7a81c184fcaf.webp" alt="What we'll build - AI chat interface screenshot" style="display: block;" width="1920" height="1440" loading="lazy"> <h2 id="heading-table-of-contents">Table of Contents</h2> <ul> <li><p><a href="#heading-prerequisites"><strong>Prerequisites</strong></a></p> </li> <li><p><a href="#heading-what-youll-build"><strong>What You'll Build</strong></a></p> </li> <li><p><a href="#heading-step-1-scaffold-the-nextjs-app"><strong>Step 1: Scaffold the Next.js App</strong></a></p> </li> <li><p><a href="#heading-step-2-install-the-vercel-ai-sdk"><strong>Step 2: Install the Vercel AI SDK</strong></a></p> </li> <li><p><a href="#heading-step-3-why-shadcnui-pairs-so-well-with-ai-chat">Step 3: Why shadcn/ui Pairs So Well With AI Chat UIs</a></p> </li> <li><p><a href="#heading-step-4-set-up-shadcnui-in-your-project">Step 4: Set Up shadcn/ui in Your Project</a></p> </li> <li><p><a href="#heading-step-5-build-the-streaming-api-route"><strong>Step 5: Build the Streaming API Route</strong></a></p> </li> <li><p><a href="#heading-step-6-wire-up-the-client-with-usechat"><strong>Step 6: Wire Up the Client With useChat</strong></a></p> </li> <li><p><a href="#heading-step-7-let-the-model-call-tools"><strong>Step 7: Let the Model Call Tools</strong></a></p> </li> <li><p><a href="#heading-step-8-prototype-the-ui-without-a-backend"><strong>Step 8: Prototype the UI Without a Backend</strong></a></p> </li> <li><p><a href="#heading-turning-your-chat-into-a-full-product"><strong>Turning Your Chat Into a Full Product</strong></a></p> </li> <li><p><a href="#heading-speed-up-shadcn-development-with-an-mcp-server"><strong>Speed Up shadcn Development With an MCP Server</strong></a></p> </li> <li><p><a href="#heading-a-few-things-to-handle-before-you-ship"><strong>A Few Things to Handle Before You Ship</strong></a></p> </li> <li><p><a href="#heading-skip-the-boilerplate-with-a-ready-made-template"><strong>Skip the Boilerplate With a Ready-Made Template</strong></a></p> </li> <li><p><a href="#heading-wrapping-up"><strong>Wrapping Up</strong></a></p> </li> <li><p><a href="#heading-resources"><strong>Resources</strong></a></p> </li> </ul> <h2 id="heading-prerequisites">Prerequisites</h2> <p>You will need:</p> <ul> <li><p>Node.js 18 or later</p> </li> <li><p>Basic familiarity with React and Next.js, specifically the App Router</p> </li> <li><p>An API key from an LLM provider such as OpenAI, Anthropic, or Google. You can follow along without one, more on that later.</p> </li> </ul> <h2 id="heading-what-youll-build">What You'll Build</h2> <p>You're going to build a Next.js chat app with:</p> <ul> <li><p>A streaming API route that talks to an LLM provider</p> </li> <li><p>A client-side chat interface built with <code>useChat</code></p> </li> <li><p>Message bubbles, an auto-growing input, and a scrollable conversation, all styled with shadcn/ui components</p> </li> <li><p>A simple tool call so the model can do more than just talk</p> </li> <li><p>A fallback state that works even before you add an API key, so you can build the UI first and wire up the model later</p> </li> </ul> <p>Let's start from an empty folder and work up to something you would be comfortable showing a teammate.</p> <h2 id="heading-step-1-scaffold-the-nextjs-app">Step 1: Scaffold the Next.js App</h2> <p>Create a new Next.js project with TypeScript and Tailwind enabled:</p> <pre><code class="language-bash">npx create-next-app@latest ai-chat-app --typescript --tailwind --eslint --app cd ai-chat-app </code></pre> <p>Keep the defaults for everything else the CLI asks you. You'll be working almost entirely inside the <code>app</code> directory.</p> <h2 id="heading-step-2-install-the-vercel-ai-sdk">Step 2: Install the Vercel AI SDK</h2> <p>The <a href="https://vercel.com/docs/ai-sdk"><strong>Vercel AI SDK</strong></a> is what does the heavy lifting here. It gives you one API for calling different model providers, streaming text and structured data, and handling tool calls, so you're not rewriting your chat logic every time you switch models.</p> <p>Install the core package, the React bindings, and an OpenAI-compatible provider:</p> <pre><code class="language-bash">npm install ai @ai-sdk/react @ai-sdk/openai-compatible </code></pre> <p><code>@ai-sdk/openai-compatible</code> is worth calling out specifically: instead of installing a separate package per provider, it lets you point at any provider that speaks the OpenAI-style API (OpenAI itself, Gemini, Groq, and plenty of self-hosted setups) just by swapping a base URL. Combined with an <code>AI_PROVIDER</code> environment variable, you get provider switching without touching your route handler at all, which is exactly the pattern you'll build in the next step.</p> <h2 id="heading-step-3-why-shadcnui-pairs-so-well-with-ai-chat-uis">Step 3: Why shadcn/ui Pairs So Well With AI Chat UIs</h2> <p>Before you write any UI code, it's worth understanding why so many AI chat products lean on shadcn/ui instead of a traditional component library.</p> <p>Most component libraries hand you a compiled package and hide the internals behind props. That works fine for a settings page, but it works badly for a chat interface. For chat, you need to control exactly how a message bubble animates while it streams, how a "thinking" indicator behaves, or how a tool call renders differently from plain text.</p> <p>shadcn/ui takes a different approach: instead of installing a package, you copy the component's actual source code into your project. You own it completely, with no fighting an abstraction to bend it to your use case and no waiting on a maintainer to expose the one prop you need. That ownership model is exactly what a chat interface needs, since almost no two AI products render messages, reasoning, or tool output the same way.</p> <p>It's also why an entire ecosystem has grown up around it. If you want a wider set of production-ready blocks and templates beyond the default registry, including dashboards, marketing sections, and full chat UIs, the <a href="https://shadcnspace.com/"><strong>shadcn/ui</strong></a> community hub at Shadcn Space is worth bookmarking. You'll come back to it later in this tutorial.</p> <h2 id="heading-step-4-set-up-shadcnui-in-your-project">Step 4: Set Up shadcn/ui in Your Project</h2> <p>Since you already have a Next.js project from Step 1, apply the Shadcn Space preset to it directly:</p> <pre><code class="language-bash">npx shadcn@latest apply --preset b0 </code></pre> <p>This sets up <code>components.json</code>, your Tailwind config, and <code>lib/utils.ts</code> inside your existing project. From there, pull in the components you need for a chat screen:</p> <pre><code class="language-bash">npx shadcn@latest add button input textarea scroll-area avatar separator </code></pre> <p>Each <code>add</code> call copies real, readable component source into <code>components/ui/</code>, ready to import and edit like any other file in your project, with no compiled package to fight with later.</p> <p>If you'd rather not assemble the message list and composer from individual primitives, Shadcn Space also has ready-made <a href="https://shadcnspace.com/blocks/dashboard-ui/ai-chat"><strong>AI chat blocks</strong></a> that you can add directly:</p> <pre><code class="language-bash">npx shadcn@latest add @shadcn-space/ai-chat-01 npx shadcn@latest add @shadcn-space/ai-chat-03 </code></pre> <p><code>ai-chat-01</code> provides the conversation interface with a welcome screen, suggested prompts, a scrollable message thread, and a composer with attachments and a model picker.</p> <h3 id="heading-live-preview-of-ai-chat-01">Live Preview of AI Chat 01:</h3> <p><a href="https://shadcnspace.com/blocks/dashboard-ui/ai-chat"><img src="https://cdn.hashnode.com/uploads/covers/68b53a3d851476bd2ce87f12/6369c5c8-9ad3-4725-89d1-7e077581aa8b.webp" alt="Live Preview of AI Chat 01" style="display: block;" width="1920" height="1440" loading="lazy"></a></p> <p><code>ai-chat-03</code> provides the surrounding application shell with a collapsible sidebar, pinned and recent chats, search, and a topbar.</p> <h3 id="heading-live-preview-of-ai-chat-03">Live Preview of AI Chat 03:</h3> <p><a href="https://shadcnspace.com/blocks/dashboard-ui/ai-chat"><img src="https://cdn.hashnode.com/uploads/covers/68b53a3d851476bd2ce87f12/96cb68c3-85b8-405b-9f20-82fe2d378bb4.webp" alt="Live Preview of AI Chat 03" style="display: block;" width="1920" height="1440" loading="lazy"></a></p> <p>You can install either block separately, or install both if you want the complete chat layout without building the surrounding interface from scratch.</p> <p>Both blocks are Premium. If you want a free sidebar for your chat interface, the standard shadcn <code>sidebar-07</code> block is a lightweight, no-cost alternative:</p> <pre><code class="language-bash">npx shadcn@latest add sidebar-07 </code></pre> <h2 id="heading-step-5-build-the-streaming-api-route">Step 5: Build the Streaming API Route</h2> <p>Create <code>app/api/chat/route.ts</code>. This server-side piece talks to the model and streams the response back to the browser.</p> <pre><code class="language-typescript">// app/api/chat/route.ts import { createOpenAICompatible } from "@ai-sdk/openai-compatible"; import { convertToModelMessages, streamText, type UIMessage } from "ai"; const PROVIDERS: Record&lt;string, { baseURL: string; model: string }&gt; = { openai: { baseURL: "https://api.openai.com/v1", model: "gpt-4o-mini", }, gemini: { baseURL: "https://generativelanguage.googleapis.com/v1beta/openai", model: "gemini-2.5-flash", }, groq: { baseURL: "https://api.groq.com/openai/v1", model: "llama-3.3-70b-versatile", }, }; export async function POST(req: Request) { const { messages }: { messages: UIMessage[] } = await req.json(); const providerName = process.env.AI_PROVIDER?.trim().toLowerCase() ?? "openai"; const { baseURL, model } = PROVIDERS[providerName] ?? PROVIDERS.openai; const provider = createOpenAICompatible({ name: providerName, baseURL: process.env.AI_BASE_URL ?? baseURL, apiKey: process.env.AI_API_KEY, }); const result = streamText({ model: provider(process.env.AI_MODEL ?? model), system: "You are a concise, helpful assistant.", messages: convertToModelMessages(messages), }); return result.toUIMessageStreamResponse(); } </code></pre> <p>A few things worth calling out:</p> <ul> <li><p><code>createOpenAICompatible</code> gives you one provider instance that works against any OpenAI-style API. Swap <code>AI_PROVIDER</code> between <code>openai</code>, <code>gemini</code>, or <code>groq</code> and your route handler doesn't change at all.</p> </li> <li><p><code>convertToModelMessages</code> bridges the UI message format, which the client sends, with the format the model provider expects.</p> </li> <li><p><code>streamText</code> starts the model generating and returns a stream you can pipe straight to the client.</p> </li> <li><p><code>toUIMessageStreamResponse()</code> wraps that stream in a response your <code>useChat</code> hook on the client knows how to consume, token by token.</p> </li> </ul> <p>Set your provider and key in <code>.env</code>:</p> <pre><code class="language-bash"># .env AI_PROVIDER=openai AI_API_KEY= </code></pre> <p>If you don't have a key yet, you can still build the UI. Just have this route return a canned streamed response until you're ready to wire up a real provider. The client code below doesn't care where the stream comes from.</p> <h2 id="heading-step-6-wire-up-the-client-with-usechat">Step 6: Wire Up the Client With useChat</h2> <p>Now, let’s build the chat interface. Create a <code>components/chat.tsx</code> file:</p> <pre><code class="language-tsx">// components/chat.tsx "use client"; import { useState } from "react"; import { useChat } from "@ai-sdk/react"; import { DefaultChatTransport } from "ai"; import { Button } from "@/components/ui/button"; import { Textarea } from "@/components/ui/textarea"; import { ScrollArea } from "@/components/ui/scroll-area"; import { Avatar, AvatarFallback } from "@/components/ui/avatar"; import { cn } from "@/lib/utils"; export function Chat() { const [input, setInput] = useState(""); const { messages, sendMessage, status } = useChat({ transport: new DefaultChatTransport({ api: "/api/chat" }), }); const isLoading = status === "submitted" || status === "streaming"; const handleSubmit = (e: React.FormEvent) =&gt; { e.preventDefault(); if (!input.trim()) return; sendMessage({ text: input }); setInput(""); }; return ( &lt;div className="flex h-screen flex-col"&gt; &lt;ScrollArea className="flex-1 p-4"&gt; &lt;div className="mx-auto flex max-w-2xl flex-col gap-4"&gt; {messages.map((message) =&gt; ( &lt;div key={message.id} className={cn( "flex gap-3", message.role === "user" &amp;&amp; "justify-end" )} &gt; {message.role !== "user" &amp;&amp; ( &lt;Avatar className="h-8 w-8"&gt; &lt;AvatarFallback&gt;AI&lt;/AvatarFallback&gt; &lt;/Avatar&gt; )} &lt;div className={cn( "max-w-[75%] rounded-2xl px-4 py-2 text-sm", message.role === "user" ? "bg-primary text-primary-foreground" : "bg-muted" )} &gt; {message.parts.map((part, i) =&gt; part.type === "text" ? ( &lt;span key={i}&gt;{part.text}&lt;/span&gt; ) : null )} &lt;/div&gt; &lt;/div&gt; ))} &lt;/div&gt; &lt;/ScrollArea&gt; &lt;form onSubmit={handleSubmit} className="border-t p-4"&gt; &lt;div className="mx-auto flex max-w-2xl items-end gap-2"&gt; &lt;Textarea value={input} onChange={(e) =&gt; setInput(e.target.value)} placeholder="Message the assistant..." className="min-h-11 flex-1 resize-none" disabled={isLoading} /&gt; &lt;Button type="submit" disabled={isLoading || !input.trim()} &gt; Send &lt;/Button&gt; &lt;/div&gt; &lt;/form&gt; &lt;/div&gt; ); } </code></pre> <p>Drop <code>&lt;Chat /&gt;</code> into <code>app/page.tsx</code> and run <code>npm run dev</code>. You now have a working, streaming chat interface. Every message the model sends back appears word by word instead of all at once, and <code>status</code> gives you a clean way to disable the input while a response is in flight.</p> <p>Notice that <code>useChat</code> is doing a lot of quiet work here: it owns the message list, handles the streaming reassembly as chunks arrive, and manages the submitted, streaming, and ready lifecycle so you don't have to track any of that by yourself.</p> <h3 id="heading-live-preview">Live Preview:</h3> <p><a href="https://shadcnspace.com/blocks/dashboard-ui/ai-chat"><img src="https://cdn.hashnode.com/uploads/covers/68b53a3d851476bd2ce87f12/8fb95a2f-68c8-4449-bf74-5baa0bde59e1.webp" alt="Live Preview of Chat" style="display: block;" width="1920" height="1440" loading="lazy"></a></p> <h2 id="heading-step-7-let-the-model-call-tools">Step 7: Let the Model Call Tools</h2> <p>A chat box that can only talk is limiting. The AI SDK lets your model call real functions in your code, with a JSON schema describing the input it's allowed to send.</p> <p>Add this to your route handler, right next to the provider setup from Step 5:</p> <pre><code class="language-typescript">// app/api/chat/route.ts import { createOpenAICompatible } from "@ai-sdk/openai-compatible"; import { convertToModelMessages, jsonSchema, streamText, tool, type UIMessage, } from "ai"; export async function POST(req: Request) { const { messages }: { messages: UIMessage[] } = await req.json(); const provider = createOpenAICompatible({ name: "openai", baseURL: "https://api.openai.com/v1", apiKey: process.env.AI_API_KEY, }); const result = streamText({ model: provider("gpt-4o-mini"), messages: convertToModelMessages(messages), tools: { getWeather: tool({ description: "Get the current weather for a city", inputSchema: jsonSchema&lt;{ city: string }&gt;({ type: "object", properties: { city: { type: "string", description: "The city to get the weather for", }, }, required: ["city"], }), execute: async ({ city }) =&gt; { // Call a real weather API here in production return { city, temperature: 22, condition: "clear", }; }, }), }, }); return result.toUIMessageStreamResponse(); } </code></pre> <p>The model decides when to call <code>getWeather</code>, the SDK routes that call to your <code>execute</code> function, and the result streams back into the conversation as a message part. No extra plumbing is needed on the client beyond checking <code>part.type</code> for tool parts if you want to render them differently from plain text.</p> <h2 id="heading-step-8-prototype-the-ui-without-a-backend">Step 8: Prototype the UI Without a Backend</h2> <p>Here's a problem you'll hit constantly: you want to polish the chat UI, including spacing, animations, and how a reasoning block collapses, before your backend or API keys are even ready. Rebuilding that UI against a live model every time you tweak a pixel is slow and burns tokens.</p> <p>This is exactly what the <a href="https://ui.shadcn.com/docs/helpers/ai-sdk"><strong>shadcn AI SDK helper</strong></a> package solves. It lets you script out a fake conversation and stream it through the same <code>useChat</code> hook you're already using, with no server, model, or API key involved:</p> <pre><code class="language-bash">npm install @shadcn/helpers </code></pre> <pre><code class="language-tsx">import { createChat } from "@shadcn/helpers"; import { useChat } from "@ai-sdk/react"; const chat = createChat() .user("What changed in the last release?") .assistant("The release added keyboard shortcuts and faster search."); function ChatPreview() { const { messages } = useChat({ messages: chat.get(0), transport: chat.transport(), }); // render `messages` exactly like you would with a real backend } </code></pre> <p>It supports every part type the AI SDK understands, including reasoning, tool calls, files, and sources, and streams deterministically every time. This also makes it genuinely useful for writing reproducible demos or UI tests.</p> <p>You can build and refine your entire interface this way, then swap in the real <code>/api/chat</code> route the moment your backend is ready.</p> <h2 id="heading-turning-your-chat-into-a-full-product">Turning Your Chat Into a Full Product</h2> <p>A chat window rarely ships alone. Once yours works, you'll usually need a sidebar for past conversations, a settings panel for model selection, and maybe an admin view to see usage across your users. That's a different problem than streaming text. It's application shell and data-table territory.</p> <p>Rather than hand-rolling that shell, most teams reach for a pre-built admin layout. A ready-made <a href="https://shadcnspace.com/admin-dashboard"><strong>shadcn dashboard</strong></a>, like the one at Shadcn Space, ships with the layouts, data tables, charts, and navigation patterns an internal tool needs, so you're not rebuilding a sidebar and settings page from scratch just to give your chat feature a home.</p> <p>And if you'd rather skip building the chat screen itself too, that's a real option. Some teams start straight from a ready-made <a href="https://shadcnspace.com/templates/ai-chatbox"><strong>shadcn AI chat app</strong></a> template that already has a conversation sidebar, markdown and code rendering, and tool-call visualization built in. We'll come back to that at the end.</p> <h3 id="heading-live-preview-of-full-chat-app"><strong>Live Preview of full Chat App:</strong></h3> <p><a href="https://shadcnspace.com/templates/ai-chatbox"><img src="https://cdn.hashnode.com/uploads/covers/68b53a3d851476bd2ce87f12/80b2e6a0-4f2f-4223-a060-9e1e5172f0e3.webp" alt="Live Preview of full Chat App" style="display: block;" width="1920" height="1440" loading="lazy"></a></p> <h2 id="heading-speed-up-shadcn-development-with-an-mcp-server">Speed Up shadcn Development With an MCP Server</h2> <p>However you build your chat UI, there's a faster way to pull in components than copy-pasting from docs: an MCP (Model Context Protocol) server that gives your AI coding assistant live access to a component registry.</p> <p>The Shadcn MCP server connects tools like Claude Code, Cursor, and Windsurf directly to the <a href="https://shadcnspace.com/"><strong>Shadcn Space</strong></a> component catalog. Instead of you searching docs and pasting install commands, you just ask your assistant for what you need, such as "add a message bubble component with an avatar and timestamp", and it pulls real, current component definitions instead of guessing from outdated training data.</p> <p>Setting it up is a one-line command for Claude Code:</p> <pre><code class="language-bash">claude mcp add shadcnspace-mcp -- npx -y shadcnspace-mcp@latest </code></pre> <p>Other editors just need the same command dropped into their MCP config file, for example <code>.cursor/mcp.json</code> in Cursor. The full <a href="https://shadcnspace.com/docs/getting-started/mcp-server-docs"><strong>getting started guide for the MCP server</strong></a> walks through configuration for each supported editor, and the <a href="https://shadcnspace.com/mcp"><strong>Shadcn MCP</strong></a> page covers exactly what it can search, install, and generate once it's connected.</p> <p>If you'd rather watch the setup than read it, there's a short walkthrough that covers the same steps end to end.</p> <div class="embed-wrapper"><iframe width="560" height="315" src="https://www.youtube.com/embed/ymTlzbkvvPk" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div> <h2 id="heading-a-few-things-to-handle-before-you-ship">A Few Things to Handle Before You Ship</h2> <p>The tutorial version above is intentionally minimal. Before this goes anywhere near production, add:</p> <ul> <li><p><strong>Rate limiting</strong> on your <code>/api/chat</code> route. A chat endpoint with no limits is an easy way to run up a very large model bill.</p> </li> <li><p><strong>Abort handling</strong> so users can stop a response mid-stream, which <code>useChat</code> supports out of the box via its <code>stop()</code> function.</p> </li> <li><p><strong>Error boundaries</strong> around the chat component, since a dropped stream or provider outage shouldn't crash the whole page.</p> </li> <li><p><strong>Auth</strong>, if responses or conversation history should be scoped to a specific user.</p> </li> </ul> <p>None of these are exotic. They're the same production basics you'd apply to any API route. Chat endpoints just make it easier to forget them because the happy path looks so smooth in development.</p> <h2 id="heading-skip-the-boilerplate-with-a-ready-made-template">Skip the Boilerplate With a Ready-Made Template</h2> <p>Everything above gets you a real, working chat interface, but it's the tutorial version. A production chat product usually also needs a conversation sidebar, project grouping, markdown and syntax-highlighted code blocks, a reasoning panel, voice input, and a settings screen for switching models. Building all of that from scratch can be a multi-week job on its own.</p> <p>If you'd rather not build that shell yourself, it's worth checking out the <a href="https://shadcnspace.com/templates/ai-chatbox"><strong>shadcn AI chat app</strong></a> template at Shadcn Space. It's built on the same foundation covered in this article (Next.js, the Vercel AI SDK, and shadcn ui) but ships with the sidebar, reasoning and tool-call UI, file attachments, and multi-provider model switching already wired up. You set <code>AI_PROVIDER</code> and <code>AI_API_KEY</code> and you're talking to a real model through a finished interface.</p> <p>You can check out the <a href="https://shadcnspace.com/templates/preview/ai-chatbox-nextjs"><strong>live demo</strong></a> to see exactly how the sidebar, streaming, and tool calls behave before deciding whether to build it yourself or start from the template.</p> <h2 id="heading-wrapping-up">Wrapping Up</h2> <p>You now have a chat interface that streams real responses, calls tools, and is built entirely on components you own and can freely edit. And for an AI product, all this matters more than it sounds like it should. The Vercel AI SDK handles the hard streaming and model logic while shadcn/ui gives you full control over how that logic actually looks on screen.</p> <p>From here, the natural next steps are hooking up a real provider, adding the production basics above, and deciding whether to keep extending your own UI or lean on a finished template to get the surrounding product built faster. Either way, you now understand what's actually happening under the hood, which makes both paths a lot easier.</p> <h2 id="heading-resources"><strong>Resources</strong></h2> <ul> <li><p><a href="https://vercel.com/docs/ai-sdk"><strong>Vercel AI SDK</strong></a></p> </li> <li><p><a href="https://vercel.com/docs/ai-sdk"><strong>Shadcn AI SDK</strong></a></p> </li> <li><p><a href="https://shadcnspace.com/admin-dashboard"><strong>shadcn dashboard</strong></a></p> </li> <li><p><a href="https://shadcnspace.com/"><strong>Shadcn ui</strong></a></p> </li> <li><p><a href="https://shadcnspace.com/templates/ai-chatbox"><strong>shadcn AI chat app</strong></a></p> </li> </ul> <p>I wrote this article with the help of Ashutosh Rada (Sr. Frontend Developer). <a href="https://www.linkedin.com/in/ashutosh-rada/">Connect on LinkedIn</a>.</p>

How to apply

  1. 1 Read the full details above and confirm you meet the eligibility criteria.
  2. 2 Prepare your documents — an updated CV, and any cover letter, proposal or certificates required.
  3. 3 Click Apply on official site to complete your application on Vaibhav Gupta’s official page.
  4. 4 Submit as early as possible — many close once filled.
Apply on official site

Sourced from freecodecamp. Always verify details on the official website. Opportunihub never charges you to apply.

Frequently asked questions

How do I apply for How to Build an AI Chat App Interface With the Vercel AI SDK and Shadcn/ui?

Review the full details and eligibility on this page, prepare your documents, then use the “Apply on official site” button to complete your application on Vaibhav Gupta’s official page.

Is this opportunity remote or location-based?

This opportunity is remote-friendly and open to applicants who can work from anywhere.

Is How to Build an AI Chat App Interface With the Vercel AI SDK and Shadcn/ui free to apply for?

Opportunihub lists this Course for free. Legitimate Courses do not ask for payment to apply — never pay a fee to submit an application.