Attachment

Attachment.Root shows one file in a composer or a message: a preview, its name, a line such as its size, an upload bar, and a button that removes it. It shows the state of an upload; the upload itself is your code, such as a fetch for each file that useDropzone accepts.

On this page
<Attachment.Root status={file.status}>
  <Attachment.Preview>
    <FileText aria-hidden />
  </Attachment.Preview>
  <Attachment.Name>{file.name}</Attachment.Name>
  <Attachment.Meta>{file.size}</Attachment.Meta>
  {file.status === 'uploading' ? <Attachment.Progress value={file.progress} max={100} /> : null}
  <Attachment.Remove onClick={() => remove(file)} />
</Attachment.Root>
  • quarterly-report.pdf1.2 MB
  • whiteboard.jpgUploading, 0%
  • recording.movToo large to upload

Parts

  • Attachment.Root is a div with role="group", named by Attachment.Name unless you give it aria-label or aria-labelledby. Its status is ready, uploading or error, and sets data-status. An error colors the border and Attachment.Meta with the attachment.border.error and attachment.meta.fg.error tokens. It is at most attachment.max-width wide.
  • Attachment.Preview is a box of attachment.preview.size at the start. An img or video, or the img in a picture, covers it and is cropped to it; an svg icon takes attachment.icon.size.
  • Attachment.Name is the file name, as text. A name too long for the width ends in an ellipsis.
  • Attachment.Meta is a line under the name, such as the size and type, or what went wrong.
  • Attachment.Progress is a Progress bar under them, for an upload. It is named by Attachment.Name unless you give it aria-label or aria-labelledby.
  • Attachment.Remove is a ghost Button at the end. With no content it shows the close glyph and is named by the removeAttachment string, Remove {name} in English.

Leave out a part you don't need, and the others close up.

Removing

When an attachment that holds focus is removed, and nothing else has focus once React has committed the update, focus moves to the remove button of the attachment now in its place, else the one before. The attachments counted are its parent's children, or, when each attachment is the only child of an li, the items of the same list. Focus you move in your own onClick stays where you put it. When no attachment is left, focus is yours to place, such as on the composer's text field.

Accessible composition

Todae handles: A group for each file, named by its file name. A remove button named after the file, and a progress bar named by it. Focus moving to the next remove button when an attachment holding focus is removed.

You supply: The file name in Attachment.Name. An alt="" on a thumbnail, since the name already says what the file is. Focus after the last attachment is removed. An upload error said in words in Attachment.Meta, and announced when it happens, such as through useAnnouncer.

Watch for: Showing an error by the border color alone. Announcing every step of an upload's progress: the bar can be read when a reader moves to it.

When to use

When: A file attached to a message, before or after it is sent.

When not: A text label with a remove button → Chip. Choosing files → useDropzone.

Props

Attachment.Root props
NameTypeDescription
status"ready" | "uploading" | "error"

Sets data-status. An error takes the attachment.border.error and attachment.meta.fg.error tokens.

Default: "ready"

Attachment.Preview props
NameTypeDescription
childrenReact.ReactNode

A thumbnail, such as an img with alt="", or an icon of the file type.

Attachment.Name props
NameTypeDescription
children Requiredstring

The file name. Text only.

Attachment.Meta props
NameTypeDescription
childrenReact.ReactNode

Size, type, or an error.

Attachment.Progress props
NameTypeDescription
valuenumber

How far the upload has come, out of max. Leave it out when the end is unknown.

Attachment.Remove props
NameTypeDescription
childrenReact.ReactNode

The button's content. Without it, the close glyph, named by the removeAttachment string, Remove {name} in English.