Attachment

Displays a file or image with its media, metadata, upload state and actions

Theme
<div class="flex flex-col gap-3">
    <div class="flex gap-3">
        <sa-attachment orientation="AttachmentOrientation.Vertical">
            <sa-attachment-media variant="AttachmentMediaVariant.Image">
                <img src="/gradients/gradient-1.jpg" alt="Sunrise over the Arashiyama bamboo grove"/>
            </sa-attachment-media>
            <sa-attachment-content>
                <sa-attachment-title>arashiyama-grove.jpg</sa-attachment-title>
                <sa-attachment-description>JPG · 1.8 MB</sa-attachment-description>
            </sa-attachment-content>
        </sa-attachment>
        <sa-attachment orientation="AttachmentOrientation.Vertical">
            <sa-attachment-media variant="AttachmentMediaVariant.Image">
                <img src="/avatars/avatar-1.jpg" alt="Priya Raman at the Fushimi Inari shrine"/>
            </sa-attachment-media>
            <sa-attachment-content>
                <sa-attachment-title>priya-at-fushimi.jpg</sa-attachment-title>
                <sa-attachment-description>JPG · 1.1 MB</sa-attachment-description>
            </sa-attachment-content>
        </sa-attachment>
        <sa-attachment orientation="AttachmentOrientation.Vertical">
            <sa-attachment-media variant="AttachmentMediaVariant.Image">
                <img src="/avatars/avatar-3.jpg" alt="Mika Tanaka in the Gion district"/>
            </sa-attachment-media>
            <sa-attachment-content>
                <sa-attachment-title>mika-at-gion.jpg</sa-attachment-title>
                <sa-attachment-description>JPG · 940 KB</sa-attachment-description>
            </sa-attachment-content>
        </sa-attachment>
    </div>
    <sa-attachment state="AttachmentState.Uploading" class="w-full">
        <sa-attachment-media>
            <sa-spinner/>
        </sa-attachment-media>
        <sa-attachment-content>
            <sa-attachment-title>hotel-invoice.pdf</sa-attachment-title>
            <sa-attachment-description>Uploading · 64%</sa-attachment-description>
        </sa-attachment-content>
        <sa-attachment-actions>
            <sa-attachment-action aria-label="Cancel uploading hotel-invoice.pdf">
                <sa-icon name="x"/>
            </sa-attachment-action>
        </sa-attachment-actions>
    </sa-attachment>
    <sa-attachment class="w-full">
        <sa-attachment-media>
            <sa-icon name="file-text"/>
        </sa-attachment-media>
        <sa-attachment-content>
            <sa-attachment-title>kyoto-itinerary.pdf</sa-attachment-title>
            <sa-attachment-description>PDF · 2.4 MB</sa-attachment-description>
        </sa-attachment-content>
        <sa-attachment-actions>
            <sa-attachment-action aria-label="Remove kyoto-itinerary.pdf">
                <sa-icon name="x"/>
            </sa-attachment-action>
        </sa-attachment-actions>
    </sa-attachment>
</div>

Usage

An attachment is composed of <sa-attachment> wrapping a <sa-attachment-media> region, a <sa-attachment-content> block holding the title and description, and a <sa-attachment-actions> row. Add a <sa-attachment-button-trigger> or <sa-attachment-link-trigger> to make the whole card clickable. Place attachments in a <sa-attachment-group> to lay them out as a scrolling row.

<sa-attachment-group>
    <sa-attachment state="..." size="..." orientation="...">
        <sa-attachment-media variant="...">
            ...
        </sa-attachment-media>
        <sa-attachment-content>
            <sa-attachment-title>...</sa-attachment-title>
            <sa-attachment-description>...</sa-attachment-description>
        </sa-attachment-content>
        <sa-attachment-actions>
            <sa-attachment-action>...</sa-attachment-action>
        </sa-attachment-actions>
        <sa-attachment-button-trigger/>
    </sa-attachment>
</sa-attachment-group>

Every part is optional. An attachment with only a media region is a bare thumbnail; one with only content is a filename chip. The padding follows what is present, so an attachment stays correctly spaced whichever parts you leave out.

Examples

State

Set state to indicate the upload or processing state. Idle draws a dashed border, for a card standing in as a drop target before anything has been attached. Uploading and Processing shimmer the title. Error turns the border and the description red, and Done — the default — is a completed, uploaded file.

