App Stack
betaA pile of app icons that fans out on hover and opens into a multi-select picker whose icons fly to their tiles.
- Forms
- 1 file
- 2 npm packages
- Accessibility notes
- Animates with motion
Loading the example…
pnpm dlx @dowel-ui/cli add app-stacknpm packages installed: class-variance-authority, motion.
import { AppStack } from "@/components/ui/app-stack";Default
Gallery
Failing
<AppStack>
| Prop | Type | Default |
|---|---|---|
apps (required) | AppStackItem[] | — |
completeLabel | string | "Download complete" |
defaultExpanded | boolean | false |
defaultSelected | string[] | [] |
downloadingLabel | string | "Downloading…" |
downloadLabel | string | "Download selected" |
expanded | boolean | — |
failedLabel | string | "Download failed" |
onDownloadCalled with the selected ids. Return a promise to show progress until it settles. | (selected: string[]) => void | Promise<unknown> | — |
onExpandedChange | (expanded: boolean) => void | — |
onSelectedChange | (selected: string[]) => void | — |
resetAfterMilliseconds the completed state shows before resetting. | number | 1000 |
selectedControlled selection, by app id. | string[] | — |
titleThe picker's heading, e.g. "Starter Mac". | string | "Apps" |
triggerLabelAccessible name of the collapsed stack. Defaults to "Choose from {title}". | string | — |
Plus every attribute of <div> except children.
The collapsed stack is a button (aria-expanded="false", named "Choose from {title}" or triggerLabel); opening moves focus to the picker's header button (aria-expanded="true"), which closes it and returns focus. Each app is a toggle button (aria-pressed) named by the app; icons and check marks are decorative. The download button is disabled until something is selected. Progress, completion and failure are announced through a polite status region, and the stack is aria-disabled while busy. Under reduced motion the icons move without animating (MotionConfig) and the fan, float and shine stop.
10/10
checks passed
- Tested — passes
- axe assertion — passes
- Keyboard tested — passes
- Storybook examples — passes
- Accessibility documented — passes
- Semantic tokens only — passes
- Motion from tokens — passes
- className merged — passes
- Visible focus — passes
- No fixed widths — passes