Attachment
File chip or image thumbnail with type icon, size, upload progress and remove button.
pnpm dlx @glinui/cli@latest add attachmentAttached to this message
Installation
pnpm dlx @glinui/cli@latest add attachmentPrefer the package?
Usage
In a message
Attachments inside a user message.
Q3 revenue review
Glin assistant, 3 sources
import { ArrowsClockwise, Paperclip, ThumbsDown, ThumbsUp } from "@phosphor-icons/react"import { Attachment, Badge, Heading, Message, MessageAction, MessageActions, MessageAvatar, MessageContent, MessageCopyAction, MessageScroller, PromptInput, StreamingText, Text, Thinking} from "@glinui/ui"
const reply = "Revenue grew 12% quarter over quarter, driven mostly by the Pro plan. Churn stayed flat at 1.8%, so the gain came from expansion rather than new logos."
export function ChatScreen() { return ( <div className="flex h-[34rem] w-full max-w-2xl flex-col overflow-hidden rounded-2xl border border-[var(--line-soft)] bg-[var(--surface-1)] text-left"> <header className="flex items-center justify-between gap-3 border-b border-[var(--line-soft)] px-4 py-3"> <div className="flex flex-col"> <Heading level={2} size="sm">Q3 revenue review</Heading> <Text size="sm" variant="muted">Glin assistant, 3 sources</Text> </div> <Badge tone="success" variant="soft">Online</Badge> </header> <MessageScroller label="Conversation" className="min-h-0 flex-1"> <Message role="user"> <MessageAvatar fallback="MK" alt="" /> <MessageContent> <div className="flex flex-col gap-2"> <span>Summarize how Q3 went compared with Q2.</span> <div className="flex flex-wrap gap-2"> <Attachment name="q3-revenue.csv" size={48210} /> <Attachment name="board-notes.pdf" size={1203400} /> </div> </div> </MessageContent> </Message> <Message role="assistant"> <MessageAvatar fallback="G" alt="" /> <MessageContent actions={ <MessageActions> <MessageCopyAction value={reply} /> <MessageAction label="Regenerate"><ArrowsClockwise /></MessageAction> <MessageAction label="Good response" pressed><ThumbsUp /></MessageAction> <MessageAction label="Bad response"><ThumbsDown /></MessageAction> </MessageActions> } > <div className="flex flex-col gap-2"> <Thinking active={false} doneLabel="Thought for 4 seconds">Compared monthly totals, then split growth into new and expansion revenue.</Thinking> <span>{reply}</span> </div> </MessageContent> </Message> <Message role="user"> <MessageAvatar fallback="MK" alt="" /> <MessageContent>Which regions grew fastest?</MessageContent> </Message> <Message role="assistant"> <MessageAvatar fallback="G" alt="" /> <MessageContent> <StreamingText text="Europe led with 19% growth, followed by North America at 11%. APAC was flat after the pricing change in August." speed={30} /> </MessageContent> </Message> <Message role="assistant"> <MessageAvatar fallback="G" alt="" /> <MessageContent><Thinking /></MessageContent> </Message> </MessageScroller> <div className="border-t border-[var(--line-soft)] p-3"> <PromptInput placeholder="Ask a follow up" maxLength={500} onSubmit={(value) => console.log(value)} actions={<MessageAction label="Attach file"><Paperclip /></MessageAction>} /> </div> </div> )}Variants
Every vocabulary variant on the default tone. Omit variant to follow the ambient design style.
import { Attachment } from "@glinui/ui"
export function AttachmentVariantsDemo() { return ( <div className="flex flex-wrap items-center gap-3"> <Attachment variant="glinr" name="glinr.pdf" size={24000} /> <Attachment variant="solid" name="solid.pdf" size={24000} /> <Attachment variant="plain" name="plain.pdf" size={24000} /> <Attachment variant="soft" name="soft.pdf" size={24000} /> <Attachment variant="outline" name="outline.pdf" size={24000} /> <Attachment variant="ghost" name="ghost.pdf" size={24000} /> <Attachment variant="gradient" name="gradient.pdf" size={24000} /> </div> )}Glass (opt-in)
Glass is opt-in and needs a backdrop behind it. Switch the preview stage to Vivid or Photo to see the frosted surface.
import { Attachment } from "@glinui/ui"
export function AttachmentGlassDemo() { return ( <Attachment variant="glass" name="glass.pdf" size={24000} /> )}Accessibility
- Upload progress is exposed as role="progressbar" with aria-valuenow.
- The remove button is named "Remove <file name>".
- Thumbnail images use the file name as alt text; chip icons are decorative.
Keyboard Interactions
| Key | Action |
|---|---|
| Enter / Space | Activate the remove button. |
ARIA Attributes
- `role="progressbar"` with `aria-valuenow`
- `aria-label` on the remove button
Reduced Motion
Progress width changes animate only when motion is allowed.
Affected properties
widthbackground-colorAPI Reference
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
name | string | Yes | - | File name. Required. |
size | number | No | - | Size in bytes, formatted automatically. |
type | string | No | - | MIME type, used with the extension to choose the icon. |
progress | number | No | - | 0 to 100. Below 100 shows a progress bar. |
previewUrl | string | No | - | Image source for thumbnails. |
display | "chip" | "thumbnail" | No | chip | Row chip or square image tile. |
variant | SurfaceVariant | "default" | "raised" | "frosted" | No | ambient (glinr) | Surface variant. Omit to follow the ambient design style (glinr by default, plain for minimal, glass for glass). |
tone | SurfaceTone | No | neutral | Colour tone for the vocabulary variants. |
onRemove | () => void | No | - | Renders a remove button labelled with the file name. |
removeLabel | string | No | - | Auto-generated from TypeScript source. |
Source
Import directly from the package or browse the source on GitHub. Click any file to view it.
Import
import { Attachment } from "@glinui/ui"Source Files
Dependencies
@glinui/ui@phosphor-icons/reactclass-variance-authorityGenerated API Snapshot
Beta
Generated API Snapshot
BetaAuto-extracted from TypeScript source in packages/ui/src/components/attachment.tsx. This section is in beta and may lag behind hand-curated docs. Regenerate with pnpm --filter @glinui/docs api:generate.
Generated: 2026-10-08T01:41:21.546Z · Full index: /docs/api-metadata
Primary Props Type
AttachmentProps
AttachmentProps
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
display | "chip" | "thumbnail" | No | "chip" | Variant option from attachmentDisplay. |
name | string | Yes | - | - |
onRemove | () => void | No | - | - |
previewUrl | string | No | - | Image URL. With `display="thumbnail"` it fills the tile. |
progress | number | No | - | 0 to 100. When defined and below 100 a progress bar is shown. |
removeLabel | string | No | - | - |
size | number | No | - | Size in bytes. |
tone | SurfaceTone | No | - | - |
type | string | No | - | MIME type or extension used to pick the icon. |
variant | SurfaceVariant | "default" | "raised" | "frosted" | No | - | Visual variant. Omit for the ambient design style (glinr by default). Vocabulary: glinr, solid, plain, soft, outline, ghost, gradient, glass. |