Skip to content
Sign in
MediaStyle pickerMenu

Style picker

A grid of style presets with your own thumbnails. One style or several with a cap, an optional None tile, and grid keyboard movement by column and row.

Photo styles with a None tile. Arrow keys move through the grid by column and row.

Installation

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

Usage

tsx
import { StylePicker } from "@/components/ui/chatcn/style-picker"

const styles = [
  { id: "film", label: "Film grain", thumbnail: "/styles/film.jpg" },
  { id: "mono", label: "Monochrome", thumbnail: "/styles/mono.jpg" },
]

<StylePicker styles={styles} value={value} onValueChange={setValue} noneOption />

The value is always an array of ids, so switching to multiple never changes its type. An empty array means no style, and checks the None tile when there is one. Thumbnails can be any image, or a render node for swatches, canvases or anything drawn.

Examples

Multiple with a cap

Multiple selection with a cap: at the limit the rest wait until one is removed.

States

Loading, empty with an action, render-slot swatches, long labels, a disabled preset and disabled.

Props

PropTypeNotes
stylesStylePreset[]{ id, label, description?, thumbnail?, render?, disabled? }
value, defaultValue, onValueChangestring[]Selected ids
multiplebooleanSeveral at once. Default false
maxnumberWith multiple, the most that can be selected
noneOptionboolean | stringAdds a None tile first. A string renames it
columnsnumberFixed columns. Defaults to as many 96 px columns as fit
loading, loadingCountboolean, numberSkeleton tiles in the final layout
emptyReactNodeShown when styles is empty
disabledboolean
labelstringNames the group. Default "Style"

Keyboard

KeyAction
TabMove into the grid. It is one tab stop
ArrowLeft, ArrowRightPrevious or next tile
ArrowUp, ArrowDownSame column, previous or next row
Home, EndStart or end of the row. With Ctrl, the first or last tile
Space, EnterToggle the focused tile. Single select also follows the arrows

Accessibility

  • Single select is a radio group, multiple is a group of checkboxes. Each tile is named by its label and description.
  • At the cap, unselected tiles become aria-disabled and a polite line says 3 of 3 selected. Remove one to pick another.
  • Selection shows as an accent ring with a gap and a check badge, never color alone. In forced colors the ring uses the system highlight.

Motion

  • Tiles press to 0.98. The ring fades in 150 ms and the check swaps in with the kit's blur crossfade.
  • Thumbnails fade in over 200 ms as they load. Moving with the keyboard is instant. Skeletons are static.