Theme
<div class="flex flex-col gap-3">
    <sa-attachment state="AttachmentState.Idle">
        <sa-attachment-media>
            <sa-icon name="upload"/>
        </sa-attachment-media>
        <sa-attachment-content>
            <sa-attachment-title>Attach a travel document</sa-attachment-title>
            <sa-attachment-description>PDF, JPG or PNG up to 10 MB</sa-attachment-description>
        </sa-attachment-content>
    </sa-attachment>
    <sa-attachment state="AttachmentState.Uploading">
        <sa-attachment-media>
            <sa-spinner/>
        </sa-attachment-media>
        <sa-attachment-content>
            <sa-attachment-title>flight-confirmation.pdf</sa-attachment-title>
            <sa-attachment-description>Uploading · 64%</sa-attachment-description>
        </sa-attachment-content>
        <sa-attachment-actions>
            <sa-attachment-action aria-label="Cancel uploading flight-confirmation.pdf">
                <sa-icon name="x"/>
            </sa-attachment-action>
        </sa-attachment-actions>
    </sa-attachment>
    <sa-attachment state="AttachmentState.Processing">
        <sa-attachment-media>
            <sa-icon name="id-card"/>
        </sa-attachment-media>
        <sa-attachment-content>
            <sa-attachment-title>passport-priya.jpg</sa-attachment-title>
            <sa-attachment-description>Checking the expiry date</sa-attachment-description>
        </sa-attachment-content>
    </sa-attachment>
    <sa-attachment state="AttachmentState.Error">
        <sa-attachment-media>
            <sa-icon name="circle-alert"/>
        </sa-attachment-media>
        <sa-attachment-content>
            <sa-attachment-title>hotel-invoice.pdf</sa-attachment-title>
            <sa-attachment-description>Upload failed — the file is over 10 MB</sa-attachment-description>
        </sa-attachment-content>
        <sa-attachment-actions>
            <sa-attachment-action aria-label="Retry uploading hotel-invoice.pdf">
                <sa-icon name="rotate-cw"/>
            </sa-attachment-action>
        </sa-attachment-actions>
    </sa-attachment>
    <sa-attachment state="AttachmentState.Done">
        <sa-attachment-media>
            <sa-icon name="file-text"/>
        </sa-attachment-media>
        <sa-attachment-content>
            <sa-attachment-title>kyoto-itinerary.pdf</sa-attachment-title>
            <sa-attachment-description>PDF · 2.4 MB</sa-attachment-description>
        </sa-attachment-content>
        <sa-attachment-actions>
            <sa-attachment-action aria-label="Remove kyoto-itinerary.pdf">
                <sa-icon name="x"/>
            </sa-attachment-action>
        </sa-attachment-actions>
    </sa-attachment>
</div>

Size

Set size to AttachmentSize.Small or AttachmentSize.ExtraSmall to compact the attachment card. The smaller sizes suit a dense list or the row of pending files above a message composer, where the attachment is supporting content rather than the subject of the screen. Consider leaving <sa-attachment-description> out at smaller sizes.

Theme
<div class="flex flex-col gap-3">
    <sa-attachment size="AttachmentSize.Default">
        <sa-attachment-media>
            <sa-icon name="file-text"/>
        </sa-attachment-media>
        <sa-attachment-content>
            <sa-attachment-title>kyoto-itinerary.pdf</sa-attachment-title>
            <sa-attachment-description>PDF · 2.4 MB</sa-attachment-description>
        </sa-attachment-content>
    </sa-attachment>
    <sa-attachment size="AttachmentSize.Small">
        <sa-attachment-media>
            <sa-icon name="file-text"/>
        </sa-attachment-media>
        <sa-attachment-content>
            <sa-attachment-title>kyoto-itinerary.pdf</sa-attachment-title>
            <sa-attachment-description>PDF · 2.4 MB</sa-attachment-description>
        </sa-attachment-content>
    </sa-attachment>
    <sa-attachment size="AttachmentSize.ExtraSmall">
        <sa-attachment-media>
            <sa-icon name="file-text"/>
        </sa-attachment-media>
        <sa-attachment-content>
            <sa-attachment-title>kyoto-itinerary.pdf</sa-attachment-title>
        </sa-attachment-content>
    </sa-attachment>
</div>

Image

Set variant on <sa-attachment-media> to AttachmentMediaVariant.Image and add an <img> inside it to show a preview of the file itself instead of an icon standing in for its type. The image is cropped to a square and fills the media region, so it needs no sizing classes of its own.

When using orientation="AttachmentOrientation.Vertical" the preview is stacked above the filename as a card. Vertical attachments move the actions row on top of the media, in the top corner.

