codefast/ui

Command Palette

Search for a command to run...

Source
Form

Checkbox Cards

Card-style multi-select. Each card has a built-in checkbox with highlighted selected state.

Examples

Multi-select cards

Card-style multi-select with highlighted state and a live list of choices.

Enabled: analytics

30 lines
import { CheckboxCards, CheckboxCardsItem } from "@codefast/ui/checkbox-cards";
import { useState } from "react";

const FEATURES = [
  { value: "analytics", label: "Analytics", description: "Track usage and insights" },
  { value: "notifications", label: "Notifications", description: "Email and push alerts" },
  { value: "api", label: "API access", description: "Integrate with external tools" },
];

export function CheckboxCardsFeatures() {
  const [selected, setSelected] = useState<Array<string>>(["analytics"]);

  return (
    <div className="w-full max-w-xs space-y-3">
      <CheckboxCards className="grid gap-2" value={selected} onValueChange={(value) => setSelected(value ?? [])}>
        {FEATURES.map(({ value, label, description }) => (
          <CheckboxCardsItem key={value} value={value}>
            <div className="flex flex-col gap-0.5 text-start">
              <span className="text-sm font-medium">{label}</span>
              <span className="text-xs text-ui-muted">{description}</span>
            </div>
          </CheckboxCardsItem>
        ))}
      </CheckboxCards>
      <p className="text-center text-xs text-ui-muted">
        Enabled: <span className="font-medium text-ui-fg">{selected.join(", ") || "none"}</span>
      </p>
    </div>
  );
}

Two columns

Lay cards out in a grid for compact add-on pickers.

27 lines
import { CheckboxCards, CheckboxCardsItem } from "@codefast/ui/checkbox-cards";
import { useState } from "react";

const ADDONS = [
  { value: "ci", label: "CI minutes" },
  { value: "seats", label: "Extra seats" },
  { value: "storage", label: "More storage" },
  { value: "support", label: "Priority support" },
];

export function CheckboxCardsColumns() {
  const [selected, setSelected] = useState<Array<string>>(["ci", "storage"]);

  return (
    <CheckboxCards
      className="grid w-full max-w-sm grid-cols-2 gap-2"
      value={selected}
      onValueChange={(value) => setSelected(value ?? [])}
    >
      {ADDONS.map(({ value, label }) => (
        <CheckboxCardsItem key={value} value={value}>
          <span className="text-sm font-medium">{label}</span>
        </CheckboxCardsItem>
      ))}
    </CheckboxCards>
  );
}

Disabled option

Mark an option unavailable while keeping it visible.

29 lines
import { CheckboxCards, CheckboxCardsItem } from "@codefast/ui/checkbox-cards";
import { useState } from "react";

const PLANS = [
  { value: "free", label: "Free", description: "Up to 3 projects", disabled: false },
  { value: "pro", label: "Pro", description: "Unlimited projects", disabled: false },
  { value: "enterprise", label: "Enterprise", description: "Contact sales", disabled: true },
];

export function CheckboxCardsDisabled() {
  const [selected, setSelected] = useState<Array<string>>(["pro"]);

  return (
    <CheckboxCards
      className="grid w-full max-w-xs gap-2"
      value={selected}
      onValueChange={(value) => setSelected(value ?? [])}
    >
      {PLANS.map(({ value, label, description, disabled }) => (
        <CheckboxCardsItem key={value} value={value} {...(disabled ? { disabled } : {})}>
          <div className="flex flex-col gap-0.5 text-start">
            <span className="text-sm font-medium">{label}</span>
            <span className="text-xs text-ui-muted">{description}</span>
          </div>
        </CheckboxCardsItem>
      ))}
    </CheckboxCards>
  );
}

Usage

The minimal import and composition — see Examples below for styled, real-world variants.

10 lines
import { CheckboxCards, CheckboxCardsItem } from "@codefast/ui/checkbox-cards";

export function CheckboxCardsUsage() {
  return (
    <CheckboxCards className="grid grid-cols-2 gap-3" defaultValue={["storage"]}>
      <CheckboxCardsItem value="storage">Extra storage</CheckboxCardsItem>
      <CheckboxCardsItem value="support">Priority support</CheckboxCardsItem>
    </CheckboxCards>
  );
}

Anatomy

How the parts nest — every slot the component exposes, in composition order.

CheckboxCards
└── CheckboxCardsItem

Features

  • Each CheckboxCardsItem already renders its own Label wrapping the checkbox and its children — the whole card is clickable, no separate <Label htmlFor> needed.
  • Built on the same multi-select headless primitive as Checkbox Group, styled as selectable cards sharing one value array.

API reference

Props for each part of the component. All native element props are also forwarded.

CheckboxCards

A multi-selection group of cards sharing one value array.

valuestring[]

The controlled list of selected card values.

defaultValuestring[]

The selected card values when initially rendered (uncontrolled).

onValueChange(value: string[]) => void

Called when the selected card values change.

CheckboxCardsItem

valuestring

Added to the array when the card is selected (required).

disabledboolean

Makes a single card non-selectable.

Defaultfalse

Accessibility

Built to be keyboard-navigable and screen-reader friendly out of the box.

KeyFunction
TabMoves between cards.
SpaceToggles the focused card.
  • Each card is a checkbox with its own aria-checked.
  • The whole card is the hit target, not just a small box.
  • Keep card content concise so the selected state reads clearly.

Guidelines

Conventions that keep usage consistent across an app.

Do

  • Use for picking several rich options (features, add-ons).
  • Show a short description on each card.

Don’t

  • Don’t use for single-select — that’s Radio Cards.
  • Don’t put multiple actions inside a card.

Explore further

Ready to integrate?

Follow the Getting Started guide to install @codefast/ui, or browse the full component gallery.