Image Selector
betaA photo grid with a Select mode: tick photos, see the count, share or delete them, and reset.
- Forms
- 1 file
- 2 npm packages
- Accessibility notes
- Animates with motion
Loading the example…
pnpm dlx @dowel-ui/cli add image-selectornpm packages installed: class-variance-authority, motion.
import { ImageSelector } from "@/components/ui/image-selector";Default
Gallery
Start In Select Mode
Four Columns
<ImageSelector>
| Prop | Type | Default |
|---|---|---|
images (required) | SelectableImage[] | — |
defaultSelecting | boolean | false |
defaultValue | string[] | [] |
gridClassName | string | — |
labelAccessible name of the photo group. | string | "Photos" |
onDeleteCalled with the ids being deleted. They are also hidden until Reset. | (ids: string[]) => void | — |
onSelectingChange | (selecting: boolean) => void | — |
onShareShows a Share button in the bar, called with the selected ids. | (ids: string[]) => void | — |
onValueChange | (value: string[]) => void | — |
selectingWhether Select mode is on (controlled). | boolean | — |
showResetShow a Reset button that restores deleted photos and leaves Select mode. | boolean | true |
valueSelected image ids (controlled). | string[] | — |
Plus every attribute of <div> except defaultValue, onChange, children.
The grid is a list named by `label`. In Select mode each photo is a native checkbox named by the image's alt text — Tab reaches each, Space ticks it — with a visible focus ring on the photo. The Select toggle exposes aria-pressed; the selection count is a polite live region. Share and Delete are named icon buttons that become aria-disabled (not disabled) with nothing selected, so focus stays put after a delete. Tick marks are aria-hidden. The reflow after a delete uses motion inside MotionConfig reducedMotion="user"; the rest is CSS and stops under reduced motion.
8/8
checks passed
- Tested — passes
- axe assertion — passes
- Keyboard tested — does not apply
- Storybook examples — passes
- Accessibility documented — passes
- Semantic tokens only — passes
- Motion from tokens — passes
- className merged — passes
- Visible focus — does not apply
- No fixed widths — passes