React AI Prompt Input
ChatGPT-style input with auto-resize and model selector. React component with TypeScript, keyboard shortcuts, and shadcn/ui for AI chat.
Powered by
Trying to implement AI Elements?
Join our Discord community for help from other developers.
Auto-resizing textarea with toolbar for AI prompts in conversational AI applications. This free open source React component handles Enter submits, Shift+Enter adds new lines, and includes model selection with proper form handling for Next.js projects.
Auto-resizing prompt input with toolbar
Textarea with submit button and model selection:
Automatically adjusts height based on content in React applications, handles Enter/Shift+Enter shortcuts correctly in TypeScript components, and provides a flexible toolbar system for JavaScript frameworks. Integrates seamlessly with Vercel AI SDK status.
Installation
npx shadcn@latest add https://www.shadcn.io/registry/ai.json
npx shadcn@latest add https://www.shadcn.io/registry/ai.json
pnpm dlx shadcn@latest add https://www.shadcn.io/registry/ai.json
bunx shadcn@latest add https://www.shadcn.io/registry/ai.json
Usage
import {
PromptInput,
PromptInputTextarea,
PromptInputToolbar,
PromptInputSubmit,
} from "@/components/ai/prompt-input";
<PromptInput onSubmit={() => {}}>
<PromptInputTextarea
value={input}
onChange={(e) => setInput(e.currentTarget.value)}
placeholder="Type your message..."
/>
<PromptInputToolbar>
<PromptInputSubmit disabled={!input.trim()} />
</PromptInputToolbar>
</PromptInput>;
Why not just use a regular textarea?
Fixed-height textareas cut off AI prompts in React applications. Users write long, complex prompts and need to see what they're typing without scrolling in a tiny box in Next.js projects.
Enter/Shift+Enter behavior has to be right in JavaScript implementations. Users expect Enter to submit, Shift+Enter for new lines in TypeScript components. Get this wrong and your chat feels broken.
Usage with Vercel AI SDK
Complete chat interface using Vercel AI SDK with model selection and status integration in React applications:
"use client";
import {
PromptInput,
PromptInputTextarea,
PromptInputToolbar,
PromptInputTools,
PromptInputButton,
PromptInputSubmit,
PromptInputModelSelect,
PromptInputModelSelectTrigger,
PromptInputModelSelectContent,
PromptInputModelSelectItem,
PromptInputModelSelectValue,
} from "@/components/ai/prompt-input";
import {
Conversation,
ConversationContent,
} from "@/components/ai/conversation";
import { Message, MessageContent } from "@/components/ai/message";
import { useChat } from "@ai-sdk/react";
import { useState } from "react";
import { MicIcon, PaperclipIcon } from "lucide-react";
const models = [
{ id: "gpt-4o", name: "GPT-4o" },
{ id: "claude-3-5-sonnet-20241022", name: "Claude 3.5 Sonnet" },
];
export default function Chat() {
const [input, setInput] = useState("");
const [selectedModel, setSelectedModel] = useState(models[0].id);
const { messages, append, status } = useChat({
body: { model: selectedModel },
});
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (input.trim()) {
append({ role: "user", content: input });
setInput("");
}
};
return (
<div className="flex flex-col h-full max-w-4xl mx-auto">
<Conversation>
<ConversationContent>
{messages.map((message) => (
<Message from={message.role} key={message.id}>
<MessageContent>{message.content}</MessageContent>
</Message>
))}
</ConversationContent>
</Conversation>
<PromptInput onSubmit={handleSubmit}>
<PromptInputTextarea
value={input}
onChange={(e) => setInput(e.currentTarget.value)}
placeholder="Type your message..."
/>
<PromptInputToolbar>
<PromptInputTools>
<PromptInputButton>
<PaperclipIcon size={16} />
</PromptInputButton>
<PromptInputButton>
<MicIcon size={16} />
<span>Voice</span>
</PromptInputButton>
<PromptInputModelSelect
value={selectedModel}
onValueChange={setSelectedModel}
>
<PromptInputModelSelectTrigger>
<PromptInputModelSelectValue />
</PromptInputModelSelectTrigger>
<PromptInputModelSelectContent>
{models.map((model) => (
<PromptInputModelSelectItem key={model.id} value={model.id}>
{model.name}
</PromptInputModelSelectItem>
))}
</PromptInputModelSelectContent>
</PromptInputModelSelect>
</PromptInputTools>
<PromptInputSubmit disabled={!input.trim()} status={status} />
</PromptInputToolbar>
</PromptInput>
</div>
);
}
Backend route handling model selection:
// app/api/chat/route.ts
import { streamText, convertToModelMessages } from "ai";
export async function POST(req: Request) {
const { messages, model } = await req.json();
const result = streamText({
model: model || "openai/gpt-4o",
messages: convertToModelMessages(messages),
});
return result.toUIMessageStreamResponse();
}
Features
- Auto-resizing textarea with configurable min/max height (prevents layout jumps) in React applications
- Keyboard shortcuts that work like users expect (Enter to submit, Shift+Enter for new lines) in TypeScript components
- Submit button states that integrate with Vercel AI SDK status in Next.js projects
- Flexible toolbar system for custom actions and model selection in JavaScript frameworks
- Form validation that prevents empty submissions
- Proper focus management for continuous conversation
- Works with any Vercel AI SDK setup and AI chat applications
- Free open source component designed for conversational AI interfaces and prompt-based applications
API Reference
PromptInput
Form container for the prompt input system.
Prop | Type | Description |
---|---|---|
onSubmit | FormEventHandler | Form submission handler |
className | string | Additional CSS classes |
...props | HTMLAttributes<HTMLFormElement> | Standard form attributes |
PromptInputTextarea
Auto-resizing textarea with keyboard shortcuts.
Prop | Type | Default | Description |
---|---|---|---|
placeholder | string | "What would you like to know?" | Placeholder text |
minHeight | number | 48 | Minimum height in pixels |
maxHeight | number | 164 | Maximum height in pixels |
className | string | - | Additional CSS classes |
...props | ComponentProps<typeof Textarea> | - | Textarea component props |
PromptInputToolbar
Container for toolbar actions and submit button.
Prop | Type | Description |
---|---|---|
className | string | Additional CSS classes |
...props | HTMLAttributes<HTMLDivElement> | Standard div attributes |
PromptInputTools
Container for tool buttons and controls.
Prop | Type | Description |
---|---|---|
className | string | Additional CSS classes |
...props | HTMLAttributes<HTMLDivElement> | Standard div attributes |
PromptInputButton
Toolbar button with automatic sizing.
Prop | Type | Default | Description |
---|---|---|---|
variant | ButtonVariant | "ghost" | Button style variant |
size | ButtonSize | "icon" (auto) | Button size |
className | string | - | Additional CSS classes |
...props | ComponentProps<typeof Button> | - | Button component props |
PromptInputSubmit
Submit button with status indicators.
Prop | Type | Default | Description |
---|---|---|---|
status | ChatStatus | - | Current chat status for icon display |
variant | ButtonVariant | "default" | Button style variant |
size | ButtonSize | "icon" | Button size |
className | string | - | Additional CSS classes |
...props | ComponentProps<typeof Button> | - | Button component props |
Model Selection Components
All model selection components forward props to their underlying shadcn/ui Select components:
PromptInputModelSelect
- Select root componentPromptInputModelSelectTrigger
- Select trigger with custom stylingPromptInputModelSelectContent
- Select dropdown contentPromptInputModelSelectItem
- Individual model optionPromptInputModelSelectValue
- Selected value display
Keyboard interactions
Key | Description |
---|---|
Enter | Submit form (when not in composition) |
Shift + Enter | Insert new line |
Tab | Navigate between toolbar elements |
Escape | Blur textarea |
Prompt input gotchas
Unconstrained auto-resize breaks layouts: Set reasonable minHeight/maxHeight in React applications. Long AI prompts can grow to 500+ lines without constraints in TypeScript components.
Mobile keyboard inconsistency: Enter behavior varies across mobile keyboards in JavaScript implementations. Test on real devices, not just desktop browsers in Next.js projects.
Empty input submission: Users will hit Enter on empty textareas in React applications. Validate and disable submit for empty/whitespace-only input.
Model selection persistence: Consider saving user's model preference to localStorage in TypeScript projects. They don't want to reselect every session.
Focus management after submit: Return focus to the textarea after successful submission in React components so users can continue the conversation.
Integration with other components
Works great with Conversation for scrolling chat interfaces in React applications. Combine with Message for complete chat UI in Next.js projects. Add Actions for message interactions like copy, regenerate, or edit. This free open source component integrates seamlessly with modern JavaScript frameworks.
Questions developers actually ask
React AI Message
Chat messages with avatars that distinguish user from AI. React component for clean conversation displays with TypeScript and shadcn/ui.
React AI Reasoning
Show AI thinking process like Claude's "thinking" blocks. Collapsible React component with TypeScript and shadcn/ui for transparent AI.