Composer

Composable message-editor parts for an input, toolbar, attachments, and drag-and-drop feedback.

Preview#

64%
PDFrelease-notes.pdf18 KB
PDFuploading-notes.pdf18 KB64%
PDFfailed-upload.pdf18 KB
PDFdesign-spec.pdf18 KB
PDFresearch-notes.pdf18 KB
PDFapi-contract.pdf18 KB
Controls
Attachments
Feedback
import {
  Checkbox,
  Composer,
  ComposerActions,
  ComposerAttachment,
  ComposerAttachmentBody,
  ComposerAttachmentFile,
  ComposerAttachmentImage,
  ComposerAttachmentMeta,
  ComposerAttachmentRemove,
  ComposerAttachments,
  ComposerAttachmentTitle,
  ComposerAttachmentUploadingOverlay,
  ComposerAttachmentUploadProgressBar,
  ComposerDropOverlay,
  ComposerDropOverlayPrompt,
  ComposerIconButton,
  ComposerInput,
  ComposerMeta,
  ComposerRoot,
  ComposerSubmit,
  ComposerToolbar,
  ComposerToolbarLabel,
  SortableComposerAttachment,
  SortableComposerAttachmentsScroll,
  Spinner,
} from "raft-ui";

<div className="relative">
  <ComposerRoot>
    <ComposerAttachments>
      {/* wrap: SortableComposerAttachments — scroll: SortableComposerAttachmentsScroll */}
      <SortableComposerAttachmentsScroll items={["shot", "notes"]} onReorder={() => {}}>
        <SortableComposerAttachment id="shot" label="screenshot.png">
          <ComposerAttachment>
            <ComposerAttachmentImage />
            <ComposerAttachmentUploadingOverlay>
              <Spinner />
              64%
            </ComposerAttachmentUploadingOverlay>
            <ComposerAttachmentUploadProgressBar value={64} />
            <ComposerAttachmentRemove />
          </ComposerAttachment>
        </SortableComposerAttachment>
        <SortableComposerAttachment id="notes" label="release-notes.pdf">
          <ComposerAttachment>
            <ComposerAttachmentFile>
              <ComposerAttachmentBody>
                <ComposerAttachmentTitle />
                <ComposerAttachmentMeta>18 KB</ComposerAttachmentMeta>
              </ComposerAttachmentBody>
              <ComposerAttachmentUploadingOverlay>
                <Spinner />
                64%
              </ComposerAttachmentUploadingOverlay>
              <ComposerAttachmentUploadProgressBar value={64} />
            </ComposerAttachmentFile>
            <ComposerAttachmentRemove />
          </ComposerAttachment>
        </SortableComposerAttachment>
      </SortableComposerAttachmentsScroll>
    </ComposerAttachments>
    <Composer>
      <ComposerInput />
      <ComposerToolbar>
        <ComposerActions>
          <ComposerIconButton />
        </ComposerActions>
        <ComposerMeta>
          <ComposerToolbarLabel>
            <Checkbox />
            As Task
          </ComposerToolbarLabel>
          <ComposerSubmit />
        </ComposerMeta>
      </ComposerToolbar>
    </Composer>
  </ComposerRoot>
  <ComposerDropOverlay>
    <ComposerDropOverlayPrompt />
  </ComposerDropOverlay>
</div>

Default composer#

Pending and failed attachments#

64%
PDFrelease-notes.pdf18 KB
PDFfailed-upload.pdf18 KB

Attachment limit banner#

Attachment count limits are product policy. Keep the Banner outside Composer and show it when the consumer rejects another file.

PDFrelease-notes.pdf18 KB
PDFdesign-spec.pdf18 KB
PDFresearch-notes.pdf18 KB
PDFapi-contract.pdf18 KB
PDFattachment-5.pdf18 KB
PDFattachment-6.pdf18 KB
PDFattachment-7.pdf18 KB
PDFattachment-8.pdf18 KB
PDFattachment-9.pdf18 KB
PDFattachment-10.pdf18 KB

Single-row attachments with arrows#

Use SortableComposerAttachmentsScroll inside ComposerAttachments for a single-row strip (arrows + horizontal reorder). For wrapping tiles, use SortableComposerAttachments instead.

PDFrelease-notes.pdf18 KB
PDFdesign-spec.pdf18 KB
PDFresearch-notes.pdf18 KB
PDFapi-contract.pdf18 KB
PDFattachment-5.pdf18 KB
PDFattachment-6.pdf18 KB
PDFattachment-7.pdf18 KB
PDFattachment-8.pdf18 KB
PDFattachment-9.pdf18 KB
PDFattachment-10.pdf18 KB

Reorder attachments (wrap)#

Use SortableComposerAttachments with consumer-owned order. Pass string items / onReorder; render each tile inside SortableComposerAttachment.

