Attachment

File attachment rows for uploads, chats, and media previews, with download actions and per-type document icons.

Loading preview

Examples

Practical examples and common states for the same installable component.

Compact

Minimal file attachment for dense interfaces.

examples/attachment-compact.tsx
import { Attachment } from "@/components/wensity/attachment";
export function AttachmentCompact() {
return (
<div className="flex flex-col gap-2">
<Attachment variant="compact" fileName="invoice-2024-q4.pdf" fileSize={182_000} />
<Attachment variant="compact" fileName="brand-assets.zip" fileSize={8_400_000} />
<Attachment variant="compact" fileName="notes.txt" fileSize={4_200} />
</div>
);
}

Preview

Rich attachment with image or file preview.

examples/attachment-preview.tsx
import { Attachment } from "@/components/wensity/attachment";
export function AttachmentPreview() {
return (
<div className="flex flex-wrap gap-3">
<Attachment
variant="preview"
fileName="cover-photo.jpg"
fileSize={820_000}
thumbnailSrc="https://assets.wensity.com/photos/landscape/rainy-cafe-window.webp"
/>
<Attachment
variant="preview"
fileName="reference-shot.jpg"
fileSize={1_100_000}
thumbnailSrc="https://assets.wensity.com/photos/landscape/grand-library-hall.webp"
/>
</div>
);
}

Upload

Attachment with uploading progress and status.

examples/attachment-upload.tsx
import { Attachment } from "@/components/wensity/attachment";
export function AttachmentUpload() {
return (
<div className="flex flex-col gap-2">
<Attachment variant="upload" fileName="selected-file.pdf" status="pending" />
<Attachment
variant="upload"
fileName="design-system.zip"
status="uploading"
progress={64}
/>
<Attachment variant="upload" fileName="market-research.pdf" status="processing" />
<Attachment
variant="upload"
fileName="financial-model.xlsx"
status="error"
errorMessage="Upload failed. Try again."
onRetry={() => {}}
/>
<Attachment
variant="upload"
fileName="uploaded-report.pdf"
status="success"
fileSize={1_800_000}
/>
</div>
);
}

Removable

Attachment with clear remove action.

examples/attachment-removable.tsx
import { useState } from "react";
import { Attachment } from "@/components/wensity/attachment";
export function AttachmentRemovable() {
const [files, setFiles] = useState([
{ id: "1", name: "design-system.fig", size: 5_800_000 },
{ id: "2", name: "user-research.pdf", size: 1_100_000 },
]);
return (
<div className="flex flex-col gap-2">
{files.map((file) => (
<Attachment
key={file.id}
variant="removable"
fileName={file.name}
fileSize={file.size}
onRemove={() => setFiles((prev) => prev.filter((f) => f.id !== file.id))}
/>
))}
</div>
);
}

Download

File attachment optimized for downloading.

examples/attachment-download.tsx
import { Attachment } from "@/components/wensity/attachment";
export function AttachmentDownload() {
return (
<Attachment
variant="download"
fileName="onboarding-guide.pdf"
fileSize={960_000}
downloadHref="https://example.com/onboarding-guide.pdf"
/>
);
}

Props

PropTypeDefaultDescription
fileNamestring-Name of the file. Required.
variant"compact" | "preview" | "upload" | "removable" | "download""compact"Row treatment, and which affordances are shown by default.
fileSizenumber | string-Bytes, or a pre-formatted string such as 2.4 MB.
thumbnailSrcstring-Image shown instead of the file-type icon, for the preview variant.
status"idle" | "pending" | "uploading" | "processing" | "success" | "error""idle"Lifecycle state of the upload.
progressnumber0Completion from 0 to 100, shown while status is uploading.
errorMessagestring-Message shown when status is error.
onRetry() => void-Called from the retry affordance after a failure.
removableboolean-Shows a remove button. Defaults to true for the removable variant.
onRemove() => void-Called when the remove button is pressed.
downloadHrefstring-Turns the download affordance into a link to this URL.