GitHub
Core
Glass
Brutal
Humanist

Chat Input
Pro

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

Chat Input Playground
Preview
Code
Controls
Size:
Default
Small
Quoted:

Installation

You can add the chat input component to your project manually:

1

Install the following dependencies:

npm install class-variance-authority clsx tailwind-merge @phosphor-icons/react @react-aria/focus @react-aria/interactions
2

Copy and paste the following code into your project.

Loading...
3

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

KeyAction
EnterSend message
Shift + EnterInsert newline
EscapeDismiss quoted reply

Accessibility

  • Textarea has aria-label="Message input" for screen readers
  • Container uses role="group" with aria-label="Message composer"
  • Action buttons have descriptive aria-label attributes
  • 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-primary token (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

PropTypeDefaultDescription
size'default' | 'small''default'Size variant controlling typography, button sizes, and spacing.
state'default' | 'typing' | 'filled'AutoVisual state. Auto-computed from focus/value when unset.
valuestringControlled input value.
defaultValuestring''Default uncontrolled value.
onChange(e: ChangeEvent) => voidTextarea change handler.
onSend(value: string) => voidCalled when the user sends via Enter or send button.
onAttach() => voidCalled when the attach button is clicked.
onFileDrop(files: FileList) => voidCalled when files are dragged and dropped onto the input. Visual drag-over feedback is shown only when this prop is provided.
placeholderstring'Type your message...'Placeholder text for the input.
disabledbooleanfalseDisables the input and action buttons.
maxLengthnumberMaximum character length.
quotedQuotedMessageData | nullQuoted reply data. Pass null to hide.
onRemoveQuote() => voidCalled when the quoted reply dismiss button is clicked.
filesAttachedFile[]File attachments displayed above the input.
onRemoveFile(id: string) => voidCalled when a file attachment is removed.
imagesAttachedImage[]Image attachments displayed above the input.
onRemoveImage(id: string) => voidCalled when an image attachment is removed.
isHoveredbooleanControlled hover state for demos.
isFocusedbooleanControlled focus state for demos.
classNamestring''Additional CSS classes.

Quoted Message Props

PropTypeDefaultDescription
size'default' | 'small''default'Size variant matching the parent ChatInput size.
senderNamestring'Amanda Brooks'Sender display name.
messagestring'This message needs your immediate attention'Quoted message text.
avatarPersonAvatarPerson'amanda-brooks'Avatar person key from the design system.
onDismiss() => voidCalled when the dismiss button is clicked. Hides button when not provided.
classNamestring''Additional CSS classes.

Image Attachment Props

PropTypeDefaultDescription
size'default' | 'small''default'Size variant. Default=80×80, Small=64×64.
srcstringImage source URL. undefined = still uploading.
progressnumber0Upload progress percentage (0–100).
uploadProgressbooleanfalseWhether to show the upload progress indicator.
altstring''Alt text for the image.
classNamestring''Additional CSS classes.

On this page