PDFrelease-notes.pdf18 KB
PDFdesign-spec.pdf18 KB
PDFresearch-notes.pdf18 KB
PDFapi-contract.pdf18 KB
PDFproduct-brief.pdf18 KB
PDFaudit-log.pdf18 KB
PDFrollout-plan.pdf18 KB
PDFqa-checklist.pdf18 KB

Reorder attachments (scroll)#

SortableComposerAttachmentsScroll is a thin wrapper around ComposerAttachmentsScrollArea with horizontal sort + x-only autoscroll. Same items / onReorder contract as the wrap variant.

PDFrelease-notes.pdf18 KB
PDFdesign-spec.pdf18 KB
PDFresearch-notes.pdf18 KB
PDFapi-contract.pdf18 KB
PDFproduct-brief.pdf18 KB
PDFaudit-log.pdf18 KB
PDFrollout-plan.pdf18 KB
PDFqa-checklist.pdf18 KB
PDFmeeting-notes.pdf18 KB

Ready images with lightbox#

Composer does not own preview state. Ready image attachments stay clickable tiles; the consumer opens Lightbox and owns gallery index / navigation.

File drop overlay#

Custom toolbar#

Toolbar slots are consumer-owned. Replace the left actions with policy copy when send is blocked, or with a single custom affordance while keeping submit on the right.

Subscribe to send more messages in this channel.

API#WIP

PropTypeDefaultDescription
...propsform propsComposition root for autocomplete, pending attachments, and the bordered composer surface.
PropTypeDefaultDescription
...propsdiv propsBordered composer shell.
PropTypeDefaultDescription
...propstextarea propsAuto-growing message textarea.
PropTypeDefaultDescription
...propsdiv propsToolbar row under the input.
PropTypeDefaultDescription
...propsdiv propsCaller-owned action cluster in the toolbar.
PropTypeDefaultDescription
...propsdiv propsCaller-owned metadata cluster in the toolbar.
PropTypeDefaultDescription
...propsbutton propsAttach-action icon button.
PropTypeDefaultDescription
...propsButton propsAccent Button used for submit. Use Button size, loading, and render props; pass visible content as children.
PropTypeDefaultDescription
...propslabel propsA labelled checkbox or status cluster with theme-aware spacing and typography.
PropTypeDefaultDescription
...propsdiv propsPending-upload strip above the input.
PropTypeDefaultDescription
...propsdiv propsOpt-in single-row overflow with prev/next arrows. Prefer SortableComposerAttachmentsScroll when reorder is needed — that wrapper includes this shell.
PropTypeDefaultDescription
itemsreadonly string[]Ordered attachment ids. Consumer owns the list and maps ids back to tile data.
onReorder(items: string[]) => voidCommits the reordered id list on drag end. Live draft order is kept inside the sortable while dragging.
childrenReactNodeSortableComposerAttachment children for each id in items.
PropTypeDefaultDescription
...propsSortableComposerAttachments propsThin wrapper: ComposerAttachmentsScrollArea + horizontal sort strategy + x-only autoscroll.
PropTypeDefaultDescription
idstringStable id matching an entry in the parent items list.
labelstringAccessible name used for the reorder control (e.g. filename).
childrenReactNodeComposerAttachment tile content. DragOverlay clones this as the pointer ghost.
PropTypeDefaultDescription
...propsdiv propsAttachment tile within the pending-upload strip.
PropTypeDefaultDescription
...propsspan propsFile-chip tile for non-image uploads.
PropTypeDefaultDescription
...propsspan propsFixed 64px image media. Place FilePreview media inside. The attachment root owns the brutal frame border when this part is present.
PropTypeDefaultDescription
...propsspan propsFile-chip text block.
PropTypeDefaultDescription
...propsspan propsAttachment filename.
PropTypeDefaultDescription
...propsspan propsAttachment mime/type metadata.
PropTypeDefaultDescription
...propsspan propsWhite upload overlay for caller-owned progress content. For images, place as a sibling under ComposerAttachment; for files, nest inside ComposerAttachmentFile.
PropTypeDefaultDescription
...propsspan props & { value: number }Bottom linear upload progress bar. Place next to the uploading overlay (image: under ComposerAttachment; file: inside ComposerAttachmentFile).
PropTypeDefaultDescription
...propsspan propsBorderless failed-upload mask for caller-owned retry feedback.
PropTypeDefaultDescription
...propsbutton propsCorner remove affordance.
PropTypeDefaultDescription
...propsdiv propsDrag-and-drop overlay that fills its nearest positioned ancestor. May sit inside ComposerRoot or outside it on a shared relative wrapper.
PropTypeDefaultDescription
...propsspan propsVisible drop feedback content.
PropTypeDefaultDescription
...propsspan propsDefault drop feedback prompt; pass children to replace its visible content.