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-ui

Import

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

PropTypeDefaultDescription
messages*ChatMessage[]Array of messages to display in the chat
onSend*(msg: string) => voidCalled when the user submits a message
isLoadingbooleanfalseShows the animated loading bubble while awaiting a response
placeholderstring"Ask anything..."Textarea placeholder text
agentNamestring"AI Assistant"Name shown in the chat header
systemAvatarstringURL for the assistant avatar image
userAvatarstringURL for the user avatar image

ChatMessage type

interface ChatMessage {
  id: string
  role: "user" | "assistant" | "system"
  content: string
  timestamp?: Date
  status?: "sending" | "sent" | "error" | "streaming"
}