UploadKit
SDK@uploadkitdev/react

UploadAttachmentTray

A Discord/iMessage-style horizontal scrollable strip of file thumbnails with progress rings and remove buttons.

A horizontal tray of 72px thumbnail cards that scrolls as more files are added. Each card shows a live image preview (or file-type icon), a circular progress ring overlay during upload, and a remove button. Designed to sit below a text input or chat composer.

Design inspiration: Discord file attachments, iMessage, WhatsApp.

motion is an optional peerDependency. Without it, cards appear instantly. pnpm add motion for spring scale-in entrances and AnimatePresence exit animations.

Discord · iMessage — attachment tray

Basic usage

import { UploadAttachmentTray } from '@uploadkitdev/react';

export default function Page() {
  return (
    <div>
      <textarea placeholder="Type a message..." />
      <UploadAttachmentTray
        route="chatUploader"
        accept={['image/*', 'application/pdf']}
        maxFiles={10}
        onUploadComplete={(results) => {
          console.log('Attached:', results.map((r) => r.url));
        }}
      />
    </div>
  );
}

Props

PropTypeDefaultDescription
routestringRequired. Route name from your file router.
acceptstring[]Accepted MIME types.
maxSizenumberMaximum file size in bytes.
maxFilesnumberMaximum number of files.
metadataRecord<string, unknown>Metadata forwarded to the server.
onUploadComplete(results: UploadResult[]) => voidCalled after all files upload.
onUploadError(error: Error) => voidCalled on failure.
classNamestringAdditional CSS class(es).

Card anatomy

Each 72x72 card shows:

  • Image files: blob URL thumbnail as background-image
  • Other files: centered file-type SVG icon
  • Upload overlay: dark overlay with 28px SVG progress ring
  • Remove button: 18px circle in top-right corner (red on hover)
  • Error state: red border + alert icon

Accessibility

  • Attach button opens file picker
  • Scroll snap for smooth horizontal navigation
  • Blob URLs revoked on unmount
  • Respects prefers-reduced-motion

On this page