- Accordion
- Action Bar
- Action Toast
- Alert Banner
- Alert Dialog
- Alert
- Alphabet Index
- Amount Field
- Aspect Ratio
- Attachment
- Availability List
- Avatar
- Badge
- Bank Card
- Breadcrumb
- Bubble
- Button Group
- Button
- Calendar
- Camera Frame
- Card Design Picker
- Card Details
- Card Peek
- Card Stack
- Card
- Carousel
- Chart
- Chat Thread
- Checkbox
- Chip Group
- Choice Tile
- Code Block
- Code Dots
- Collapsible
- Combobox
- Command
- Context Menu
- Copy Field
- Countdown
- Country Select
- Data Table
- Date Field
- Date Picker
- Date Range Picker
- Dialog
- Direction
- Document Paper
- Drawer
- Dropdown Menu
- Empty
- Entity Avatar
- Field
- File Trigger
- File Upload Item
- Hover Card
- Input Group
- Input OTP
- Input
- Item
- Kbd
- Key Value
- Keypad
- Label
- Live Region
- Marker
- Message Scroller
- Message
- Money Amount
- Native Select
- Number Field
- Pagination
- Percent Split Editor
- Phone Field
- Popover
- Progress
- QR Code
- Questionnaire
- Radio Group
- Range Histogram
- Rating
- Resizable
- Scroll Area
- Search Field
- Select
- Separator
- Share Bar
- Sheet
- Sidebar
- Skeleton
- Slider
- Sonner
- Sortable List
- Spinner
- Status Timeline
- Step Header
- Steps List
- Swipe Row
- Switch
- Table
- Tabs
- Text Field
- Textarea
- Tier Ladder
- Toggle Group
- Toggle
- Token Search Field
- Tooltip
- Trace
- Transaction Row
- Usage Meter
"use client"
import * as React from "react"The CardDesignPicker component lets people choose a plastic for their card from a grid of BankCard swatches. It is a React Aria radio group: one design is selected at a time, and its name shows next to the label. Use it when ordering a card or changing its design, with a full card above that previews the choice.
Installation#
pnpm dlx shadcn@latest add @dots/card-design-picker
Usage#
import { BankCard, findCardSkin } from "@/components/ui/bank-card"
import { CardDesignPicker } from "@/components/ui/card-design-picker"const [design, setDesign] = React.useState("midnight")
<BankCard skin={findCardSkin(design)} mark={<IssuerLogo />} />
<CardDesignPicker value={design} onChange={setDesign} mark={<IssuerLogo />} />The value is the skin id. Use findCardSkin to turn it back into a skin for the card.
Features#
- Built on React Aria
RadioGroup: arrow keys, formnameand disabled state work as on any radio group - Controlled with
valueandonChange, or uncontrolled withdefaultValue - All 24 built-in designs by default, or any list of built-ins and your own skins
- The chosen design's name next to the label
- Your issuer mark on every swatch
- Any number of columns
Fewer designs#
Pass skins to offer only some designs, in your order. Set columns to fit the grid to its space.
import { CardDesignPicker } from "@/components/ui/card-design-picker"
/** A neutral issuer mark for the demo. Pass your own logo in a product. */Your own designs#
Mix your own CardSkin objects with built-in ids in skins. Every id must be unique. Pass the same list to findCardSkin so the preview finds your skins too.
"use client"
import * as React from "react"A skin's art is a function, and functions cannot pass from a server component to this client component. Define your skins in a client module, or in the same client component as the picker.
Hidden label#
Pass label={null} with an aria-label when a heading above already says what the picker is for. The chosen name still shows.
<CardDesignPicker label={null} aria-label="Card design" defaultValue="onyx" />Accessibility#
CardDesignPicker is a React Aria RadioGroup of Radios, so it is one tab stop, the arrow keys move the selection, and it works with a pointer and touch.
- The group is named by its label, "Card design" by default, or by
aria-labelwhen the label is hidden. - Each swatch is named by its skin's
name, such as "Midnight". The swatch drawing itself is hidden from assistive tech. - The chosen name next to the label is hidden from assistive tech, because the checked radio already announces it.
- The selected swatch is marked by a frame, not by colour alone.
API Reference#
CardDesignPicker#
Accepts React Aria RadioGroup props, such as value, defaultValue, onChange, isDisabled, isRequired, name and aria-label, except children and style.
| Prop | Type | Default | Description |
|---|---|---|---|
skins | ReadonlyArray<CardSkinId | CardSkin> | all built-ins | The designs to offer, in order. Ids must be unique. |
value | string | - | The selected skin id, when controlled. |
defaultValue | string | - | The initially selected skin id, when uncontrolled. |
onChange | (value: string) => void | - | Called with the skin id when the selection changes. |
label | React.ReactNode | "Card design" | Visible group label. Pass null with an aria-label to hide it. |
mark | React.ReactNode | - | Issuer mark drawn on every swatch. |
columns | number | 6 | Swatches per row. |
className | string | - | Additional classes to apply to the root. |