Hi. Ask me anything about Club Med. I'm here to help you find the right information quickly.
Getting Started
Components
- Advanced Toast
- ArrowButton
- Arrows
- Avatar
- Backdrop
- Basic Toast
- Breadcrumb
- Button
- CardBackground
- Card
- Carousel
- ChatButton
- ChatInput
- ChatMessage
- ChatTypingIndicator
- ChatWindow
- CheckboxSelect
- Checkbox
- Checkboxes
- Chip
- ChoiceExpander
- Clickable
- Date Field
- Dropdown
- ElasticHeight
- ExpandableCard
- Filter
- Form Control
- Form Label
- Frame
- HamburgerIcon
- Heading
- Image
- Link
- Loader
- Number Field
- Pagination
- Password
- Phone Field
- Popin
- Portal
- Prose
- Radio Group
- Radio
- Range
- Scrollbar
- Select
- SidebarLayout
- SliderFrame
- Spinner
- Switch
- Tabs
- Tag
- TextField
- Tooltip
- ValidationMessage
Ask me a question
My son is 14 years old, and I would like to find activities for him during our stay.
'use client';
import { useState } from 'react';
import { ChatWindow } from '@/ui/ChatWindow';
import type { ChatWindowMessage } from '@/ui/ChatWindow';
export function ChatWindowDemo() {
const [messages, setMessages] = useState<ChatWindowMessage[]>([
{
id: '1',
sender: 'assistant',
content:
"Hi. Ask me anything about Club Med. I'm here to help you find the right information quickly.",
},
{
id: '2',
sender: 'user',
content:
'My son is 14 years old, and I would like to find activities for him during our stay.',
},
]);
const [inputValue, setInputValue] = useState('');
const [isTyping, setIsTyping] = useState(false);
function handleSubmit() {
if (!inputValue.trim()) return;
const userMsg: ChatWindowMessage = {
id: Date.now().toString(),
sender: 'user',
content: inputValue,
};
setMessages((prev) => [...prev, userMsg]);
setInputValue('');
setIsTyping(true);
setTimeout(() => {
setIsTyping(false);
setMessages((prev) => [
...prev,
{
id: (Date.now() + 1).toString(),
sender: 'assistant',
content: 'Let me look into that for you…',
},
]);
}, 2000);
}
return (
<ChatWindow
messages={messages}
inputValue={inputValue}
isTyping={isTyping}
onInputChange={setInputValue}
onSubmit={handleSubmit}
onClose={() => {}}
onAudioClick={() => {}}
className="w-380 h-660"
/>
);
}
Installation
npx shadcn@latest add https://develop.trident-ui.pro.clubmed/r/chat-window.json
Usage
import { ChatWindow } from '@/ui/ChatWindow';
import type { ChatWindowMessage } from '@/ui/ChatWindow';
import { useState } from 'react';
export function Component() {
const [messages, setMessages] = useState<ChatWindowMessage[]>([]);
const [inputValue, setInputValue] = useState('');
const [isTyping, setIsTyping] = useState(false);
function handleSubmit() {
if (!inputValue.trim()) return;
setMessages((prev) => [
...prev,
{ id: Date.now().toString(), sender: 'user', content: inputValue },
]);
setInputValue('');
// Trigger your AI call here, then set isTyping accordingly
}
return (
<ChatWindow
messages={messages}
inputValue={inputValue}
isTyping={isTyping}
onInputChange={setInputValue}
onSubmit={handleSubmit}
onClose={() => console.log('close')}
onAudioClick={() => console.log('audio')}
/>
);
}API Reference
ChatWindow
| Prop | Type | Default | Description |
|---|---|---|---|
messages | ChatWindowMessage[] | — | Required. Ordered list of messages to display |
inputValue | string | — | Required. Controlled value of the text input |
onInputChange | (value: string) => void | — | Required. Called on every keystroke in the input |
onSubmit | () => void | — | Required. Called when the user submits a message |
title | string | "Ask me a question" | Heading displayed in the intro header |
greeting | string | undefined | Optional static greeting text shown above the message list |
inputPlaceholder | string | "Ask a question?" | Placeholder text for the input field |
isTyping | boolean | false | When true, shows the animated typing indicator |
onClose | () => void | undefined | When provided, renders a close button below the panel |
onAudioClick | () => void | undefined | When provided, renders an audio/attachment button in the input |
logo | ReactNode | undefined | Custom logo node; defaults to a Sparkles icon button |
className | string | undefined | Additional CSS classes on the outer wrapper |
ChatWindowMessage
interface ChatWindowMessage {
id: string;
sender: 'assistant' | 'user';
content: string;
}Notes
- The component is entirely controlled from the outside — all state (messages, input value, typing indicator) is managed by the parent.
- The message list uses
role="log"witharia-live="polite"so screen readers announce new messages automatically. isTypingshould be set totruewhile waiting for the AI response, thenfalsewhen the response arrives.- Built from sub-components:
ChatMessage,ChatTypingIndicator, andChatInput.