MessageAttachments

What was attached, before or after sending — a pasted stack trace, an image to open, a document with its page count.

Install it:

npx shadcn add @ambientui/message-attachments

Live

Staged in the composer (compact)

TypeError: Cannot read properties of undefinedcomposer-regression.pngvitest-run.log

Received files

migration-0.14.pdf1.2 MB · 14 pages
vitest-run.log38 KB

Behavior

  • ·ONE COMPONENT FOR BOTH MOMENTS, because removability is the only honest difference: pass onRemove while the attachment is still staged in the composer, omit it once the message is sent and the attachment is a record. Two components would have drifted into two ideas of what an attachment looks like.
  • ·A removable row is never also an openable one — it already contains a button, so it must not be one. While staged, removing wins.
  • ·Pasted text is a `text` attachment: it is quoted material rather than a file, it says so with the quote mark, and its meta counts lines and characters so it is identifiable without being read.
  • ·`compact` is the composer's density: chips in one row rather than stacked cards, because staged attachments sit beside context chips and mean the same thing. Four stacked cards pushed the input off the surface, which is the wrong trade for material you are only referring to.
  • ·It is the SAME chip wherever it is drawn (AttachmentChip) inside the SAME slider (ChipSlider). The ambient layer's context row renders attachments beside the page chip in one run; `compact` here is for a composer standing alone, with no context row above it. Two components drawing an attachment is how two drawings of one thing drift apart.
  • ·The row PAGES with arrows when it overflows, and carries none when it does not. A row that scrolls silently is one most people read as truncated — the arrows are the only thing separating "there is more" from "that is all".
  • ·An openable attachment is a raised, bordered card; the rest sit on the quiet fill — affordance is carried by the surface, not by a hover-only cue.
  • ·An image shows its thumbnail; everything else shows the icon for its kind, drawn by the configured icon library.
  • ·Size and meta are formatted by the caller and shown in mono — they are facts about a file, not prose.

When to use

  • ·On a user turn that carried files, and on assistant turns that produced them.
  • ·In a composer that stands alone (`compact`), for anything staged while the turn is still being written. Inside the ambient layer, the context row does this instead.

When not to

  • ·For links or references; those are ContextChip and ReferenceChips.
  • ·As a second place to show what is already staged. ONE ROW OWNS THE STAGE: where a context row exists it draws the attachments itself, in its own slider, and the composer is handed none. Rendering them in both produced two of every chip, each with its own remove button — and later, when that was fixed by stacking them instead, two rows that read as two different kinds of thing.