Chat InputPro
Production-grade message composer with auto-resizing textarea, quoted replies, file/image attachments, and keyboard shortcuts. Supports two sizes, three visual states, and integrates with existing Button, FileCard, and Avatar components.
Chat Input Playground
Installation
You can add the chat input component to your project manually:
Install the following dependencies:
npm install class-variance-authority clsx tailwind-merge @phosphor-icons/react @react-aria/focus @react-aria/interactionsCopy and paste the following code into your project.
Update the import paths to match your project setup.
Update the import aliases (e.g. @/components, @/utils) in the copied files to match your project's path configuration.
Basic Usage
import { ChatInput } from '@versaui/ui/components/ChatInput';
<ChatInput
placeholder="Type your message..."
onSend={(value) => console.log('Sent:', value)}
onAttach={() => console.log('Attach clicked')}
/>Controlled Usage
import { useState } from 'react';
import { ChatInput } from '@versaui/ui/components/ChatInput';
function Chat() {
const [message, setMessage] = useState('');
return (
<ChatInput
value={message}
onChange={(e) => setMessage(e.target.value)}
onSend={(value) => {
console.log('Sent:', value);
setMessage('');
}}
/>
);
}Variants
Size
Two sizes matching the design system scale:
// Default — 16px text, 40px action buttons
<ChatInput size="default" />
// Small — 12px text, 32px action buttons
<ChatInput size="small" />State
Visual state is auto-computed from focus and value, or can be controlled:
// Default — subtle border, unfocused
<ChatInput state="default" />
// Typing — strong border, focused
<ChatInput state="typing" />
// Filled — strong border, has content, send button activates
<ChatInput state="filled" />With Quoted Reply
Show a reply preview above the input field. When any attachment is present (quoted reply, files, or images), the container corner-radius automatically switches from thematic to default values:
<ChatInput
quoted={{
senderName: 'Amanda Brooks',
message: 'This message needs your immediate attention',
}}
onRemoveQuote={() => setQuoted(null)}
/>With File Attachment
Show file cards using the existing FileCard component:
<ChatInput
files={[{
id: '1',
name: 'Report.pdf',
size: '412 KB',
format: 'pdf',
}]}
onRemoveFile={(id) => removeFile(id)}
/>With Image Attachments
Show image thumbnails with upload progress support:
<ChatInput
images={[
{ id: '1', progress: 25 }, // Uploading (25%)
{ id: '2', src: '/photo.jpg' }, // Completed
{ id: '3', src: '/screenshot.png' }, // Completed
]}
onRemoveImage={(id) => removeImage(id)}
/>File Drag and Drop
Allow users to drag and drop files directly onto the input bar:
<ChatInput
onFileDrop={(files) => {
// files is a FileList — process or upload as needed
Array.from(files).forEach(file => console.log(file.name));
}}
onAttach={() => console.log('Attach clicked')}
/>Sub-Components
QuotedMessage
Inline reply preview with avatar, sender name, message text, and dismiss button:
import { QuotedMessage } from '@versaui/ui/components/ChatInput';
<QuotedMessage
size="default"
senderName="Amanda Brooks"
message="This message needs your immediate attention"
onDismiss={() => {}}
/>ImageAttachment
Image thumbnail with upload progress circle:
import { ImageAttachment } from '@versaui/ui/components/ChatInput';
// Uploading
<ImageAttachment size="default" uploadProgress progress={25} />
// Completed
<ImageAttachment size="default" src="/photo.jpg" />Keyboard Shortcuts
| Key | Action |
|---|---|
Enter | Send message |
Shift + Enter | Insert newline |
Escape | Dismiss quoted reply |
Accessibility
- Textarea has
aria-label="Message input"for screen readers - Container uses
role="group"witharia-label="Message composer" - Action buttons have descriptive
aria-labelattributes - Quoted message uses
role="blockquote"with attribution - Image attachments use
role="img"with progress or alt text - Full keyboard navigation support with IME composition handling
- Focus ring: Keyboard-only focus ring using
--focus-ring-primarytoken (visible on Tab navigation, hidden on click) - Drag-and-drop hint: Screen-reader announcement during file drag-over
- Corner radius: Automatically switches from thematic to default radius when any attachment is present (quoted reply, files, or images)
Chat Input Props
| Prop | Type | Default | Description |
|---|---|---|---|
size | 'default' | 'small' | 'default' | Size variant controlling typography, button sizes, and spacing. |
state | 'default' | 'typing' | 'filled' | Auto | Visual state. Auto-computed from focus/value when unset. |
value | string | — | Controlled input value. |
defaultValue | string | '' | Default uncontrolled value. |
onChange | (e: ChangeEvent) => void | — | Textarea change handler. |
onSend | (value: string) => void | — | Called when the user sends via Enter or send button. |
onAttach | () => void | — | Called when the attach button is clicked. |
onFileDrop | (files: FileList) => void | — | Called when files are dragged and dropped onto the input. Visual drag-over feedback is shown only when this prop is provided. |
placeholder | string | 'Type your message...' | Placeholder text for the input. |
disabled | boolean | false | Disables the input and action buttons. |
maxLength | number | — | Maximum character length. |
quoted | QuotedMessageData | null | — | Quoted reply data. Pass null to hide. |
onRemoveQuote | () => void | — | Called when the quoted reply dismiss button is clicked. |
files | AttachedFile[] | — | File attachments displayed above the input. |
onRemoveFile | (id: string) => void | — | Called when a file attachment is removed. |
images | AttachedImage[] | — | Image attachments displayed above the input. |
onRemoveImage | (id: string) => void | — | Called when an image attachment is removed. |
isHovered | boolean | — | Controlled hover state for demos. |
isFocused | boolean | — | Controlled focus state for demos. |
className | string | '' | Additional CSS classes. |
Quoted Message Props
| Prop | Type | Default | Description |
|---|---|---|---|
size | 'default' | 'small' | 'default' | Size variant matching the parent ChatInput size. |
senderName | string | 'Amanda Brooks' | Sender display name. |
message | string | 'This message needs your immediate attention' | Quoted message text. |
avatarPerson | AvatarPerson | 'amanda-brooks' | Avatar person key from the design system. |
onDismiss | () => void | — | Called when the dismiss button is clicked. Hides button when not provided. |
className | string | '' | Additional CSS classes. |
Image Attachment Props
| Prop | Type | Default | Description |
|---|---|---|---|
size | 'default' | 'small' | 'default' | Size variant. Default=80×80, Small=64×64. |
src | string | — | Image source URL. undefined = still uploading. |
progress | number | 0 | Upload progress percentage (0–100). |
uploadProgress | boolean | false | Whether to show the upload progress indicator. |
alt | string | '' | Alt text for the image. |
className | string | '' | Additional CSS classes. |