build69
build69  /  Components  /  Media & Files  /  ThumbnailStrip

ThumbnailStrip

v1.0.4Updated 19 Oct 2026

Horizontal or vertical rail of image thumbnails to CHOOSE from (fb_fd688b75): one current selection (single), or multi-select where each picked thumbnail carries an order badge — 1, 2, 3 in the order ticked. A <button> per thumbnail with aria-current / aria-pressed, a fixed aspect box that holds the rail's shape while a thumbnail is still being generated, a caption under each image, and roving-tabindex arrow-key navigation along the rail.

Preview

Live · 10 stories
DefaultOpen ↗
▸Why this is recommendedthumbnailfilmstripgallerypicker+7

The default, out-of-the-box ThumbnailStrip.

Recommended for+14
  • ✓Pick which captures to attach to a bug report, in the order ticked
  • ✓Choose which attached screenshot the viewer or canvas is showing
  • ✓A filmstrip of pages or photos under a larger preview
Tags+6
thumbnailfilmstripgallerypickerimagestriprailattachmentsscreenshotsmulti-selectdefault
Features+4
  • Single mode (aria-current) for "which capture is shown"; multiple mode (aria-pressed) for "which captures to attach"
  • Order badges 1, 2, 3 in the order ticked — un-ticking one renumbers the rest, and the value IS the ordered id list
  • Fixed aspect box per thumbnail (aspectRatio prop), so the rail keeps its shape while an image is missing, pending or broken
  • Per-thumbnail states: still-being-generated placeholder (no src or loading), image-load error, caption, disabled
  • Controlled (value / onValueChange) and uncontrolled (defaultValue); maxSelected caps a multi-select
  • One tab stop for the rail (roving tabindex); arrow keys along the axis, Home / End, and scroll-into-view; RTL-aware
  • Horizontal or vertical orientation, each scrolling on its own axis for overflow; sizes sm / md / lg
  • Empty state, whole-strip disabled (e.g. while the form submits) and per-item disabled
  • i18n labels prop (ThumbnailStripLabels — the order badge is a {position} template and the single rail-level loading status a {count}/{total} one; numbers use the locale formatter)
Not recommended for−2
  • ✕Viewing one document or file (use DocumentViewer)
  • ✕A picture grid that is read, not chosen from (use ImageList)
  • ✕Choosing from text options (use Select / MultiSelect / Combobox)

Install

Ask your agent, or call the MCP tool directly. The resolved bundle is written into your project.

get_registry_item({ name: "ThumbnailStrip" })

Usage

import { ThumbnailStrip } from '@/components/media/thumbnail-strip';

const [attached, setAttached] = React.useState<string[]>([]);

<ThumbnailStrip
  items={captures}
  selectionMode="multiple"
  value={attached}
  onValueChange={setAttached}
  aria-label="Captures to attach"
/>

Tick variants in the left menu — each adds a tab with that variant’s real story source, the same code the preview above renders.

Props

PropTypeRequired
items

Thumbnails: { id, src?, alt, caption?, disabled?, loading? } — alt is required and becomes the button's accessible name; omit src while the thumbnail is still being generated

ThumbnailStripItem[]yes
selectionMode

single (default) marks one current thumbnail with aria-current; multiple toggles with aria-pressed and shows order badges

'single' | 'multiple'—
value

Controlled selection: an id in single mode, the ORDERED id list in multiple mode

string | null | string[]—
defaultValue

Uncontrolled initial selection

string | null | string[]—
onValueChange

Fires with the new selection (the ordered list in multiple mode)

(value: string | null) => void | (value: string[]) => void—
maxSelected

Multiple mode: stop accepting new picks at this many (un-ticking still works)

number—
allowDeselect

Single mode: clicking the current thumbnail again clears it (default false)

boolean—
orientation

Rail direction; drives the arrow keys and which axis scrolls (default horizontal)

'horizontal' | 'vertical'—
size

Thumbnail width preset (default md)

'sm' | 'md' | 'lg'—
aspectRatio

Width / height of every thumbnail box (default 4/3) — this is what keeps the rail from reflowing while images load

number—
fit

How each image fills its box (default cover)

'cover' | 'contain'—
disabled

Disable the whole rail (e.g. while the form submits)

boolean—
emptyState

Rendered instead of the default text when items is empty

React.ReactNode—
labels

Override any built-in string (strip / empty / loading / imageError / order) for i18n

Partial<ThumbnailStripLabels>—

Related