Theme
<div class="flex flex-wrap gap-3">
    <sa-attachment orientation="AttachmentOrientation.Vertical">
        <sa-attachment-media variant="AttachmentMediaVariant.Image">
            <img src="/gradients/gradient-1.jpg" alt="Sunrise over the Arashiyama bamboo grove"/>
        </sa-attachment-media>
        <sa-attachment-content>
            <sa-attachment-title>arashiyama-grove.jpg</sa-attachment-title>
            <sa-attachment-description>1.8 MB</sa-attachment-description>
        </sa-attachment-content>
        <sa-attachment-actions>
            <sa-attachment-action aria-label="Remove arashiyama-grove.jpg">
                <sa-icon name="x"/>
            </sa-attachment-action>
        </sa-attachment-actions>
    </sa-attachment>
    <sa-attachment orientation="AttachmentOrientation.Vertical">
        <sa-attachment-media variant="AttachmentMediaVariant.Image">
            <img src="/avatars/avatar-1.jpg" alt="Priya Raman at the Fushimi Inari shrine"/>
        </sa-attachment-media>
        <sa-attachment-content>
            <sa-attachment-title>priya-at-fushimi.jpg</sa-attachment-title>
            <sa-attachment-description>640 KB</sa-attachment-description>
        </sa-attachment-content>
        <sa-attachment-actions>
            <sa-attachment-action aria-label="Remove priya-at-fushimi.jpg">
                <sa-icon name="x"/>
            </sa-attachment-action>
        </sa-attachment-actions>
    </sa-attachment>
    <sa-attachment orientation="AttachmentOrientation.Vertical">
        <sa-attachment-media variant="AttachmentMediaVariant.Image">
            <img src="/avatars/avatar-2.jpg" alt="Arjun Raman in the Gion district"/>
        </sa-attachment-media>
        <sa-attachment-content>
            <sa-attachment-title>arjun-at-gion.jpg</sa-attachment-title>
            <sa-attachment-description>612 KB</sa-attachment-description>
        </sa-attachment-content>
        <sa-attachment-actions>
            <sa-attachment-action aria-label="Remove arjun-at-gion.jpg">
                <sa-icon name="x"/>
            </sa-attachment-action>
        </sa-attachment-actions>
    </sa-attachment>
</div>

Group

<sa-attachment-group> lays attachments out in a horizontally scrolling row that snaps each one into place and fades the content at the edges as it scrolls, which is how a set of files attached to a single message usually reads.

Theme
<sa-attachment-group tabindex="0" role="group" aria-label="Documents for the Kyoto trip">
    <sa-attachment orientation="AttachmentOrientation.Vertical">
        <sa-attachment-media variant="AttachmentMediaVariant.Image">
            <img src="/gradients/gradient-1.jpg" alt="Sunrise over the Arashiyama bamboo grove"/>
        </sa-attachment-media>
        <sa-attachment-content>
            <sa-attachment-title>arashiyama-grove.jpg</sa-attachment-title>
            <sa-attachment-description>1.8 MB</sa-attachment-description>
        </sa-attachment-content>
    </sa-attachment>
    <sa-attachment orientation="AttachmentOrientation.Vertical">
        <sa-attachment-media>
            <sa-icon name="file-text"/>
        </sa-attachment-media>
        <sa-attachment-content>
            <sa-attachment-title>kyoto-itinerary.pdf</sa-attachment-title>
            <sa-attachment-description>2.4 MB</sa-attachment-description>
        </sa-attachment-content>
    </sa-attachment>
    <sa-attachment orientation="AttachmentOrientation.Vertical">
        <sa-attachment-media>
            <sa-icon name="plane"/>
        </sa-attachment-media>
        <sa-attachment-content>
            <sa-attachment-title>flight-confirmation.pdf</sa-attachment-title>
            <sa-attachment-description>180 KB</sa-attachment-description>
        </sa-attachment-content>
    </sa-attachment>
    <sa-attachment orientation="AttachmentOrientation.Vertical">
        <sa-attachment-media variant="AttachmentMediaVariant.Image">
            <img src="/avatars/avatar-1.jpg" alt="Priya Raman at the Fushimi Inari shrine"/>
        </sa-attachment-media>
        <sa-attachment-content>
            <sa-attachment-title>priya-at-fushimi.jpg</sa-attachment-title>
            <sa-attachment-description>640 KB</sa-attachment-description>
        </sa-attachment-content>
    </sa-attachment>
    <sa-attachment orientation="AttachmentOrientation.Vertical">
        <sa-attachment-media>
            <sa-icon name="receipt"/>
        </sa-attachment-media>
        <sa-attachment-content>
            <sa-attachment-title>hotel-invoice.pdf</sa-attachment-title>
            <sa-attachment-description>96 KB</sa-attachment-description>
        </sa-attachment-content>
    </sa-attachment>
</sa-attachment-group>

