<!-- Generated by scripts/gen-docs.mts from the JSDoc in registry/. Do not edit; run `pnpm run docs`. -->

# Attachment

A file attached to a chat message, or waiting to be sent with one: an icon for its kind, its name and size. With `href` it is a link that opens or downloads the file; with `onOpen` it opens the file in the app, such as in a `Lightbox`; with `onRemove` it has a remove button, named after the file, for the composer. Long names truncate.

```tsx
import { Attachment } from "@/components/ouro/message/attachment";
```

## Example

```tsx
<Attachment name="menu.pdf" size={file.size} contentType={file.type} href={file.url} />
<Attachment name={file.name} size={file.size} onRemove={() => remove(file)} />
<Attachment name="crumb.jpg" contentType="image/jpeg" href={file.url} onOpen={() => showInLightbox(file)} />
```

## Use instead when

- Use `Link` instead for a link that is not a file, and `Avatar` for a person's picture.

## Props

Type: `AttachmentProps`.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `className` | `string` |  | Layout only: margins, width (`mt-2`). Appearance classes warn in development. |
| `contentType` | `string` |  | The file's MIME type (`file.type`). With the name's extension, it picks the icon: "application/pdf" or "menu.pdf" shows a PDF's. |
| `download` | `boolean` |  | Downloads the file instead of opening it (the link's `download` attribute). Needs `href`. |
| `formatSize` | `((bytes: number) => string)` | `"512 B"`, "2 kB", "1.2 MB", in steps of 1024 | Writes `size` for other languages or units. |
| `href` | `string` |  | Where the file opens or downloads. With it, the attachment is a link named by the file and its size. |
| `icon` | `ReactNode` |  | An icon to show instead of the one for the file's kind, such as the app's own file-type icons. |
| `kind` | `"audio" \| "code" \| "video" \| "image" \| "sheet" \| "doc" \| "slides" \| "pdf" \| "zip" \| "file"` | from `contentType`, then the name's extension, else "file" | The kind of file, for its icon, when the type and the name do not say: a document, a spreadsheet, slides, a PDF, an image, a video, audio, an archive, code, or any other file. |
| `name` (required) | `string` |  | The file's name, as the user sees it: "menu.pdf". Required, so every file has a name. |
| `onOpen` | `((event: MouseEvent<HTMLElement>) => void)` |  | Opens the file in the app, for example in a `Lightbox`. Without `href` the attachment is a button that calls it. With `href` it stays a link: a plain click calls it instead of following the link, and a click with a modifier key (a new tab, a new window) or the middle button follows the link as usual. |
| `onRemove` | `(() => void)` |  | Shows a remove button, which calls this. Use it while composing a message, before it is sent. |
| `ref` | `Ref<HTMLDivElement>` |  | Reaches the rendered element. |
| `removeLabel` | `((name: string) => string)` | `` (name) => `Remove ${name}` `` | The remove button's accessible name, for other languages. |
| `size` | `number` |  | The file's size in bytes (`file.size`), shown as "1.2 MB". |

## Native attributes

Also accepts the attributes in React's `HTMLAttributes` (`id`, `aria-*`, event handlers), passed to the rendered element, except those named on this page.

## Don't use

These are not props. Passing one fails the type check with the fix in the error, and in development a console message names the fix.

- `filename`: Not a prop. The file's name is `name`: `<Attachment name="menu.pdf" />`.
- `fileName`: Not a prop. The file's name is `name`: `<Attachment name="menu.pdf" />`.
- `onDelete`: Not a prop. Use `onRemove`: `<Attachment name="menu.pdf" onRemove={remove} />`.
- `onDismiss`: Not a prop. Use `onRemove`: `<Attachment name="menu.pdf" onRemove={remove} />`.
- `url`: Not a prop. The file's address is `href`: `<Attachment name="menu.pdf" href="/menu.pdf" />`.

## `className` is for layout only

Pass margins, width and grid placement (`mt-4`, `w-full`, `col-span-2`). Your classes always win over Ouro UI's: Attachment merges `className` last with `cn` (tailwind-merge), so a class that conflicts with its own replaces it.[^layout-classes]

Appearance comes from props, not classes. In development, a class that sets appearance logs one warning per component instance, naming the prop to use instead. A class sets appearance when, after its variants (`hover:`, `sm:`) and any `!` are removed, it starts with `bg-`, `text-`, `border-`, `rounded-`, `shadow-`, `font-`, `ring-`, `from-`, `via-`, `to-`, `fill-` or `stroke-`, or is `border`, `rounded`, `shadow` or `ring`, or has a `dark:` variant. Text wrapping, overflow and table layout classes (`text-wrap`, `text-ellipsis`, `border-collapse`) are layout and do not warn.

Alignment classes (`text-center`) warn too: set alignment on a parent element.

[^layout-classes]: test:registry/ouro/components/ouro/message/attachment.test.tsx::Attachment > forwards a ref and lets app layout classes win verify:testExists(registry/ouro/components/ouro/message/attachment.test.tsx::Attachment > forwards a ref and lets app layout classes win)
