Attachment

One shape of a file attachment everywhere (approved by the owner 27 September 2026, variant A; delivered in acrm !3997). React <Attachment> (packages/ui/src/components/Attachment.tsx), CSS apps/web/src/ds/attachment.css (.acrm-att*).

It replaces four earlier, unrelated families that had each grown its own look: the mail reader's segmented frame (.mv-att), the compose chip (.mc-att), the template preview's dashed auto chip (.pv-att-auto) and the task tile (.tk-att-*, AttachmentTile). All four contexts render the same component now — only the props change.

When to use

  • Any file the user attaches, receives or is about to receive: mail (reading and composing), tasks, template previews, meetings, activities.
  • A row of several files — wrap them in .acrm-atts (flex-wrap, --sp-2 gap); the row wraps onto more than one line.

When not to use

  • A file inside a data table cell — that has its own column, not a chip.
  • A picture meant to be seen, not opened (an avatar, a logo) — that is Avatar or a plain <img>.

Anatomy

  • Name: <Button variant="ghost" compact> with the type glyph and the name, opening the preview (onOpen) — when there is nothing to open, a plain static span (.acrm-att-static) with the same glyph and text.
  • Glyph: attachmentGlyph(name, mime) reads the MIME type first, falls back to the file extension; unknown types get a generic file-text icon. It marks the file's type only — the separate "file type badge" design is out of scope here.
  • Size: muted meta (.acrm-att-sz), formatAttachmentSize(bytes) — one algorithm, used everywhere: below 1 MB it rounds to whole kB ("482 kB", minimum 1 kB so a tiny file never reads "0 kB"); at or above 1 MB it shows MB to one decimal with a comma, the app's number convention ("2,3 MB"). No other place in the app formats a file size its own way.
  • Actions: IconButton size="sm", in this order — download (downloadHref, opens in a new tab) → save to CRM (onSave, file-import) → remove (onRemove, x). Remove is always the LAST action; only the actions whose prop is set are rendered.
  • auto: a file that does not exist yet (a template's automatic attachment, created only when the mail is sent) — dashed border, no size, no actions, muted text.
  • busy: an upload or save in progress — actions disabled, name dimmed; pass a label such as "Foto_z_mobilu.heic · nahrává se…" to say so.
  • title (tooltip) defaults to the file name; label overrides the visible name text without changing the tooltip default.
  • Height 28px, matching the chip row (.tk-chip) rhythm elsewhere in the app.

Best practices

Do

  • Pass every action the context actually supports — a read-only task detail gets only downloadHref, compose gets only onRemove, the mail reader gets downloadHref + onSave.
  • Wrap a multi-file list in .acrm-atts so chips wrap instead of overflowing.
  • Give auto chips a label that explains what will exist and when ("Výkaz práce (PDF, vznikne při odeslání)").
  • Let the chip's max-width: 100% and ellipsis do the truncation — do not cap the width yourself.

Don't

  • Reintroduce a screen-specific attachment chip — the four replaced families are gone (.mv-att, .mc-att, .pv-att-auto, AttachmentTile); use <Attachment>.
  • Format a file size by hand — always formatAttachmentSize.
  • Put a trailing action after remove — remove is always last.
  • Add actions to an auto chip — it has none; the file does not exist yet.

Content

  • Name is the file name as stored, never truncated in the title tooltip — only the visible text ellipsises.
  • Action labels are per-action and localised (labels prop overrides the Czech defaults: "Náhled přílohy", "Stáhnout", "Uložit do dokumentů", "Odebrat"); each IconButton gets aria-label="<action>: <file name>" so multiple attachments in one list stay distinguishable to a screen reader.
  • Icon button — every action in the chip.
  • Button — the ghost compact name button that opens the preview.
  • Item list, Email list, Task list — the rows and threads Attachment appears inside (mail reader, compose, task dialog, activities).
  • Stories: components--attachment--default, --variants, --states, --composition. No Sizes (one height) and no With icon & kbd (the glyph is the file type, there is no shortcut).

Source: docs/attachment/attachment.usage.md · GitLab