Installation
pnpm dlx shadcn@latest add https://deltacomponents.dev/r/chat.jsonUsage
import { Chat } from "@/components/chat"<Chat onMessage={handleMessage} allowFileUpload={true} />Examples
Chat with Previous Messages
Can you explain how to use React hooks effectively?
React Hooks Best Practices
React hooks are a powerful feature that let you use state and other React features without writing classes. Here are some tips for using them effectively:
Rules of Hooks
- Only call hooks at the top level of your component or custom hooks
- Don't call hooks inside loops, conditions, or nested functions
Common Hooks
- useState: For local component state
- useEffect: For side effects like data fetching
- useContext: For consuming context
- useReducer: For complex state logic
- useCallback: For memoizing functions
- useMemo: For memoizing values
Example of useState and useEffect
Would you like me to explain any specific hook in more detail?
Yes, could you explain useCallback and useMemo in more detail? When should I use one over the other?
I'm particularly interested in understanding the performance implications of useCallback and useMemo. Could you break down when each is most appropriate?
Thanks for the overview! Could you dive deeper into the specific use cases where useCallback and useMemo make the biggest difference in React applications?
The user is asking for a detailed explanation of useCallback and useMemo. I should provide a clear and concise explanation of each hook's purpose and how they differ.
The useCallback hook is used to memoize functions to prevent unnecessary re-renders of child components that receive functions as props.
The useMemo hook is used to memoize values to avoid expensive recalculations on every render.
Both hooks help with performance optimization, but they serve different purposes.
useCallback vs useMemo
Both hooks help with performance optimization, but they serve different purposes:
useCallback
useCallback memoizes functions to prevent unnecessary re-renders of child components that receive functions as props.
useMemo
useMemo memoizes values to avoid expensive recalculations on every render.
When to use which?
-
Use useCallback when:
- Passing callbacks to optimized child components that rely on reference equality
- Working with event handlers that you pass to child components
-
Use useMemo when:
- You have computationally expensive calculations
- You want to avoid recreating objects that are used as dependencies for other hooks
Performance Note
Don't overuse these hooks! They come with their own overhead. Only use them when you have identified a genuine performance issue.
Non-Streaming Chat
For use cases where LLM streaming doesn't happen and you receive the whole message in one go. Shows a loader until the message is received and then displays the complete message.
Chat with Shimmer Effect
Demonstrates the use of the shimmer component for loading states while AI processes requests.
Chat with Reasoning
Shows how to integrate the reasoning component to display AI thinking processes before responses.
API Reference
Chat
| Prop | Type | Default | Description |
|---|---|---|---|
allowFileUpload | boolean | false | Enable file upload functionality |
userAvatar | string | - | Custom user avatar URL |
models | Model[] | [{id: 'gpt-4', name: 'GPT-4', model: 'GPT-4o'}, {id: 'claude', name: 'Claude', model: 'Claude 3.5'}] | Available AI models |
onMessage | (message: string, modelId: string) => Promise<string> | - | Message handler function |
children | ReactNode | - | Custom content in chat options area |
className | string | - | Additional CSS classes |
Individual Components
The chat component is composed of several modular components that can be used independently:
ChatMessages- Message display containerChatUserMessage- User message bubbleChatAssistantMessage- AI response message bubbleChatPromptInput- Input area with model selectionChatResponse- Streamdown markdown rendererChatStreamingResponse- Streaming text effectChatReasoning- "Thinking..." shimmer animationChatSendButton- Standalone send button componentChatModelSelector- Model selection dropdownChatOptions- Container for custom content before input
ChatSendButton
| Prop | Type | Default | Description |
|---|---|---|---|
isDisabled | boolean | - | Whether the button is disabled |
isLoading | boolean | - | Loading state indicator |
className | string | - | Custom CSS classes |
ChatModelSelector
| Prop | Type | Default | Description |
|---|---|---|---|
selectedModel | string | - | Currently selected model ID |
onModelChange | (modelId: string) => void | - | Model selection callback |
models | Model[] | - | Available models array |
className | string | - | Custom CSS classes |
ChatOptions
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | - | Content to display in options area |
className | string | - | Custom CSS classes |
Styling with Data Attributes
The chat component uses data attributes for easy CSS targeting without prop drilling:
| Data Attribute | Target Element | Description |
|---|---|---|
[data-chat="send-button"] | Send button | Style the submit button |
[data-chat="model-selector"] | Model selector dropdown | Style the model selection button |
[data-chat="options"] | Options container | Style the options area |
[data-chat="prompt-input"] | Prompt input container | Style the entire input area |
[data-chat="textarea"] | Textarea element | Style the text input field |
Example CSS
/* Custom send button styling */
[data-chat="send-button"] {
background: linear-gradient(45deg, #ff6b6b, #ee5a52);
border-radius: 50%;
}
/* Custom textarea styling */
[data-chat="textarea"] {
background-color: #f8f9fa;
border: 2px solid #e9ecef;
font-family: "Inter", sans-serif;
}
/* Custom model selector styling */
[data-chat="model-selector"] {
background-color: #495057;
color: white;
border-radius: 8px;
}
/* Custom options area */
[data-chat="options"] {
padding: 16px;
background-color: #f1f3f4;
border-radius: 12px;
}Features
- Streaming Responses: Real-time text streaming with typewriter effect
- File Upload: Drag & drop or click to upload files with preview
- Model Selection: Dropdown to choose between different AI models
- Rich Markdown: Full support for code blocks, tables, math, and more
- Responsive Design: Works on desktop and mobile devices
- Customizable: Modular components for flexible integration
- TypeScript: Full type safety and IntelliSense support
Enhanced Scrollbar UI/UX
For a better scrollbar experience in your chat interface, add the thin-scrollbar utility class to your global CSS:
@utility thin-scrollbar {
scrollbar-width: thin;
scrollbar-color: rgb(163 163 163) transparent;
&::-webkit-scrollbar {
width: 2px;
height: 2px;
}
&::-webkit-scrollbar-track {
background: transparent;
}
&::-webkit-scrollbar-thumb {
background-color: rgb(163 163 163);
border-radius: 2px;
}
&::-webkit-scrollbar-thumb:hover {
background-color: rgb(115 115 115);
}
@variant dark {
scrollbar-color: rgb(82 82 82) transparent;
&::-webkit-scrollbar-thumb {
background-color: rgb(82 82 82);
}
&::-webkit-scrollbar-thumb:hover {
background-color: rgb(115 115 115);
}
}
}This utility provides:
- Ultra-thin 2px scrollbars for a minimal, modern look
- Neutral gray colors that work well with any theme
- Dark mode support with appropriate contrast
- Smooth hover interactions
- Cross-browser compatibility
The ChatContainer component automatically applies this styling when the utility is available.
Examples
Custom Message Handler
const handleMessage = async (message: string, modelId: string) => {
const response = await fetch("/api/chat", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ message, modelId }),
})
return response.text()
}
;<Chat onMessage={handleMessage} />With Custom Models
const customModels = [
{ id: 'gpt-4', name: 'GPT-4', model: 'GPT-4o' },
{ id: 'claude', name: 'Claude', model: 'Claude 3.5 Sonnet' },
{ id: 'gemini', name: 'Gemini', model: 'Gemini Pro' }
]
<Chat models={customModels} />With File Upload
<Chat allowFileUpload={true} onMessage={handleMessage} />Custom Styling with CSS
// Add custom styles in your CSS file
<Chat className="my-custom-chat">
<div className="flex items-center gap-2">
<span>Custom controls here</span>
</div>
</Chat>/* Custom styling using data attributes */
.my-custom-chat [data-chat="send-button"] {
background-color: #ef4444;
transition: background-color 0.2s;
}
.my-custom-chat [data-chat="send-button"]:hover {
background-color: #dc2626;
}
.my-custom-chat [data-chat="textarea"] {
background-color: #f3f4f6;
border-color: #d1d5db;
}
.my-custom-chat [data-chat="model-selector"] {
color: #2563eb;
border-color: #93c5fd;
}Using ChatOptions
<Chat>
<div className="bg-muted flex items-center justify-between rounded-md p-2">
<span className="text-muted-foreground text-sm">AI Assistant</span>
<button className="text-primary text-xs">Clear Chat</button>
</div>
</Chat>Individual Components
import {
ChatAssistantMessage,
ChatMessages,
ChatModelSelector,
ChatOptions,
ChatPromptInput,
ChatSendButton,
ChatUserMessage,
} from "@/components/chat"
// Use components independently
;<div className="flex h-full flex-col">
<ChatMessages messages={messages} isLoading={loading} />
<ChatPromptInput
input={input}
onInputChange={setInput}
onSubmit={handleSubmit}
// ... other props
/>
</div>
// Or use individual components for custom layouts
;<div className="flex items-center gap-2">
<ChatModelSelector
selectedModel={model}
onModelChange={setModel}
models={models}
className="rounded-md border"
/>
<ChatSendButton
isDisabled={!input.trim()}
isLoading={loading}
className="bg-green-500"
/>
</div>On This Page
InstallationUsageExamplesChat with Previous MessagesNon-Streaming ChatChat with Shimmer EffectChat with ReasoningAPI ReferenceChatIndividual ComponentsChatSendButtonChatModelSelectorChatOptionsStyling with Data AttributesExample CSSFeaturesEnhanced Scrollbar UI/UXExamplesCustom Message HandlerWith Custom ModelsWith File UploadCustom Styling with CSSUsing ChatOptionsIndividual Components