Skip to content

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

Forward

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 is role="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 ​

AttributeDescriptionTypeDefault
detailSecondary metadata (type · size); in the error state with no detail, shows the localized failure text ("Upload failed"); an explicit value is kept——
downloadableBoolean presence: shows the built-in download button (clicking dispatches oas-download; the download itself is host-owned)boolean—
hrefWhen set, the whole card becomes a clickable trigger (a[part=trigger]) and clicks dispatch oas-open; host preventDefault takes over and blocks default navigation——
nameFile name (title channel; renders media only without error when absent)——
orientationLayout direction: horizontal (default) / vertical (media above text, for narrow columns)——
progressUpload progress 0–100 (clamped; the thin bottom progress bar with role=progressbar renders only while uploading)——
removableBoolean presence: shows the built-in remove button (clicking dispatches oas-remove; the component never removes itself — removal is a host decision)boolean—
sizeThree size steps: default / sm (accepts the small alias) / xs, tightening padding and media per step——
stateUpload state machine: idle / uploading / processing / error / done (default done; uploading/processing reflect aria-busy)stringdone

Events ​

EventDescription
oas-downloadDispatched when the built-in download button is clicked, detail
oas-openDispatched when the href card trigger is clicked, detail { href }; cancelable — host preventDefault also blocks the anchor default navigation
oas-removeDispatched when the built-in remove button is clicked, detail { name }; never self-removes

Slots ​

NameDescription
actionsAppends custom actions (after the built-in download/remove buttons)
mediaMedia slot (icon/thumbnail); any slotted content overrides the built-in default glyph

oas-attachment-group ​

Slots ​

NameDescription
defaultAttachment card sequence (oas-attachment or any cards; snap-scrolls with edge fade when overflowing horizontally)

CSS Variables ​

CSS VariableDefault
--oas-attachment-group-fade24px
--oas-attachment-group-gapvar(--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).

Released under the MIT OR Apache-2.0 License.