Attachments

A responsive file list with image, audio, and video previews, file metadata, removal, and application-owned upload states.

  • Project brief.txt

    text/plain · 342 bytes

Files in context

Local image and video files. Retry updates the example state without uploading a document.

Use it for

  • Compose Attachment items inside Attachments for files in a message, a draft, or a tool result.
  • Choose grid, inline, or list layout through variant. Items inherit that layout and can override it individually.
  • Supply stable data IDs, readable filenames, media types, and optional web or local preview addresses.
  • Use useFileAttachments with a browser File array to create local previews with automatic cleanup.
  • Set status, progress, error, and onRetry from an application upload process. Native audio and video controls let the reader start playback.
  • Use preview for application-specific media content, including captions and transcripts where available.

Avoid

  • Treating removal or retry controls as an upload service. The application owns those operations.
  • Passing untrusted script addresses, or revoking preview addresses created by a different owner.

React package

npm install @noorddev/vlak-react

Load the stylesheet once at your app root, then import the components you use.

import "@noorddev/vlak-react/css";
import { Attachment, Attachments, Button } from "@noorddev/vlak-react";

Per-component imports are available at @noorddev/vlak-react/components/attachments.

Copy the source

npx @noorddev/vlak-cli add attachments

Adds the component and its dependencies to components/vlak/. Follow the StyleX setup to compile the source in your application.

shadcn registry

npx shadcn add https://vlak.dev/r/attachments.json

Installs the same source through the shadcn CLI.

"use client";
import { useState } from "react";
import { Attachment, Attachments, Button } from "@noorddev/vlak-react";

export function DraftFiles() {
  const [visible, setVisible] = useState(true);
  return visible ? <Attachments>
    <Attachment data={{ id: "brief", name: "Project brief.txt", mediaType: "text/plain", size: 342 }} onRemove={() => setVisible(false)} />
  </Attachments> : <Button variant="subtle" onClick={() => setVisible(true)}>Reset file</Button>;
}

See the integration example to compose these components with your application's model and data.

Attachment

File metadata and native media previews, with explicit application actions.

PropTypeDefaultDescription
datarequiredAttachmentData
variantAttachmentVariantOverrides the layout inherited from Attachments.
disabledbooleanfalse
onRemove() => void
onRetry() => void
previewReactNodeTrusted application content replaces the automatic media preview.

Also accepts HTMLAttributes<HTMLLIElement>.

The ref reaches HTMLLIElement.

Attachments

A responsive list of application-owned files and media.

PropTypeDefaultDescription
labelstring"Attachments"
variantAttachmentVariant"grid"

Also accepts HTMLAttributes<HTMLUListElement>.

The ref reaches HTMLUListElement.

useFileAttachments (hook)

Creates local preview URLs and revokes them when files leave the list or the owner unmounts.

KeysDoes
TabReaches file links, native media controls, retry, and remove actions.
Enter, SpaceActivates the focused file action or native media control.
  • The named list preserves file grouping. Filenames identify file links and action buttons.
  • Images use decorative thumbnails beside their readable filenames. Audio and video use named native controls without autoplay.
  • Upload status and errors are announced separately from file content. Determinate progress has a file-specific accessible name.
  • Removal and retry have 44px targets and visible focus inherited from Button. Native list and item attributes, className, style, and refs pass through.
  • useFileAttachments preserves file identity and revokes owned preview addresses when files are removed or the owner unmounts.

The same styles are available as CSS. Native HTML provides the static presentation; React or application code supplies state updates and actions.

npm install @noorddev/vlak
import "@noorddev/vlak/css";
<ul class="rs-attachments" aria-label="Attachments"><li class="rs-attachment"><div class="rs-attachment-row"><div class="rs-attachment-info"><p class="rs-attachment-name">Project brief.txt</p><p class="rs-attachment-detail">text/plain · 342 bytes</p></div></div></li></ul>

Classes

.rs-attachments.rs-attachments-grid.rs-attachments-inline.rs-attachments-list.rs-attachment-inline.rs-attachment-list.rs-attachment-thumbnail-inline.rs-attachment-detail-inline.rs-attachment-media-inline.rs-attachment.rs-attachment-row.rs-attachment-thumbnail.rs-attachment-file-icon.rs-attachment-info.rs-attachment-name.rs-attachment-detail.rs-attachment-action.rs-attachment-media.rs-attachment-link.rs-attachment-status.rs-attachment-progress