AI
Chat UI
A full-featured chat interface with animated message bubbles, streaming support, copy-to-clipboard, and a built-in textarea input. Plug in any AI backend via the onSend prop.
Demo
Benflux Assistant
Online
Hi! I'm your AI assistant. How can I help you today?
01:24 AM
Can you explain what Benflux UI is?
01:24 AM
Benflux UI is a modern React component library built with Tailwind CSS and Framer Motion. It provides 80+ accessible, animated components for building beautiful interfaces — from simple buttons to complex data tables and AI chat interfaces like this one!
01:24 AM
Press Enter to send, Shift+Enter for new line
Installation
npx benflux-ui add chat-uiImport
import { ChatUI } from "@benflux-ui/react"
import type { ChatMessage } from "@benflux-ui/react"Basic usage
"use client"
import * as React from "react"
import { ChatUI } from "@benflux-ui/react"
import type { ChatMessage } from "@benflux-ui/react"
export function MyChatBot() {
const [messages, setMessages] = React.useState<ChatMessage[]>([
{
id: "1",
role: "assistant",
content: "Hi! How can I help you today?",
timestamp: new Date(),
status: "sent",
},
])
const [isLoading, setIsLoading] = React.useState(false)
const handleSend = async (text: string) => {
// Add user message
setMessages((prev) => [
...prev,
{ id: Date.now().toString(), role: "user", content: text, timestamp: new Date(), status: "sent" },
])
setIsLoading(true)
// Call your AI backend
const reply = await fetch("/api/chat", {
method: "POST",
body: JSON.stringify({ message: text }),
}).then((r) => r.text())
setMessages((prev) => [
...prev,
{ id: Date.now().toString(), role: "assistant", content: reply, timestamp: new Date(), status: "sent" },
])
setIsLoading(false)
}
return (
<div className="h-[600px]">
<ChatUI
messages={messages}
onSend={handleSend}
isLoading={isLoading}
agentName="My Assistant"
placeholder="Ask anything..."
/>
</div>
)
}Streaming responses
Set status: "streaming" on a message to show the animated cursor and reveal text progressively. Update the message content in place as tokens arrive.
const handleSend = async (text: string) => {
const streamId = Date.now().toString()
// Add user message
setMessages((prev) => [
...prev,
{ id: Date.now().toString(), role: "user", content: text, status: "sent" },
])
// Add empty streaming message
setMessages((prev) => [
...prev,
{ id: streamId, role: "assistant", content: "", status: "streaming" },
])
setIsLoading(true)
// Stream from your API
const res = await fetch("/api/chat/stream", { method: "POST", body: text })
const reader = res.body!.getReader()
const decoder = new TextDecoder()
let full = ""
while (true) {
const { done, value } = await reader.read()
if (done) break
full += decoder.decode(value)
setMessages((prev) =>
prev.map((m) => (m.id === streamId ? { ...m, content: full } : m))
)
}
// Mark as done
setMessages((prev) =>
prev.map((m) => (m.id === streamId ? { ...m, status: "sent" } : m))
)
setIsLoading(false)
}Props
| Prop | Type | Default | Description |
|---|---|---|---|
| messages* | ChatMessage[] | — | Array of messages to display in the chat |
| onSend* | (msg: string) => void | — | Called when the user submits a message |
| isLoading | boolean | false | Shows the animated loading bubble while awaiting a response |
| placeholder | string | "Ask anything..." | Textarea placeholder text |
| agentName | string | "AI Assistant" | Name shown in the chat header |
| systemAvatar | string | — | URL for the assistant avatar image |
| userAvatar | string | — | URL for the user avatar image |
ChatMessage type
interface ChatMessage {
id: string
role: "user" | "assistant" | "system"
content: string
timestamp?: Date
status?: "sending" | "sent" | "error" | "streaming"
}