Elements

File

File message parts with type-aware icons, filename, size, and download actions.

Outline (default)
report.pdf2.0 KB
config.json512 B
notes.txt128 B
Muted
report.pdf2.0 KB
config.json512 B
notes.txt128 B
Sizes
sm.pdf2.0 KB
default.pdf2.0 KB
lg.pdf2.0 KB
MimeType Icons
report.pdf
config.json
notes.txt
photo.png
track.mp3
fig. 01

Installation

Install manually
npx shadcn@latest add "@assistant-ui/file"
First time? Set up a runtime

Runtime components read their state from an assistant-ui runtime. Add one to an existing project:

npx assistant-ui@latest init

Then wrap your app in a runtime provider:

import { AssistantRuntimeProvider } from "@assistant-ui/react";
import { useChatRuntime, AssistantChatTransport } from "@assistant-ui/ai-sdk";

export default function App() {
  const runtime = useChatRuntime({
    transport: new AssistantChatTransport({ api: "/api/chat" }),
  });

  return (
    <AssistantRuntimeProvider runtime={runtime}>
      {/* your components */}
    </AssistantRuntimeProvider>
  );
}

The installation guide covers new projects, templates, and API routes.

File renders one file message part. Playable audio/* and video/* files stay inline with their player, filename, optional size, and download link. Every other file remains the compact icon row. With a runtime it renders straight from a message's file part; standalone you hand it the part yourself.

Getting started

Render files from a message

Register File as the File renderer on MessagePrimitive.Parts.

components/assistant-ui/elements/thread.aui.tsx
import { File } from "@/components/assistant-ui/elements/file";
import { MessagePrimitive } from "@assistant-ui/react";

function AssistantMessage() {
  return (
    <MessagePrimitive.Root>
      <MessagePrimitive.Parts components={{ File }} />
    </MessagePrimitive.Root>
  );
}

The Thread element already renders both assistant and user file parts through File, so installing @assistant-ui/thread gives you this without any of the above.

Anatomy

<div>
  <div data-slot="file-player">
    <div data-slot="audio-player | video-player" />
  </div>
  <div>
    <span data-slot="file-size" />
    <a data-slot="file-download" />
  </div>
</div>

The player shows the filename as its title.

The icon row remains for non-media files. File.Player routes playable audio and video data to the matching player: http(s), blob:, and data: URLs are safe to play, and raw base64 becomes a data URI with the part's MIME type. An id or another URL scheme keeps the plain row. The icon depends on mimeType: images get an image icon, PDFs and other text get a document icon, JSON gets a braces icon, audio and video get their own icons, and everything else gets a generic file icon. sourceType states how data is encoded on the wire: "url" for a link, "id" for an opaque reference the download link can't resolve on its own, or omitted to infer it. The size row only appears for inline data (base64 or a data: URI), since a URL or id reference carries no byte count to read.

Examples

Variants and sizes

variant and size are props of File.Root. File itself renders the defaults.

<File.Root variant="muted" size="sm">
  <File.Icon mimeType={part.mimeType} />
  <File.Name>{part.filename}</File.Name>
</File.Root>
VariantDescription
outlineBorder, background on hover (default)
ghostNo border, background on hover
mutedMuted background
SizeDescription
smCompact padding, smaller text
defaultStandard padding
lgLarger padding and text

Restyle the row

File.Root, File.Icon, File.Name, File.Size, File.Download, and File.Player are exported individually for a custom layout:

import { File } from "@/components/assistant-ui/elements/file";

export function CustomFileRow() {
  return (
    <File.Root variant="ghost">
      <File.Icon mimeType={part.mimeType} />
      <File.Name>{part.filename}</File.Name>
      <File.Download
        data={part.data}
        mimeType={part.mimeType}
        filename={part.filename}
        sourceType={part.sourceType}
      />
    </File.Root>
  );
}

export function CustomMediaFile() {
  return (
    <File.Player
      data={part.data}
      mimeType={part.mimeType}
      filename={part.filename}
      sourceType={part.sourceType}
    />
  );
}

API reference

File

ExportRendersNotes
FiledivThe File message-part renderer. Pass to MessagePrimitive.Parts as components.File.
File.RootdivRow with variant and size.
File.IconspanIcon chosen from mimeType.
File.NamespanFilename text; shows "Unnamed file" when empty. File's own row passes it the mimeType label instead.
File.SizespanFormatted byte size; you supply bytes.
File.DownloadaDownload link; null when data can't produce a safe href.
File.PlayerdivRoutes playable audio and video files to the matching inline player; null otherwise.

File part

FieldTypeDescription
filenamestringOptional display name; without one, the icon row of a non-media file shows a label derived from mimeType, such as "PDF file".
datastringThe file payload: base64, a data: URI, or a URL/id per sourceType.
mimeTypestringDrives the icon and, for base64/data: payloads, the download href.
sourceType"url" | "id"Optional. States how to interpret data; omitted infers from its shape.