Hooks
Understanding the hook system for accessing chat state and functionality
The hook system provides access to chat state (e.g. message content), context, and functionality throughout the component tree without the need to pass props. These hooks enable deep customization and integration with the chat interface.
Context Hooks
useChatUI
The primary hook for accessing chat state and handlers to modify the chat state.
import { useChatUI } from '@llamaindex/chat-ui'
function CustomChatComponent() {
const {
messages,
input,
setInput,
isLoading,
error,
append,
reload,
stop,
setMessages,
requestData,
setRequestData,
} = useChatUI()
const handleSendMessage = async () => {
await append({
role: 'user',
content: input,
})
}
return (
<div>
<p>Messages: {messages.length}</p>
<p>Loading: {isLoading ? 'Yes' : 'No'}</p>
{error && <p>Error: {error.message}</p>}
</div>
)
}
Returned Properties:
messages
- Array of chat messagesinput
- Current input valuesetInput
- Function to update inputisLoading
- Loading state booleanerror
- Error object if anyappend
- Function to add messagereload
- Function to reload last messagestop
- Function to stop current generationsetMessages
- Function to update message arrayrequestData
- Additional request datasetRequestData
- Function to update request data
useChatMessage
Access the current message context within message components.
import { useChatMessage } from '@llamaindex/chat-ui'
function CustomMessageContent() {
const { message, isLast } = useChatMessage()
return (
<div>
<p>Role: {message.role}</p>
<p>Content: {message.content}</p>
<p>Is last message: {isLast ? 'Yes' : 'No'}</p>
{message.annotations && (
<p>Has annotations: {message.annotations.length}</p>
)}
</div>
)
}
Returned Properties:
message
- Current message objectisLast
- Boolean indicating if this is the last message
useChatInput
Access input form state and handlers.
import { useChatInput } from '@llamaindex/chat-ui'
function CustomInputField() {
const {
input,
setInput,
handleSubmit,
isLoading,
onFileUpload,
uploadedFiles,
} = useChatInput()
return (
<form onSubmit={handleSubmit}>
<textarea
value={input}
onChange={e => setInput(e.target.value)}
disabled={isLoading}
placeholder="Type your message..."
/>
<p>Uploaded files: {uploadedFiles.length}</p>
</form>
)
}
Returned Properties:
input
- Current input valuesetInput
- Function to update inputhandleSubmit
- Form submit handlerisLoading
- Loading stateonFileUpload
- File upload handleruploadedFiles
- Array of uploaded files
useChatMessages
Access messages list state and handlers.
import { useChatMessages } from '@llamaindex/chat-ui'
function CustomMessageList() {
const { messages, isLoading, reload, stop, isEmpty, scrollToBottom } =
useChatMessages()
return (
<div>
<div className="messages">
{messages.map((msg, i) => (
<div key={i}>{msg.content}</div>
))}
</div>
{isEmpty && <p>No messages yet</p>}
<button onClick={reload} disabled={isLoading}>
Reload
</button>
<button onClick={stop}>Stop</button>
<button onClick={scrollToBottom}>Scroll to Bottom</button>
</div>
)
}
Returned Properties:
messages
- Array of messagesisLoading
- Loading statereload
- Reload last messagestop
- Stop generationisEmpty
- Boolean if no messagesscrollToBottom
- Function to scroll to bottom
useChatCanvas
Access artifact canvas state and handlers.
import { useChatCanvas } from '@llamaindex/chat-ui'
function CustomCanvasControls() {
const {
currentArtifact,
isVisible,
showCanvas,
hideCanvas,
updateArtifact,
artifacts,
} = useChatCanvas()
return (
<div>
<p>Canvas visible: {isVisible ? 'Yes' : 'No'}</p>
<p>Current artifact: {currentArtifact?.title || 'None'}</p>
<p>Total artifacts: {artifacts.length}</p>
<button onClick={showCanvas}>Show Canvas</button>
<button onClick={hideCanvas}>Hide Canvas</button>
</div>
)
}
Returned Properties:
currentArtifact
- Currently displayed artifactisVisible
- Canvas visibility stateshowCanvas
- Function to show canvashideCanvas
- Function to hide canvasupdateArtifact
- Function to update artifactartifacts
- Array of all artifacts
Utility Hooks
useFile
Handle file uploads and processing.
import { useFile } from '@llamaindex/chat-ui'
function FileUploadComponent() {
const {
uploadFile,
uploadFiles,
isUploading,
uploadedFiles,
removeFile,
clearFiles,
} = useFile({
maxSize: 10 * 1024 * 1024, // 10MB
accept: ['image/*', 'application/pdf'],
multiple: true,
})
const handleFileSelect = async (files: FileList) => {
await uploadFiles(Array.from(files))
}
return (
<div>
<input
type="file"
multiple
onChange={e => handleFileSelect(e.target.files!)}
/>
{isUploading && <p>Uploading...</p>}
<div>
{uploadedFiles.map((file, i) => (
<div key={i}>
<span>{file.name}</span>
<button onClick={() => removeFile(i)}>Remove</button>
</div>
))}
</div>
<button onClick={clearFiles}>Clear All</button>
</div>
)
}
Options:
maxSize
- Maximum file size in bytesaccept
- Array of accepted MIME typesmultiple
- Allow multiple filesonUpload
- Upload completion callbackonError
- Error callback
Returned Properties:
uploadFile
- Upload single fileuploadFiles
- Upload multiple filesisUploading
- Upload stateuploadedFiles
- Array of uploaded filesremoveFile
- Remove file by indexclearFiles
- Clear all files
useCopyToClipboard
Copy content to clipboard with feedback.
import { useCopyToClipboard } from '@llamaindex/chat-ui'
function CopyButton({ content }) {
const { copyToClipboard, isCopied } = useCopyToClipboard({
timeout: 2000, // Reset after 2 seconds
})
const handleCopy = () => {
copyToClipboard(content)
}
return (
<button
onClick={handleCopy}
className={isCopied ? 'text-green-600' : 'text-gray-600'}
>
{isCopied ? 'Copied!' : 'Copy'}
</button>
)
}
Options:
timeout
- Time before resetting copied state
Returned Properties:
copyToClipboard
- Function to copy textisCopied
- Boolean indicating if recently copied
Hook Composition
Custom Chat Hook
Create custom hooks by composing existing ones:
import { useChatUI, useChatMessages } from '@llamaindex/chat-ui'
function useCustomChat() {
const chatUI = useChatUI()
const messages = useChatMessages()
const sendMessageWithMetadata = async (content: string, metadata: any) => {
await chatUI.append(
{
role: 'user',
content,
},
{ data: metadata }
)
}
const getLastAssistantMessage = () => {
return chatUI.messages.filter(m => m.role === 'assistant').pop()
}
return {
...chatUI,
...messages,
sendMessageWithMetadata,
getLastAssistantMessage,
}
}
Hook Context Boundaries
Context Availability
Different hooks are available in different contexts:
function App() {
return (
<ChatSection handler={handler}>
{/* useChatUI available here */}
<ChatMessages>
{/* useChatMessages available here */}
<ChatMessages.List>
{messages.map(message => (
<ChatMessage key={message.id} message={message}>
{/* useChatMessage available here */}
<CustomMessageContent />
</ChatMessage>
))}
</ChatMessages.List>
</ChatMessages>
<ChatInput>
{/* useChatInput available here */}
<CustomInputField />
</ChatInput>
</ChatSection>
)
}
Error Boundaries
Handle hook errors gracefully:
function SafeHookUsage() {
try {
const { messages } = useChatUI()
return <MessageList messages={messages} />
} catch (error) {
console.error('Hook error:', error)
return <ErrorFallback />
}
}
Next Steps
- Annotations - Learn how hooks work with annotation data
- Customization - Use hooks for custom styling and behavior
- Examples - See complete examples using hooks
- Core Components - Understand component-hook relationships