Skip to content

Documentation

neelam-ui

Search documentation

Getting Started
Forms
Overlays
Navigation
Data Display
Layout
AI & Chat
Blocks
GitHub repository

Attachment

A file or image attached to a message — a download link once posted, or a removable chip while staged in a composer.

release-notes.pdf248 KB

Usage#

import { Attachment } from "neelam-ui";
 
<Attachment name="release-notes.pdf" size="248 KB" url="/release-notes.pdf" />

name is the visible filename, and doubles as the alt text for an image attachment. size is a human-readable string like "2.4 MB" — formatting bytes is left to you, since the right units and locale vary.

Posted or pending#

The component has two modes, and onRemove is what selects between them:

  • Without onRemove — an attachment already posted in a message. Given a url it becomes a real link, and an image renders full-size and clickable.
  • With onRemove — a file staged in a composer before sending. A remove button appears, and an image switches to a small captioned thumbnail, because a pending upload is not something to click through to yet.
diagram.png84 KB
notes.txt2 KB

Given a url, the clickable element is a real <a> inside the component, not a <div> with a click handler. The outer element stays a plain <div> either way, so the forwarded ref's type does not depend on whether a prop was passed.

For type="file" the anchor carries download; for type="image" it opens in a new tab.

download is same-origin only

Browsers honour the download attribute only for same-origin URLs, or ones a CORS response explicitly permits. Point it at a cross-origin CDN and the file will open rather than save — serve it from your own origin, or set the appropriate headers.

Keyboard#

Keyboard shortcuts
KeyBehaviour
TabReaches the file link (when url is set), then the remove button (when onRemove is set).
EnterFollows the link — downloading a file, or opening an image in a new tab.
EnterSpaceActivates the remove button.

An attachment with neither url nor onRemove is static content and is not focusable at all, which is correct — there is nothing to do with it.

Accessibility#

  • The remove button always has a name: removeLabel, defaulting to "Remove {name}", so a row of chips does not announce three identical "Remove" buttons.
  • The file icon is aria-hidden — the filename beside it is the content.
  • An image attachment uses name as its alt, so the file is identified rather than announced as an unlabelled image.
  • External links carry rel="noopener noreferrer".

Say when a link leaves the page

An image attachment opens in a new tab. If that is surprising in context, add a visually hidden "(opens in a new tab)" to the name — an unexpected context switch is disorienting for screen reader and screen magnifier users alike.

API reference#

Props for Attachment
PropTypeDefault
namerequired

The file's name — shown in the file row, and used as the image's `alt` text for an image attachment.

string
onRemove

Shows a remove button and calls this when it's clicked. Meant for a file staged in a composer before it's sent, not one already posted in a message — supplying it also switches an image attachment from the full-size linked photo to a small captioned thumbnail, since a pending upload isn't something to click through to yet.

(() => void)
removeLabel

Accessible label for the remove button. Defaults to `"Remove {name}"`.

string
size

A human-readable size, e.g. `"2.4 MB"`.

string
type

Renders an image preview instead of the generic file row. Defaults to `"file"`.

enumfile
url

Where the file lives. Given a `url`, the attachment becomes a real link: `target="_blank"` for an image, `download` for a file. Browsers only honor `download` for same-origin URLs (or ones a CORS response explicitly permits) — see `DECISIONS.md`.

string

Also accepts every native <div> attribute except children — the content is built from name, size, and type.