Attachment
A conversation attachment row: media (icon/thumbnail) + file name/metadata + upload state machine + actions (download/remove/whole-card trigger). For sending files in chats, uploading images to AI conversations, support ticket attachments, etc.
Basic Usage
Basic attachment rows
name is the file name and detail the secondary metadata (type · size); downloadable shows the built-in download button (clicking dispatches oas-download; the actual download is host-owned).
Upload state machine (state)
idle / uploading / processing / error / done
`uploading`/`processing` reflect aria-busy and show a spinner; `uploading` renders a thin bottom progress bar (progress 0–100, clamped); `error` shows the localized failure text when detail is absent ("Upload failed"), or keeps the host's text when given.
The state machine has five states: idle / uploading / processing / error / done (default done); removable shows the remove button (clicking dispatches oas-remove; the component never removes itself — removal is a host decision).
Sizes (size)
default / sm / xs
Three size steps: default / sm (accepts the small alias) / xs, tightening padding and media per step.
Vertical layout & thumbnails (orientation / media slot)
vertical + slot=media thumbnail
orientation="vertical" stacks media above text (narrow columns/cards); any content in slot="media" (any <img>/<svg>, max 64px) overrides the default glyph; with no slotted media the built-in file glyph renders (decorative, aria-hidden) — the media form follows naturally from whether the slot has content, no form attribute needed.
Whole-card trigger (href)
href + oas-open event feedback
Click the card above to trigger oas-open (this demo blocks navigation and shows feedback).
With href, the whole card becomes <a part="trigger"> and clicks dispatch oas-open (detail { href }); calling preventDefault in the host handler takes over opening (preview/new window) and the component blocks default navigation accordingly.
Actions & event feedback
removable / downloadable / slot=actions
Click remove/download — received events show up here.
The built-in buttons' accessible names include the file name (e.g. "Remove draft-v1.docx" — a bare "Remove" is ambiguous for screen readers); slot="actions" appends custom actions (the component owns no specific actions; events come from the slot content).
Attachment group (oas-attachment-group)
Horizontal scroll + snap + edge fade
oas-attachment-group is a horizontal scroll row: items snap one by one (scroll-snap-align: start) and edges fade with a mask while scrollable (scrollability is reflected as data-scrollable="start end"). It owns no data (a pure container with no attributes); put oas-attachment or any cards in the default slot. Focus it with Tab and scroll horizontally with the arrow keys. Spacing and fade width use the CSS variables --oas-attachment-group-gap / --oas-attachment-group-fade.
Accessibility
- Busy states reflect
aria-busy; the progress bar isrole="progressbar"with min/max/now values. - Icon-only buttons carry accessible names including the target file name; decorative glyphs are always
aria-hidden. - The error state pairs color with text (never color alone); when slotting real thumbnails give them readable names (
alt/aria-label).
API
oas-attachment
Attributes
| Attribute | Description | Type | Default |
|---|---|---|---|
detail | Secondary metadata (type · size); in the error state with no detail, shows the localized failure text ("Upload failed"); an explicit value is kept | — | — |
downloadable | Boolean presence: shows the built-in download button (clicking dispatches oas-download; the download itself is host-owned) | boolean | — |
href | When set, the whole card becomes a clickable trigger (a[part=trigger]) and clicks dispatch oas-open; host preventDefault takes over and blocks default navigation | — | — |
name | File name (title channel; renders media only without error when absent) | — | — |
orientation | Layout direction: horizontal (default) / vertical (media above text, for narrow columns) | — | — |
progress | Upload progress 0–100 (clamped; the thin bottom progress bar with role=progressbar renders only while uploading) | — | — |
removable | Boolean presence: shows the built-in remove button (clicking dispatches oas-remove; the component never removes itself — removal is a host decision) | boolean | — |
size | Three size steps: default / sm (accepts the small alias) / xs, tightening padding and media per step | — | — |
state | Upload state machine: idle / uploading / processing / error / done (default done; uploading/processing reflect aria-busy) | string | done |
Events
| Event | Description |
|---|---|
oas-download | Dispatched when the built-in download button is clicked, detail |
oas-open | Dispatched when the href card trigger is clicked, detail { href }; cancelable — host preventDefault also blocks the anchor default navigation |
oas-remove | Dispatched when the built-in remove button is clicked, detail { name }; never self-removes |
Slots
| Name | Description |
|---|---|
actions | Appends custom actions (after the built-in download/remove buttons) |
media | Media slot (icon/thumbnail); any slotted content overrides the built-in default glyph |
oas-attachment-group
Slots
| Name | Description |
|---|---|
| default | Attachment card sequence (oas-attachment or any cards; snap-scrolls with edge fade when overflowing horizontally) |
CSS Variables
| CSS Variable | Default |
|---|---|
--oas-attachment-group-fade | 24px |
--oas-attachment-group-gap | var(--oas-space-2_5) |
Parts: ::part(attachment), ::part(trigger), ::part(media), ::part(title), ::part(description), ::part(spinner), ::part(progress), ::part(actions), ::part(download), ::part(remove).