Data Display · astro-ui · Attachment

Attachment

File attachment card with media, state hooks, and action slots.

Attachment shows an attached file as a composed card: a media box (icon or image thumbnail), a title and description line, and an actions area. It is purely presentational — upload progress, errors, and removal are wired app-side. Five state values render as data-state attributes (idle is dashed; error is destructive) that you can target from your own CSS, and orientation stacks the card vertically (image-first) or in a row.

Features

  • Five state hooks: idle (dashed), uploading, processing, error, done — via data-state
  • Media variants: icon (paperclip) or image thumbnail, or your own media slot
  • Three sizes (xs/sm/md) and horizontal/vertical orientation
  • Named slots: media, title, description, actions
  • Zero JS — all behavior (pick, upload, remove) stays app-side

Usage

---
import { Attachment, Button } from "astro-ui";
---

<Attachment
  state="done"
  title="quarterly-report.pdf"
  description="PDF · 2.4 MB"
>
  <Button variant="ghost" size="icon" slot="actions" aria-label="Remove file">✕</Button>
</Attachment>

Demos

Basic

quarterly-report.pdfPDF · 2.4 MB
<Attachment
  title="quarterly-report.pdf"
  description="PDF · 2.4 MB"
>
  <Button variant="ghost" size="icon" slot="actions" aria-label="Remove file">✕</Button>
</Attachment>

States

Drop files hereor browse
upload.csv64% · 1.2 MB of 1.9 MB
scan.zipScanning for viruses…
installer.exeFile type not allowed
logo.svgSVG · 12 KB
<Attachment state="idle" title="Drop files here" description="or browse" />
<Attachment state="uploading" title="upload.csv" description="64% · 1.2 MB of 1.9 MB" progress={64} />
<Attachment state="processing" title="scan.zip" description="Virus scan…" />
<Attachment state="error" title="file.exe" description="Type not allowed" />
<Attachment state="done" title="logo.svg" description="SVG · 12 KB" />

Sizes

notes.txt1 KB
notes.txt1 KB
notes.txt1 KB
<Attachment size="xs" title="notes.txt" description="1 KB" />
<Attachment size="sm" title="notes.txt" description="1 KB" />
<Attachment size="md" title="notes.txt" description="1 KB" />

Vertical with image

cover-art.pngPNG · 480 KB
<Attachment orientation="vertical" title="cover.png" description="PNG · 480 KB">
  <img slot="media" src="/cover.png" alt="" />
</Attachment>

Group

brief.pdfPDF · 2.4 MB
photo.pngPNG · 800 KB
video.movExceeds 10 MB limit
<div class="attachment-row" role="list">
  <Attachment role="listitem" title="a.pdf" description="PDF · 2.4 MB" />
  <Attachment role="listitem" title="b.png" description="PNG · 800 KB" />
</div>

API

Props

PropTypeDefaultDescription
state"idle" | "uploading" | "processing" | "error" | "done""done"Visual state; renders as data-state for styling hooks (idle = dashed border, error = destructive).
size"xs" | "sm" | "md""md"Card and media-box scale.
orientation"horizontal" | "vertical""horizontal"Media above text (vertical) or inline row (horizontal).
media"icon" | "image""icon"Media-box content: paperclip icon or image fallback; override with the media slot.
progressnumber—0–100 — renders a determinate 2px progress bar on the card's bottom edge; omit for an indeterminate sweep while uploading/processing.
titlestring—Title line (overridden by the title slot).
descriptionstring—Muted second line (overridden by the description slot).
classstring—Merged via cn(); Tailwind classes welcome.
idstring—Element id.

Accessibility

Implemented accessibility features — semantics, ARIA wiring, and keyboard behavior that ship with the component.

  • Purely presentational card — no implicit widget role, so it never traps focus
  • State is exposed via data-state attributes; announce changes app-side with aria-live when they matter
  • Action buttons keep their own accessible names — icon-only actions must pass aria-label
  • Decorative media and the paperclip fallback icon are aria-hidden

FAQ

How do I handle uploads?

The component is presentational by design. Wrap it with your own file input + submit flow, flip state through idle → uploading → done, and announce progress with an aria-live region app-side.

How do I remove an attachment?

Put a button in the actions slot with an explicit aria-label — icon-only actions need a name. Wire the click handler or a form submit in your app; the component ships zero JS.

Changelog

Version history mentioning Attachment.

v0.1.0 — 2026-11-11
added
  • Data display (10): Badge, Avatar, Attachment, Table, Progress, Bubble, Chart, Empty, Tag, Timeline.