Attachments scrolled out of view are still reachable by keyboard when they contain a link, a button or an action. When they do not — as in the group above, where the cards are purely presentational — give the group tabindex="0", role="group" and an aria-label, so a keyboard user can focus the row and scroll it.

Trigger

A trigger covers the whole attachment with a control that activates it, while leaving the buttons in <sa-attachment-actions> clickable. Use it for the primary thing the card does — opening a preview, downloading the file — and keep the actions row for everything else.

<sa-attachment-button-trigger> renders a <button> element, for a card that acts — opening a preview dialog or expanding the file in place. <sa-attachment-link-trigger> renders an <a> element, for a card that navigates, and takes the same routing attributes as the ASP.NET Core Anchor Tag Helper.

Theme
<div class="flex flex-col gap-3">
    <sa-attachment>
        <sa-attachment-media>
            <sa-icon name="file-text"/>
        </sa-attachment-media>
        <sa-attachment-content>
            <sa-attachment-title>kyoto-itinerary.pdf</sa-attachment-title>
            <sa-attachment-description>PDF · 2.4 MB</sa-attachment-description>
        </sa-attachment-content>
        <sa-attachment-actions>
            <sa-attachment-action aria-label="Remove kyoto-itinerary.pdf">
                <sa-icon name="x"/>
            </sa-attachment-action>
        </sa-attachment-actions>
        <sa-attachment-button-trigger commandfor="--attachment-preview" command="show-modal"
                                      aria-label="Preview kyoto-itinerary.pdf"/>
    </sa-attachment>
    <sa-attachment>
        <sa-attachment-media>
            <sa-icon name="plane"/>
        </sa-attachment-media>
        <sa-attachment-content>
            <sa-attachment-title>flight-confirmation.pdf</sa-attachment-title>
            <sa-attachment-description>PDF · 180 KB</sa-attachment-description>
        </sa-attachment-content>
        <sa-attachment-actions>
            <sa-attachment-action aria-label="Remove flight-confirmation.pdf">
                <sa-icon name="x"/>
            </sa-attachment-action>
        </sa-attachment-actions>
        <sa-attachment-link-trigger href="/gradients/gradient-1.jpg"
                                    aria-label="Download flight-confirmation.pdf"/>
    </sa-attachment>
</div>
<sa-dialog id="--attachment-preview">
    <sa-dialog-header>
        <sa-dialog-title>kyoto-itinerary.pdf</sa-dialog-title>
        <sa-dialog-description>12 to 19 April · 2 travellers · PDF · 2.4 MB</sa-dialog-description>
    </sa-dialog-header>
    <img src="/gradients/gradient-1.jpg" alt="First page of the Kyoto itinerary" class="w-full rounded-md"/>
    <sa-dialog-footer>
        <sa-button variant="ButtonVariant.Outline" commandfor="--attachment-preview" command="close">
            Close
        </sa-button>
    </sa-dialog-footer>
</sa-dialog>

The trigger has no visible label of its own, so give it an aria-label that says what activating the card will do, and name the file in it. Do the same for each icon-only <sa-attachment-action>, since "Remove" on its own does not say which file is being removed.

API Reference

<sa-attachment>

Renders a <div> element, forwarding any global attributes.

Prop

Type

<sa-attachment-media>

Renders a <div> element holding a file-type icon or a thumbnail preview, forwarding any global attributes.

Prop

Type

<sa-attachment-content>

Renders a <div> element holding the title and description, forwarding any global attributes.

<sa-attachment-title>

Renders a <span> element holding the name of the attachment, forwarding any global attributes. The text is truncated to fit, and shimmers while the attachment is uploading or processing.

<sa-attachment-description>

Renders a <span> element holding the supporting text of the attachment, forwarding any global attributes.

<sa-attachment-actions>

Renders a <div> element holding the attachment's action controls, forwarding any global attributes. It sits above the trigger, so its controls stay clickable when the whole card is activatable.

<sa-attachment-action>

Renders a <button> element styled as a button, forwarding any global attributes. The type defaults to button so an action inside a form does not submit it; set type explicitly to override that.

Prop

Type

<sa-attachment-button-trigger>

Renders a <button> element covering the whole attachment, making it activatable, and forwarding any global attributes. The type defaults to button so a trigger inside a form does not submit it; set type explicitly to override that.

Renders an <a> element in place of <sa-attachment-button-trigger>, making the whole attachment a link.

Routing attributes

The link trigger also accepts the same routing attributes as the ASP.NET Core Anchor Tag Helper for generating the href. Supply either an href or these attributes — not both.

Prop

Type

<sa-attachment-group>

Renders a <div> element that lays attachments out in a horizontally scrolling, snapping row, forwarding any global attributes.

On this page