Skip to content

PickerSheet

A mobile picker in a bottom sheet: a searchable list (countries, long option lists) or a wheel (a date or a time), closed with Done.

  • Pro, mobile
  • Version 2.0.0-rc.1
  • APG pattern: Dialog (modal) holding a combobox with a listbox (list) or spinbuttons (wheel)

Examples

Still previews of the real component, rendered from its stories. Pro code isn’t public, so nothing in them responds. Switch the theme and density for every preview at once.

Default

Country: United Kingdom

List (open)

Country: United Kingdom

Wheel

Date of birth: 24 October 1990

Wheel (open)

Date of birth: 24 October 1990

Tokens

The 19 design tokens PickerSheet reads, with the value each has in the theme and density chosen above. Change a token and the component follows, in Figma and in code.

Show all 19 tokens
Tokens PickerSheet reads
TokenValue nowCSS variable
color.bg.muted…--sd-color-bg-muted
color.border.strong…--sd-color-border-strong
color.border.subtle…--sd-color-border-subtle
color.text.default…--sd-color-text-default
color.text.secondary…--sd-color-text-secondary
dialog.bg…--sd-dialog-bg
dialog.fg…--sd-dialog-fg
dialog.radius…--sd-dialog-radius
dialog.scrim…--sd-dialog-scrim
elevation.3…--sd-elevation-3
layer.modal…--sd-layer-modal
radius.full…--sd-radius-full
radius.md…--sd-radius-md
spacing.gap.sm…--sd-spacing-gap-sm
spacing.inset.lg…--sd-spacing-inset-lg
spacing.inset.md…--sd-spacing-inset-md
spacing.inset.sm…--sd-spacing-inset-sm
spacing.stack.sm…--sd-spacing-stack-sm
target.min…--sd-target-min

Install

Pro components come as source from the SuperDuper registry, with a licence key from Solo, Team or Studio. The registry and checkout aren’t open yet.

Add it from the registry (Pro licence key)

npx shadcn@latest add @superduperui/picker-sheet

Then import it

import { PickerSheet, PickerSheetTrigger } from "@/components/ui/picker-sheet"

Props

PickerSheet props
PropTypeWhat it does
kind'list' | 'wheel'Default 'list'list (default): a searchable list (countries, long option lists). wheel: one spin column per part (day, month, year; hours, minutes).
titlerequiredstringRequired: names the sheet and is its heading.
isOpenboolean
onOpenChange(isOpen: boolean) => void
itemsPickerOption[]Default []List kind: the options.
selectedKeystring | nullList kind: the selected option's id.
onSelectionChange(id: string) => voidList kind: called with the id of the option chosen; the sheet stays open until Done.
searchLabelstringDefault 'Search'List kind: the search field's accessible name (its label is hidden). Default "Search".
searchPlaceholderstring
emptyTextstringDefault 'No matches'List kind: shown when nothing matches the search. Default "No matches".
columnsPickerColumn[]Default []Wheel kind: the columns, left to right.
doneLabelstringDefault 'Done'The header button that closes the sheet. Default "Done".
classNamestring

When to use it

Use it for

  • Choosing from a long list on a phone (a country, a language)
  • Choosing a date or a time on a phone

Use something else for

  • Desktop: use Select, Combobox or DatePicker
  • Short lists of up to about 6 options: use RadioGroup or ChoiceRow on the page

Accessibility

Screen readers announce List: "Country, dialog. Search, search text field", then "1 match" and "Ireland, selected, option". Wheel: "Month, spin button, October, 10 of 12".

WCAG 2.2 AAA criteria the component meets in Comfortable density: 1.4.6, 1.4.9, 2.1.3, 2.3.3, 2.4.13, 2.5.5.

Options and wheel rows stay 44px in Compact: density changes spacing only.

What your product still has to do

  • Show the chosen value on the page next to the trigger (the sheet is not the only place it appears)
  • Use the wheel only where typing is worse: a DateField takes a date of birth faster for many people

This release’s test results

Test results for PickerSheet in this release
axe-core (WCAG A, AA, AAA and best practice)80 runs across every story, theme, density and width: 0 violations
Rendered text contrast240 text runs: 0 below 7:1, lowest 8.43:1
Target size44 targets: 0 under 44px in Comfortable
Focus appearance (2.4.13)18 focus stops in 3 browser engines: all pass
Keyboard scriptChromium 7 of 7, Firefox 7 of 7, WebKit 7 of 7

Manual passes with VoiceOver and NVDA haven’t been done yet.

Keyboard

Each step is scripted and run in Chromium, Firefox and WebKit.

PickerSheet keyboard steps
KeyWhat happens
TabTab reaches the trigger
EnterEnter opens the sheet with focus in the search field
Typing filters the list and announces the count
ArrowDownDown highlights the first match (focus stays in the field)
EnterEnter chooses it
EscapeEsc clears the search
EscapeA second Esc closes the sheet and focus returns to the trigger

In Figma

The Figma component is PickerSheet, with Kind (List, Wheel). The Figma library isn’t published yet.

Figma to code: Kind → kind (List = "list", Wheel = "wheel"); Title → title; nested Search → searchPlaceholder.