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

tsx
import { 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>
PropType
valuestring
defaultValuestring
onValueChange(value: string) => void
openboolean
defaultOpenboolean
onOpenChange(open: boolean) => void
expandOn'none' | 'focus' | 'overflow' | 'both'
minLinesnumber
maxLinesnumber
sendMode'always' | 'whenDirty' | 'never'
disabledboolean
readOnlyboolean
onSubmit(payload: { value: string; attachments: ChatbarAttachment[] }) => void
size'1' | '2' | '3'
variant'surface' | 'outline' | 'classic' | 'ghost' | 'soft'
colorstring
radiusstring | number
material'solid' | 'translucent'
widthReact.CSSProperties['width']
maxWidthReact.CSSProperties['maxWidth']
asChildboolean

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

PropTypeDefault
attachmentsChatbarAttachment[]undefined
defaultAttachmentsChatbarAttachment[][]
onAttachmentsChange(attachments: ChatbarAttachment[]) => voidundefined
acceptstring | string[]undefined
multiplebooleantrue
maxAttachmentsnumberundefined
maxFileSizenumberundefined
pastebooleantrue
pasteAcceptstring | string[]accept
clearOnSubmitbooleantrue
onAttachmentReject(rejections: { file: File; reason: 'type' | 'size' | 'count' }[]) => voidundefined
dropzonebooleantrue

Subcomponents

Chatbar.Textarea

The multi-line text input component with auto-resizing behavior.

PropTypeDefault
submitOnEnterbooleanfalse
onPasteReact.ClipboardEventHandler<HTMLTextAreaElement>undefined
asChildbooleanfalse

Chatbar.AttachTrigger

Button component for opening the file picker dialog.

PropTypeDefault
acceptstring | string[]Root accept
multiplebooleanRoot multiple
asChildbooleanfalse

Chatbar.Send

Send button with conditional visibility based on sendMode.

PropTypeDefault
clearOnSendbooleantrue
asChildbooleanfalse

Types

ChatbarAttachment

tsx
interface 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.

tsx
interface 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-expanded on 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-motion user 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

tsx
const [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>
© 2025 Kushagra Dhawan. Licensed under MIT. GitHub.

Theme

Accent color

Gray color

Appearance

Radius

Scaling

Panel background