Skip to content
MediaMedia galleryMenu

Media gallery

A library of generated images and videos: filter by kind, a square grid grouped by day, a full-screen viewer and multi-select.

Filter images and videos, open the viewer, and select several with Shift for a range.

Installation

$ pnpm dlx shadcn@latest add https://chatcn.dev/r/media-gallery.json

Usage

tsx
import { MediaGallery } from "@/components/ui/chatcn/media-gallery"

<MediaGallery
  items={library} // { id, kind: "image" | "video", src, posterSrc?, alt, prompt?, createdAt?, duration? }
  loading={isLoading}
  onDownload={(items) => zipAndDownload(items)}
  onDelete={(items) => remove(items.map((item) => item.id))}
/>

Tiles show the poster for videos, so the grid never loads video files. Day headings appear when items have createdAt; pass now to pin them in tests and screenshots. The viewer is built on the shared Dialog and plays videos with the same player as video generation.

Examples

Loading and empty

Placeholder tiles while the library loads, and the empty state per filter.

Props

PropTypeNotes
itemsMediaItem[]Sorted newest first
loadingbooleanPlaceholder tiles, no counts
filter, defaultFilter, onFilterChange"all" | "image" | "video"
selected, defaultSelected, onSelectedChangestring[]Item ids
onDownload, onDelete(items: MediaItem[]) => voidEach shows its button
groupByDaybooleanOn when items have createdAt
nowDateReference for Today and Yesterday

Keyboard

KeyAction
← → ↑ ↓Move through the grid. Columns follow the layout
Home, EndFirst or last item
EnterOpen the viewer
SpaceSelect or deselect. Shift+Space selects a range
⌘A / Ctrl+ASelect everything in view
EscClear the selection
← → in the viewerPrevious or next item

Accessibility

  • One tile is in the tab order at a time; arrows move focus. Each tile's name says whether it opens or selects and whether it is selected.
  • Clicking a tile opens it, and once anything is selected a click selects instead. Shift and Command or Control clicks select without opening.
  • The filter is a toggle group with counts, and the selection count is announced politely.
  • The selection circle is a pointer shortcut; keyboard users press Space on the tile.

Motion

  • Tiles do not scale or lift on hover; a light tint appears over 150 ms on fine pointers only.
  • Selection rings and the toolbar swap instantly: they are frequent and often keyboard driven.
  • The viewer opens with the shared dialog motion, and paging swaps instantly.