Skip to content

Attachment

hc-attachment is a file card: icon, filename, size, and a remove button on one grid row. hc-attachments is its wrapping list — pluralized like hc-chips, because it is a list of attachments — and keeping it a real <ul>/<li> keeps the set announceable. Pure CSS: the dropzone collects the files, the file-upload recipe owns the multipart + progress contract, and hc-progress is the bar installUploadProgress() drives.

  • notes.md4 KB

No data-state means the file is settled — uploaded and listed. The icon slot takes an inline SVG (or an emoji placeholder); it is decorative, so keep it aria-hidden. A long filename truncates with an ellipsis rather than breaking the row.

data-state="uploading" reveals the card’s progress row — a native hc-progress element spanning the full card width, whose value is driven by installUploadProgress() while htmx uploads the form. data-state="error" tints the card via the shared status tokens.

  • report.pdf1.2 MB
  • huge.iso9.8 GB

The progress row only renders while data-state="uploading" — the server’s success fragment simply swaps in the settled card (no state, no <progress>), and a failure swaps in data-state="error".

The attachment card is the display half of a file-upload flow; the other halves already exist:

  • The dropzone collects the files — its drop assigns to a native <input type="file"> and fires a normal change, so the surrounding form serializes as usual.
  • The file-upload recipe owns the multipart + progress contract: htmx posts the form, installUploadProgress() maps real upload progress onto the <progress> element, and the response appends the settled fragment and resets the form out-of-band.
  • The remove control is a real <button> whose aria-label includes the filename — “Remove report.pdf”, never a bare “×”.
  • The <ul>/<li> structure keeps the set announceable with position and count; give the list an aria-label when no heading names it.
  • The <progress> carries an accessible name (its aria-label also naming the file), so the announced percentage is attributable.
  • The icon is decorative — aria-hidden="true"; the filename text is the identity.

Component tokens (in component.tokens.json):

Token pathPurpose
attachment.bg / border / radiusCard surface.
attachment.gapGrid gap inside the card and between cards.
attachment.padding-block / padding-inlineCard padding.
attachment.name-fg / size-fgFilename / size text.
attachment.icon-sizeIcon and remove-button square.
attachment.error-bg / error-borderError-state card.
Show the generated CSS variables
--hc-attachment-bg | -border | -radius | -gap
--hc-attachment-padding-block | -padding-inline
--hc-attachment-name-fg | -size-fg | -icon-size
--hc-attachment-error-bg | -error-border
  • Dropzone — collects the files this card displays.
  • Progress — the native bar inside the uploading state.
  • Chip — the lighter token for facts that aren’t files.
  • File upload recipe — the full multipart + live-progress pattern.