Components / AI Chat Interfaces
AI Chat Input Bar
A modern chat input bar with send button, attachment support, and auto-resize textarea for AI conversation interfaces.
Components / AI Chat Interfaces
A modern chat input bar with send button, attachment support, and auto-resize textarea for AI conversation interfaces.
Install the core libraries required for this component.
npm install reactAdd the necessary Shadcn UI primitives.
npx shadcn-ui@latest add button textarea selectimport { Button } from "@/components/ui/button";
import { Textarea } from "@/components/ui/textarea";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { useState, useRef, useEffect } from "react";
export default function AIChatInput01() {
const [message, setMessage] = useState("");
const [selectedModel, setSelectedModel] = useState("chatgpt");
const [searchEnabled, setSearchEnabled] = useState(false);
const textareaRef = useRef<HTMLTextAreaElement>(null);
// Auto-resize textarea
useEffect(() => {
if (textareaRef.current) {
textareaRef.current.style.height = "0px";
textareaRef.current.style.height = textareaRef.current.scrollHeight + "px";
}
}, [message]);
const handleSend = () => {
if (!message.trim()) return;
console.log("Send message:", message, "Model:", selectedModel, "Search:", searchEnabled);
setMessage("");
};
const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
if (e.key === "Enter" && !e.shiftKey) {
e.preventDefault();
handleSend();
}
};
return (
<div className="flex flex-col gap-2">
{/* Top controls: model selection + search toggle */}
<div className="flex items-center gap-2">
<Select onValueChange={(val) => setSelectedModel(val)} defaultValue={selectedModel}>
<SelectTrigger className="w-[150px]">
<SelectValue placeholder="Select model" />
</SelectTrigger>
<SelectContent>
<SelectItem value="chatgpt">ChatGPT</SelectItem>
<SelectItem value="gpt4">GPT-4</SelectItem>
<SelectItem value="custom-llm">Custom LLM</SelectItem>
</SelectContent>
</Select>
<Button
variant={searchEnabled ? "default" : "outline"}
onClick={() => setSearchEnabled((prev) => !prev)}
>
{searchEnabled ? "Search Enabled" : "Search"}
</Button>
</div>
{/* Text input + send */}
<div className="flex items-end gap-2">
<Textarea
ref={textareaRef}
value={message}
onChange={(e) => setMessage(e.target.value)}
onKeyDown={handleKeyDown}
placeholder="Type your message..."
className="resize-none grow overflow-hidden p-2"
rows={1}
/>
<Button onClick={handleSend} className="flex-shrink-0">
Send
</Button>
</div>
</div>
);
} import { Button } from "@/components/ui/button";
import { Textarea } from "@/components/ui/textarea";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { useState, useRef, useEffect } from "react";
export default function AIChatInput01() {
const [message, setMessage] = useState("");
const [selectedModel, setSelectedModel] = useState("chatgpt");
const [searchEnabled, setSearchEnabled] = useState(false);
const textareaRef = useRef<HTMLTextAreaElement>(null);
// Auto-resize textarea
useEffect(() => {
if (textareaRef.current) {
textareaRef.current.style.height = "0px";
textareaRef.current.style.height = textareaRef.current.scrollHeight + "px";
}
}, [message]);
const handleSend = () => {
if (!message.trim()) return;
console.log("Send message:", message, "Model:", selectedModel, "Search:", searchEnabled);
setMessage("");
};
const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
if (e.key === "Enter" && !e.shiftKey) {
e.preventDefault();
handleSend();
}
};
return (
<div className="flex flex-col gap-2">
{/* Top controls: model selection + search toggle */}
<div className="flex items-center gap-2">
<Select onValueChange={(val) => setSelectedModel(val)} defaultValue={selectedModel}>
<SelectTrigger className="w-[150px]">
<SelectValue placeholder="Select model" />
</SelectTrigger>
<SelectContent>
<SelectItem value="chatgpt">ChatGPT</SelectItem>
<SelectItem value="gpt4">GPT-4</SelectItem>
<SelectItem value="custom-llm">Custom LLM</SelectItem>
</SelectContent>
</Select>
<Button
variant={searchEnabled ? "default" : "outline"}
onClick={() => setSearchEnabled((prev) => !prev)}
>
{searchEnabled ? "Search Enabled" : "Search"}
</Button>
</div>
{/* Text input + send */}
<div className="flex items-end gap-2">
<Textarea
ref={textareaRef}
value={message}
onChange={(e) => setMessage(e.target.value)}
onKeyDown={handleKeyDown}
placeholder="Type your message..."
className="resize-none grow overflow-hidden p-2"
rows={1}
/>
<Button onClick={handleSend} className="flex-shrink-0">
Send
</Button>
</div>
</div>
);
}
Primitives required in your
@/components/ui
directory.
| Component | Path |
|---|---|
| button | @/components/ui/button |
| textarea | @/components/ui/textarea |
| select | @/components/ui/select |
Internal functions used to handle component logic.
| Function | Parameters |
|---|---|
| handleSend() | None |
| handleKeyDown() | e: React.KeyboardEvent<HTMLTextAreaElement> |
| AIChatInput01() | None |
React state variables managed within this component.
| Variable | Initial Value |
|---|---|
| message | "" |
| selectedModel | "chatgpt" |
| searchEnabled | false |
All variable declarations found in this component.
| Name | Kind | Value |
|---|---|---|
| textareaRef | | useRef<HTMLTextAreaElement>(null) |
Every JSX/HTML tag used in this component, with usage count and source.
| Tag | Count | Type | Source |
|---|---|---|---|
| <HTMLTextAreaElement> | 2× | | Local / Inline |
| <SelectContent> | 1× | | @/components/ui/select |
| <SelectItem> | 3× | | @/components/ui/select |
| <SelectTrigger> | 1× | | @/components/ui/select |
| <SelectValue> | 1× | | @/components/ui/select |
| <Button> | 2× | | Native HTML |
| <div> | 3× | | Native HTML |
| <Select> | 1× | | Native HTML |
| <Textarea> | 1× | | Native HTML |