Skip to content

Choice Card

Pick from options shown as cards, with an icon, a description and a radio, checkbox or switch.

import { ChoiceCard, ChoiceCardGroup } from '@youj/react'

Installation & usage

npm i @youj/react

For an app already set up with npx @youj/cli init, which installs the peers (@youj/core, @youj/motion, motion and Base UI) and wires the provider. New app? Start at Installation.

Use Choice Cards when each option needs a sentence or a figure to be chosen well: plans, roles, strategies, settings. For short options a Radio Group or Checkboxes take less room.

import { ChoiceCard, ChoiceCardGroup, FieldLegend, FieldSet } from '@youj/react'

export function AccessLevel() {
  return (
    <FieldSet>
      <FieldLegend variant="label">Access level</FieldLegend>
      <ChoiceCardGroup defaultValue="build" name="access" columns={2}>
        <ChoiceCard value="manage" title="Manage" description="Members, billing and every project" />
        <ChoiceCard value="build" title="Build" description="Create, edit and publish projects" />
      </ChoiceCardGroup>
    </FieldSet>
  )
}

A plan picker uses the other slots. title and description name the plan, badge marks the suggested one, note puts the price at the row's end, and children go under the description, here the plan's limit. Horizontal cards (the default) are rows; orientation="vertical" makes them tall cards for a three-column pricing grid, and moves the price into children, since note is for rows:

import { ChoiceCard, ChoiceCardGroup, FieldLegend, FieldSet } from '@youj/react'

export function PlanPicker() {
  return (
    <FieldSet>
      <FieldLegend variant="label">Plan</FieldLegend>
      <ChoiceCardGroup defaultValue="pro" name="plan">
        <ChoiceCard value="hobby" title="Hobby" description="For side projects" note="$0 / mo">
          <p className="text-ui-sm text-fg-muted">3 projects</p>
        </ChoiceCard>
        <ChoiceCard value="pro" title="Pro" description="For a team shipping weekly" badge="Suggested" note="$20 / mo">
          <p className="text-ui-sm text-fg-muted">Unlimited projects</p>
        </ChoiceCard>
      </ChoiceCardGroup>
    </FieldSet>
  )
}
<ChoiceCardGroup defaultValue="pro" name="plan" columns={3}>
  <ChoiceCard orientation="vertical" value="hobby" title="Hobby" description="For side projects">
    <p className="text-ui-lg font-semibold">$0 / mo</p>
  </ChoiceCard>
  <ChoiceCard orientation="vertical" value="pro" title="Pro" description="For a team" badge="Suggested">
    <p className="text-ui-lg font-semibold">$20 / mo</p>
  </ChoiceCard>
  <ChoiceCard orientation="vertical" value="scale" title="Scale" description="For a company">
    <p className="text-ui-lg font-semibold">$90 / mo</p>
  </ChoiceCard>
</ChoiceCardGroup>

ChoiceCardGroup sets the control for its cards. control="radio" (the default) is one choice: value, defaultValue and onValueChange take a string. control="checkbox" is any number: they take the list of ticked values. control="switch" groups independent toggles, and each card takes its own checked, defaultChecked and onCheckedChange. A card outside a group is a checkbox unless its control says otherwise.

Reference

Propsvalue, control, title, description, icon, badge, note, orientation…

Props

ChoiceCard props
PropType
valuestring

The card's value in a radio or checkbox group.

–
controlChoiceCardControl
'radio''checkbox''switch'

The control. Defaults to the group's, or checkbox outside a group.

–
checkedboolean

On or off, for a checkbox or switch card that isn't in a checkbox group.

–
defaultCheckedboolean–
onCheckedChange(checked: boolean) => void–
titleRequiredReactNode–
descriptionReactNode–
iconReactNode

A small mark in a tile at the card's start (decorative).

–
badgeReactNode

Beside the title: a string becomes a Badge ("Suggested"), any other node shows as given.

–
noteReactNode

Trailing text at the row's end, such as what the choice costs. Horizontal cards only.

–
childrenReactNode

Anything under the description: a meter, a figure, a link.

–
orientation'horizontal' | 'vertical'

horizontal (default): one row, the control first. vertical: the icon and control on top, the text under them.

default 'horizontal'

'horizontal'
disabledboolean–
namestring

Submits a standalone checkbox or switch with a native form.

–
idstring–
classNamestring–

ChoiceCardGroup

ChoiceCardGroup props
PropType
columns1 | 2 | 3 | 4

Cards per row from the sm breakpoint up (3 and 4 reach that count at lg).

default 1

1
control'radio'
'checkbox''switch''radio'
–

The group also takes the props of the group it renders: Base UI's RadioGroup for radio, CheckboxGroup for checkbox, and a div for switch. columns (1 to 4) lays the cards out from the sm breakpoint up.

Data attributes

The card and the group carry data-yj-control (radio, checkbox or switch), and the card's Field carries data-orientation.

MotionCard edge, icon tile · reduced motion

Motion

Motion tokens
MomentTokens
Card edgethe border doubles in the accent when the control turns on
duration.fastease.standard

140ms · cubic-bezier(0.2, 0, 0, 1)

140mscubic-bezier(0.2, 0, 0, 1)
Icon tiletints to the accent with the card
duration.fastease.standard

140ms · cubic-bezier(0.2, 0, 0, 1)

140mscubic-bezier(0.2, 0, 0, 1)
Hoverthe card takes the hover tint
duration.fastease.standard

140ms · cubic-bezier(0.2, 0, 0, 1)

140mscubic-bezier(0.2, 0, 0, 1)

Reduced motion

The control drops its own motion (the radio's dot, the checkbox's draw, the switch's travel), and the card's tint still changes, so the choice reads the same.

The control inside keeps its own motion and sound: see Radio Group, Checkbox and Switch.

Reduced motion

The controls switch state without moving. The card's edge and the icon tile still change, so what is chosen stays clear.

AccessibilityKeyboard, ARIA, focus

Accessibility

  • Each card is a label around its control, so clicking anywhere on it operates the control, and the card's text names it.
  • A radio group is one tab stop: Tab lands on the chosen card, the arrow keys move the choice and wrap, and disabled cards are skipped. Checkbox and switch cards are each a tab stop, toggled with Space.
  • The card carries the focus ring for the control inside, which drops its own.
  • Name the group with a FieldLegend in a FieldSet, or aria-label on the ChoiceCardGroup. The icon is decorative and hidden from assistive technology.