Experience System

File Card

Presentation-only card that represents a single file with its media, name, label, and actions.

quarterly-report.pdf
240 KB

Installation

The component is exported from @by/experience-system. Add the package with your package manager:

pnpm add @by/experience-system

In this monorepo, depend on the workspace package (for example via workspace:* or your catalog) so imports resolve to packages/experience-system.

Composition

Use the following composition to build a FileCard:

FileCard
├── FileCardMedia
├── FileCardContent
│   ├── FileCardName
│   └── FileCardLabel (optional)
└── FileCardActions (optional)

Group related cards with FileCardGroup for consistent spacing. FileCard is presentation-only — it has no built-in file behavior (no upload, drag-and-drop, or I/O). It is a div by default and can render as any element with asChild.

Usage

import {
  FileCard,
  FileCardActions,
  FileCardContent,
  FileCardGroup,
  FileCardLabel,
  FileCardMedia,
  FileCardName,
} from '@by/experience-system';

FileCard is a client component ('use client'). Use it inside a Client Component or a dynamic import when using the Next.js App Router.

<FileCard onClick={() => open(file)}>
  <FileCardMedia fileName="report.pdf" />
  <FileCardContent>
    <FileCardName>report.pdf</FileCardName>
    <FileCardLabel>240 KB</FileCardLabel>
  </FileCardContent>
</FileCard>

Pass onClick to make the whole card activate a consumer-defined callback: the card becomes interactive (role="button", keyboard focusable, activates on Enter / Space). Prefer asChild with a real <a> or <button> when you already have a semantic element.

When to use

Use FileCard to display an existing file — for example a selected attachment, a search result, or an item in a file list — with a derived type icon or extension badge, a name, and optional actions.

When not to use

For picking or uploading files (dropzone, validation, image gallery, preview dialog), use FileUpload instead. FileCard does not read or manage files.

Examples

Sizes

Use the size prop for sm, md (baseline), or lg density. Horizontal cards use minimum heights per the design spec: sm is a 24px compact row (name and label inline), md is 40px (stacked name over label), and lg is 48px. Inside a size="sm" card, FileCardMedia defaults to the compact badge media.

PDF
report.pdf
Small
report.pdf
Medium (baseline)
report.pdf
Large

Media types

FileCardMedia renders an icon (file-type glyph), a badge (uppercase extension), or an image (thumbnail). When no children are supplied and fileName is set, the icon and badge are derived from the extension. When variant is omitted, the media defaults to badge for size="sm" and icon otherwise.

PPT
presentation.pptx
Extension badge
presentation.pptx
Icon derived from extension
preview.png
Thumbnail image
preview.png
Image-only square
preview.png
Image-only square

Category colors

Media derived from fileName is colored by the file's category — documents (blue), PDF (red), spreadsheets (green), presentations (orange), images (purple), media (cyan), compressed (brown), design (iris), and code / unknown (slate). Category tints use contrast white text in light mode and black text in dark mode. The resolved category is exposed on data-category. Explicit children keep their own color.

proposal.docx
Documents · blue
annual-report.pdf
PDF · red
budget.xlsx
Spreadsheets · green
keynote.pptx
Presentations · orange
cover.png
Images · purple
promo.mp4
Media · cyan
assets.zip
Compressed · brown
mockup.fig
Design · iris
index.tsx
Code · slate
firmware.bin
Unknown · slate

Toolbar & status

The card has no persistent right-side toolbar. Surface actions on demand: put an overflow menu in FileCardActions (via DropdownMenu), reveal details with a HoverCard, show a Spinner while work is in flight, or pair color="error" with an error icon and a retry control.

quarterly-report.pdf
240 KB
roadmap.pptx
Uploading…
archive.zip
Upload failed

Vertical

Use orientation="vertical" for a stacked card layout. Vertical cards use fixed square footprints (sm 24px, md 40px, lg 100px). With FileCardMedia variant="image", the preview spans the full card width (16:9) at size="lg". At sm and md, an image-only vertical card fills the square and hides name, label, and actions. FileCardActions is positioned in the top-end corner of vertical cards.

