OptionCards present the functionality of a radio or checkbox in a more visually prominent card format with an increased click area.

OptionCard

Usage

  • Use OptionCard for decisions that benefit from icons and descriptions — choosing a plan, selecting a template, picking a provider. Cards are visually prominent and give the choice an increased click area.
  • Use Radio instead when the choice is single-select, cannot be deselected, and must be inline and visually subtle.
  • Use Checkbox instead when the choice is multi-select and must be inline and visually subtle.
  • Provide a title (title), a description (description), or both — a card requires at least one.
  • Keep content structure consistent across every card in a group: if one card has a title and description, all of them do.
  • Use the default horizontal layout (layout="horizontal") for most groups, especially when the description carries meaning.
  • Use vertical layout (layout="vertical") for icon-focused selections where the icon is the primary visual identifier, such as choosing a provider or integration.
  • Wrap grouped cards in OptionCardGroup — it owns selection state, selection mode, sizing, and card arrangement.

Appearance

  • Icons: pass a Pluma icon name (icon) or a custom image URL (iconSrc) for brand logos and illustrations the icon library doesn't cover. A custom image follows the same positioning and size rules as a Pluma icon.
  • In horizontal layout, the icon sits to the left of the content and a divider separates them.
  • In vertical layout, the icon sits above the content and the text is centered.
  • Sizes: size="md" is the default and gives titles and descriptions more breathing room. size="sm" fits tighter layouts and simpler choices needing less visual emphasis.

Behaviors

  • Radio mode (inputType="radio", the default) allows one selection per group and cards cannot be deselected — another card must be chosen instead.
  • Checkbox mode (inputType="checkbox") allows multiple independent selections and each card toggles on and off.
  • Selected state (isSelected) renders the card as checked.
  • Hover changes the border color to signal the card is interactive.
  • Focus renders the standard 2px focus ring.
  • Disabled state (isDisabled) mutes the border and text colors and blocks all interaction.

Content

  • Write titles that clearly name the option — never vague labels like "Option 1".
  • Keep titles to one to three words where possible, in sentence case with no end punctuation.
  • Write descriptions that add context the title alone can't convey. Keep them to a single short sentence explaining the option's purpose or behavior; end punctuation is not required.
  • Never restate the title in the description.

Implementation Notes

  • Content: title and description render the built-in title and description. React children and the Ember default block render below them, so built-in and custom content can coexist.
  • Custom content composes OptionCardTitle and OptionCardDescription (Ember: <PlumaOptionCardTitle>, <PlumaOptionCardDescription>) alongside other elements such as badges. Both accept any Text props.
  • When a card renders no title, pass ariaLabel — the accessible name otherwise comes from the title.
  • iconSrc renders through the Image component with alt="" (decorative). imageWithBoundingBox defaults to true; set it to false for a logo that needs to render larger without the icon-matching padding. It only applies alongside iconSrc.
  • iconSize overrides the icon size, which otherwise follows the card's resolved size.
  • The divider renders whenever icon or iconSrc is set and layout="horizontal" — it does not depend on a title being present, despite what the anatomy diagram describes.
  • canSelect (default true) blocks selecting an unselected card while still allowing an already-selected card to be deselected. isDisabled blocks both.
  • Group context: OptionCardGroup supplies inputType, value, onChange, size, name, isDisabled, and canSelect to its cards. Group values win over per-card inputType and size; group isDisabled and canSelect combine with the card's own.
  • Group value type follows the mode: a string for radio, a string[] for checkbox, with onChange receiving the matching type.
  • Group layout: cardsLayout ("flex" default, or "grid"), cardsDirection (default "row"), cardsGap (default "200"), shouldWrapCards, and the grid-only cardsColumns, cardsRows, cardsAreas, cardsAutoFlow.
  • Label the group with label, ariaLabel, or ariaLabelledby on OptionCardGroup.
  • onChange on an individual OptionCard is deprecated — use onCheckedChange, which receives (checked, event). On OptionCardGroup, onChange is the supported callback and takes precedence over both card-level handlers.
  • Ember: invoke <PlumaOptionCard> and <PlumaOptionCardGroup> with @-prefixed args (@title, @icon, @layout) and yield custom content into the default block. @onChange receives a native change event; React receives a React synthetic event.

On this page