Chat Attachments
Preview: Chips
Attachment chips for prompts and messages: image thumbnails, file type badge, upload progress, remove.
Import
import { ChatAttachments } from '@marbleui/ui'Props
<ChatAttachments>
| Prop | Type | Default | Description |
|---|---|---|---|
| items *required | ChatAttachment[] | — | |
| className | string | — | |
| onRemove | (id: string) => void | — | |
| variant | 'chips' | 'tiles' | 'chips' |
Usage notes
File chips for chat: image thumbnails, a file-type badge, size, upload progress and errors. PromptInput already shows it for files picked in the composer. Use it directly for the files on a sent ChatMessage, or in a composer you build yourself.
<ChatAttachments
variant="tiles"
items={[
{ id: 'a1', name: 'q3-report.pdf', type: 'application/pdf', size: 2_400_000 },
{ id: 'a2', name: 'mockup.png', type: 'image/png', url: previewUrl, progress: 62 },
]}
onRemove={(id) => cancelUpload(id)}
/>
- Leave out
onRemovefor a read-only list. Remove buttons are named per file (“Remove q3-report.pdf”). - Only
image/*items with aurlget a thumbnail.tilesshows those as small squares (other files stay chips); their remove button appears only on hover or keyboard focus, so touch users can’t see it. - On chips,
progress(0–100) shows “Uploading… 62%” anderrorreplaces the size; image tiles show a progress ring and no error. Neither change is announced. PromptInput’s own attachments have no progress or error state, and itsonSubmitreturns these objects, notFiles.
Example source · show· hide
import { useState } from 'react'
import { ChatAttachments, type ChatAttachment } from './chat-attachments'
const img = (id: string) => `https://images.unsplash.com/photo-${id}?w=200&h=200&fit=crop&q=60`
const initial: ChatAttachment[] = [
{ id: '1', name: 'q3-report.pdf', type: 'application/pdf', size: 2_400_000 },
{ id: '2', name: 'mockup.png', type: 'image/png', size: 820_000, url: img('1500530855697-b586d89ba3ee') },
{ id: '3', name: 'data.csv', type: 'text/csv', size: 48_000, progress: 62 },
{ id: '4', name: 'huge-video.mov', type: 'video/quicktime', error: 'Too large (max 50 MB)' },
]
function Demo({ variant }: { variant: 'chips' | 'tiles' }) {
const [items, setItems] = useState(initial)
return <ChatAttachments className="w-[30rem]" variant={variant} items={items} onRemove={(id) => setItems(items.filter((i) => i.id !== id))} />
}
export const styles = { Chips: () => <Demo variant="chips" />, Tiles: () => <Demo variant="tiles" /> }Source: packages/ui/src/chat-attachments/chat-attachments.tsx
Catalog
- Category
- ai-agents
- Priority
- Pro
- Primitive
- composed
- React Aria
- DropZone + TagGroup