cover.png
Image-only
cover.png
Image-only
cover-artwork.png
3.1 MB
annual-report.pdf
1.8 MB

API Reference

Subsection titles name the exports from @by/experience-system. FileCard is an Experience System composite (not a Radix primitive); the tables document each part's props and data attributes.

FileCard

PropTypeDefault
asChildbooleanfalse
variant'outline' | 'soft''outline'
orientation'horizontal' | 'vertical''horizontal'
size'sm' | 'md' | 'lg''md'
color'neutral' | 'warning' | 'error''neutral'
selectedbooleanfalse
onClickReact.MouseEventHandler

Also accepts standard div attributes except color, which is reserved for the semantic status tint.

Data attributeValues
data-slotfile-card
data-variantoutline, soft
data-orientationhorizontal, vertical
data-sizesm, md, lg
data-colorneutral, warning, error
data-selectedpresent ('true') when selected
data-interactivepresent ('true') when interactive or asChild

FileCardGroup

Container that groups related cards with consistent spacing. Accepts standard div attributes; applies no list role by default. For list semantics pass role="list" here and role="listitem" on each card (or use <ul>/<li>).

FileCardMedia

PropTypeDefault
variant'icon' | 'badge' | 'image'badge for sm, else icon
fileNamestring
previewSrcstring
previewAltstring''

When no children are supplied and fileName is set, icon renders the matching @by/icons/ui file-type icon and badge renders the uppercase extension. Explicit children always win over derivation. When the resolved media is image and previewSrc is set (and no children are supplied), the thumbnail is rendered from that URL. In orientation="vertical" cards the image variant fills the square card. Derived icon/badge media sits on a solid category-colored square (documents → blue, PDF → red, spreadsheets → green, presentations → orange, images → purple, media → cyan, compressed → brown, design → iris, code / unknown → slate) with contrast text that adapts in dark mode.

Data attributeValues
data-slotfile-card-media
data-varianticon, badge, image
data-categorydocument, pdf, spreadsheet, presentation, image, media, compressed, design, code, unknown (only when derived from fileName)

FileCardContent

Wraps FileCardName and FileCardLabel. Accepts standard div attributes. data-slot="file-card-content".

FileCardName

Displays the file name, including its extension; truncates on overflow. Accepts standard div attributes. data-slot="file-card-name".

FileCardLabel

Displays supporting text such as a label, file size, or status message. Use kind="meta" for helper text and kind="status" for status messages that should stay visually distinct. In compact rows (size="sm"), name and label sit inline. Tints to match color="warning" / color="error". Accepts standard div attributes. data-slot="file-card-label".

FileCardActions

Container for action buttons or other controls. In orientation="vertical" cards, actions are absolutely positioned in the top-end corner. Action clicks also bubble to the card onClick; call stopPropagation in the action handler to prevent the card click. Accepts standard div attributes. data-slot="file-card-actions".

Accessibility

  • When onClick is set (and asChild is not), the card exposes role="button", becomes focusable (tabIndex={0}), and activates on Enter / Space. A visible focus-visible ring is rendered.
  • Prefer asChild with a semantic <a> or <button> when the card is a link or a real button; wire click/keyboard behavior on that child. The card still receives interactive affordances via data-interactive.
  • Derived media icons are aria-hidden; convey the file type through the visible name and label rather than the glyph alone.
  • Give icon-only controls inside FileCardActions an aria-label, and label a loading Spinner so its purpose is announced.

Keyboard interactions

KeyDescription
TabMoves focus to an interactive card (or asChild element).
Space / EnterActivates an interactive card and fires onClick.

Source in the repo: packages/experience-system/src/components/FileCard/FileCard.tsx. Agent-oriented contracts: packages/experience-system/src/components/FileCard/FileCard.instructions.md.