API
The Chatbar component is a comprehensive multi-line text input designed for chat interfaces with built-in attachment support, auto-resizing behavior, and comprehensive file handling capabilities. It provides controlled and uncontrolled state management, drag-and-drop functionality, and accessibility compliance out of the box.
Props
tsximport { Chatbar } from '@kushagradhawan/kookie-ui';tsx<Chatbar.Root width="360px" open onOpenChange={() => {}} onSubmit={({ value, attachments }) => {
console.log('Message:', value);
console.log('Attachments:', attachments);
}}>
<Chatbar.AttachmentsRow />
<Chatbar.Textarea
placeholder="Type a message..."
aria-label="Message input"
/>
<Chatbar.Row>
<Chatbar.AttachTrigger asChild>
<IconButton size="1" variant="soft" aria-label="Attach file">
<Paperclip />
</IconButton>
</Chatbar.AttachTrigger>
<Chatbar.Send variant="ghost" />
</Chatbar.Row>
</Chatbar.Root>Chatbar supports drag-and-drop and paste for attachments. Configure acceptance, limits, and behavior via Attachment props.
Variants
Use the variant prop to set Chatbar style. Prefer classic for elevated emphasis, surface for content-heavy UIs, outline for neutral framing, soft for gentle emphasis, and ghost for minimal chrome.
Classic
tsx<Chatbar.Root width="360px" open onOpenChange={() => {}} variant="classic" minLines={3} sendMode="always">
<Chatbar.AttachmentsRow />
<Chatbar.Textarea aria-label="Message input" placeholder="Type a message..." />
<Chatbar.Row>
<Chatbar.AttachTrigger asChild>
<IconButton size="2" variant="classic" aria-label="Attach file">
<Paperclip />
</IconButton>
</Chatbar.AttachTrigger>
<Chatbar.Send variant="ghost" />
</Chatbar.Row>
</Chatbar.Root>Soft
tsx<Chatbar.Root width="360px" open onOpenChange={() => {}} variant="soft" minLines={3} sendMode="always">
<Chatbar.AttachmentsRow />
<Chatbar.Textarea aria-label="Message input" placeholder="Type a message..." />
<Chatbar.Row>
<Chatbar.AttachTrigger asChild>
<IconButton size="2" variant="classic" aria-label="Attach file">
<Paperclip />
</IconButton>
</Chatbar.AttachTrigger>
<Chatbar.Send variant="ghost" />
</Chatbar.Row>
</Chatbar.Root>Outline
tsx<Chatbar.Root width="360px" open onOpenChange={() => {}} variant="outline" minLines={3} sendMode="always">
<Chatbar.AttachmentsRow />
<Chatbar.Textarea aria-label="Message input" placeholder="Type a message..." />
<Chatbar.Row>
<Chatbar.AttachTrigger asChild>
<IconButton size="2" variant="classic" aria-label="Attach file">
<Paperclip />
</IconButton>
</Chatbar.AttachTrigger>
<Chatbar.Send variant="ghost" />
</Chatbar.Row>
</Chatbar.Root>Surface
tsx<Chatbar.Root width="360px" open onOpenChange={() => {}} variant="surface" minLines={3} sendMode="always">
<Chatbar.AttachmentsRow />
<Chatbar.Textarea aria-label="Message input" placeholder="Type a message..." />
<Chatbar.Row>
<Chatbar.AttachTrigger asChild>
<IconButton size="2" variant="classic" aria-label="Attach file">
<Paperclip />
</IconButton>
</Chatbar.AttachTrigger>
<Chatbar.Send variant="ghost" />
</Chatbar.Row>
</Chatbar.Root>Ghost
tsx<Chatbar.Root width="360px" open onOpenChange={() => {}} variant="ghost" minLines={3} sendMode="always">
<Chatbar.AttachmentsRow />
<Chatbar.Textarea aria-label="Message input" placeholder="Type a message..." />
<Chatbar.Row>
<Chatbar.AttachTrigger asChild>
<IconButton size="2" variant="classic" aria-label="Attach file">
<Paperclip />
</IconButton>
</Chatbar.AttachTrigger>
<Chatbar.Send variant="ghost" />
</Chatbar.Row>
</Chatbar.Root>Attachment Props
Subcomponents
Chatbar.Textarea
The multi-line text input component with auto-resizing behavior.
Chatbar.AttachTrigger
Button component for opening the file picker dialog.
Chatbar.Send
Send button with conditional visibility based on sendMode.
Types
ChatbarAttachment
tsxinterface ChatbarAttachment {
id: string;
name: string;
size: number;
type: string;
/** Original File object for uploads and processing */
file: File;
url?: string;
status?: 'idle' | 'uploading' | 'error' | 'done';
progress?: number;
meta?: Record<string, unknown>;
}ChatbarApi
Imperative API for programmatic control.
tsxinterface ChatbarApi {
/** Focus the textarea input */
focusTextarea: () => void;
/** Open the file picker dialog (respects accept/multiple) */
openFilePicker: () => void;
}Accessibility
The Chatbar component provides comprehensive accessibility support:
- ARIA attributes: Proper
aria-expandedon the root element - Keyboard navigation: Full keyboard support for all interactions
- Screen reader support: Proper labeling and announcements
- Focus management: Logical focus flow and trap management
- High contrast mode: Support for Windows High Contrast mode
- Reduced motion: Respects
prefers-reduced-motionuser preference
Required Accessibility Props
Always provide an accessible name for the textarea using either aria-label or aria-labelledby.
tsx<Chatbar.Root width="360px" open onOpenChange={() => {}}>
<Chatbar.Textarea
placeholder="Type a message..."
aria-label="Message input"
/>
{/* ... */}
</Chatbar.Root>Examples
Basic Chatbar
tsx<Chatbar.Root width="360px" open onOpenChange={() => {}} onSubmit={({ value, attachments }) => {
console.log('Message:', value);
console.log('Attachments:', attachments);
}}>
<Chatbar.Textarea
placeholder="Type a message..."
aria-label="Message input"
/>
<Chatbar.AttachTrigger />
<Chatbar.Send />
</Chatbar.Root>With File Restrictions
tsx<Chatbar.Root width="360px" open onOpenChange={() => {}}
accept="image/*,.pdf,.doc,.docx"
maxFileSize={5 * 1024 * 1024} // 5MB
maxAttachments={3}
onAttachmentReject={(rejections) => {
console.log('Rejected files:', rejections);
}}
onSubmit={({ value, attachments }) => {
// Handle submission
}}
>
<Chatbar.Textarea
placeholder="Type a message..."
aria-label="Message input"
/>
<Chatbar.AttachTrigger />
<Chatbar.Send />
</Chatbar.Root>Controlled State
tsxconst [value, setValue] = useState('');
const [attachments, setAttachments] = useState<ChatbarAttachment[]>([]);
<Chatbar.Root width="360px" open onOpenChange={() => {}}
value={value}
onValueChange={setValue}
attachments={attachments}
onAttachmentsChange={setAttachments}
onSubmit={({ value, attachments }) => {
// Handle submission
setValue('');
setAttachments([]);
}}
>
<Chatbar.Textarea
placeholder="Type a message..."
aria-label="Message input"
/>
<Chatbar.AttachTrigger />
<Chatbar.Send />
</Chatbar.Root>With Attachments Display
tsx<Chatbar.Root width="360px" open onOpenChange={() => {}} onSubmit={({ value, attachments }) => {
console.log('Message:', value);
console.log('Attachments:', attachments);
}}>
<Chatbar.AttachmentsRow />
<Chatbar.Textarea
placeholder="Type a message..."
aria-label="Message input"
/>
<Chatbar.Row>
<Chatbar.AttachTrigger asChild>
<IconButton size="1" variant="soft" aria-label="Attach file">
<Paperclip />
</IconButton>
</Chatbar.AttachTrigger>
<Chatbar.Send variant="ghost" />
</Chatbar.Row>
</Chatbar.Root>Custom Layout
tsx<Chatbar.Root width="360px" open onOpenChange={() => {}} onSubmit={({ value, attachments }) => {
console.log('Message:', value);
console.log('Attachments:', attachments);
}}>
<Chatbar.Textarea
placeholder="Type a message..."
aria-label="Message input"
/>
<Chatbar.Row>
<Chatbar.AttachTrigger asChild>
<IconButton size="1" variant="soft" aria-label="Attach file">
<Paperclip />
</IconButton>
</Chatbar.AttachTrigger>
<Chatbar.Send variant="ghost" />
</Chatbar.Row>
</Chatbar.Root>