# Attachments List Example

> Example implementation of attachments list.

A shadcn/ui block from the [@ai-elements](https://ai-sdk.dev/elements) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/ai-elements/example-attachments-list).

- Page, with a live preview: https://shadcn.exchange/r/ai-elements/example-attachments-list
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/ai-elements/example-attachments-list-light-0bf4cd606f6907d5.png
- Registry item: https://ai-sdk.dev/elements/api/registry/example-attachments-list.json
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://ai-sdk.dev/elements/api/registry/example-attachments-list.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- npm packages: `nanoid`
- Registry items: `https://elements.ai-sdk.dev/attachments.json`

## Files

### `registry/default/examples/attachments-list.tsx`

```tsx
"use client";

import {
  Attachment,
  AttachmentInfo,
  AttachmentPreview,
  AttachmentRemove,
  Attachments,
} from "@/components/ai-elements/attachments";
import { nanoid } from "nanoid";
import { memo, useCallback, useState } from "react";

const initialAttachments = [
  {
    filename: "mountain-landscape.jpg",
    id: nanoid(),
    mediaType: "image/jpeg",
    type: "file" as const,
    url: "https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=400&h=400&fit=crop",
  },
  {
    filename: "quarterly-report-2024.pdf",
    id: nanoid(),
    mediaType: "application/pdf",
    type: "file" as const,
    url: "",
  },
  {
    filename: "product-demo.mp4",
    id: nanoid(),
    mediaType: "video/mp4",
    type: "file" as const,
    url: "",
  },
  {
    filename: "api-reference",
    id: nanoid(),
    mediaType: "text/html",
    title: "API Documentation",
    type: "source-document" as const,
    url: "https://docs.example.com/api",
  },
  {
    filename: "meeting-recording.mp3",
    id: nanoid(),
    mediaType: "audio/mpeg",
    type: "file" as const,
    url: "",
  },
];

interface AttachmentItemProps {
  attachment: (typeof initialAttachments)[0];
  onRemove: (id: string) => void;
}

const AttachmentItem = memo(({ attachment, onRemove }: AttachmentItemProps) => {
  const handleRemove = useCallback(
    () => onRemove(attachment.id),
    [onRemove, attachment.id]
  );
  return (
    <Attachment data={attachment} key={attachment.id} onRemove={handleRemove}>
      <AttachmentPreview />
      <AttachmentInfo showMediaType />
      <AttachmentRemove />
    </Attachment>
  );
});

AttachmentItem.displayName = "AttachmentItem";

const Example = () => {
  const [attachments, setAttachments] = useState(initialAttachments);

  const handleRemove = useCallback((id: string) => {
    setAttachments((prev) => prev.filter((a) => a.id !== id));
  }, []);

  return (
    <div className="flex items-center justify-center p-8">
      <Attachments className="w-full max-w-md" variant="list">
        {attachments.map((attachment) => (
          <AttachmentItem
            attachment={attachment}
            key={attachment.id}
            onRemove={handleRemove}
          />
        ))}
      </Attachments>
    </div>
  );
};

export default Example;
```
