Webパーツ辞典

選択カードChoice card

枠で囲んだカードを並べ、どれか1つを押して選ぶ入力。見出し・説明・料金がカードに入り、選んだカードは枠が太くなりチェックの印が付く。

表示例

プランを選ぶ

アイコン: Font Awesome 7 Free(fa-solid / fa-regular)

別名・英語表記

  • カード型ラジオボタン
  • ラジオカード
  • 選択タイル
  • プラン選択カード
  • カード型の選択肢
  • Choice card

実装例

<fieldset class="x-choice-card">
  <legend class="x-choice-card__lg">プランを選ぶ</legend>
  <!-- カード全体が label なので、どこを押しても中の radio が選ばれる。
       名前はタイトルだけにし、説明と料金は aria-describedby で後から読ませる -->
  <div class="x-choice-card__list">
    <label class="x-choice-card__c">
      <input class="x-choice-card__in" type="radio" name="plan" value="lite"
             aria-labelledby="x-choice-card-t1" aria-describedby="x-choice-card-d1">
      <i class="x-choice-card__mk fa-solid fa-circle-check" aria-hidden="true"></i>
      <span class="x-choice-card__t" id="x-choice-card-t1">ライト</span>
      <span class="x-choice-card__d" id="x-choice-card-d1">1人で使う。保存容量 5GB。月 500円</span>
    </label>
    <label class="x-choice-card__c">
      <input class="x-choice-card__in" type="radio" name="plan" value="team" checked
             aria-labelledby="x-choice-card-t2" aria-describedby="x-choice-card-d2">
      <i class="x-choice-card__mk fa-solid fa-circle-check" aria-hidden="true"></i>
      <span class="x-choice-card__t" id="x-choice-card-t2">チーム</span>
      <span class="x-choice-card__d" id="x-choice-card-d2">10人まで。保存容量 100GB。月 2,400円</span>
    </label>
  </div>
</fieldset>

AIへの指示文

「選択カード(Choice card)」を実装してください。

## これは何か
枠で囲んだカードを並べ、どれか1つを押して選ぶ入力。見出し・説明・料金がカードに入り、選んだカードは枠が太くなりチェックの印が付く。

## 使いどころ
- 料金プラン・配送方法・支払い方法のように、選択肢ごとに説明や金額を見比べてから選んでほしいとき
- 選択肢が2〜4個で、1行の文言では違いが伝わらないとき

## 実装の要件
- fieldset > legend + label.カード > input[type=radio][name 共通] + タイトル + 説明。label で包むのでカードのどこを押しても選ばれる
- 選ばれたカードの見た目は label:has(input:checked) で切り替える。:has() は Chrome・Edge は 105 から、Safari は 15.4 から、Firefox は 121 から対応し、Baseline の「広く利用可能」に入っているので、input:checked + 兄弟要素の形の代替は書かない
- フォーカスの輪郭は label:has(input:focus-visible) でカードの外側に出す
- 既定で1つ選んでおかないなら required を付け、未選択のまま送られたときのメッセージを legend のそばに出す
- ラジオボタンとの違い: 中身は同じ「1つだけ選ぶ」入力。選択肢に説明や料金が付き、見比べさせたいときだけカードにする。名前だけで分かる選択肢をカードにすると、場所を取るだけで読む量が増える
- カード(container/card)との違い: あちらは情報のまとまりを見せる器で、押しても選択の状態を持たない。選択カードは中に本物の radio があり、フォームとして値を送る
- 選んだ状態を色の差だけで示さない。枠の太さ・チェックの印・radio の塗りのように形でも変える
- カードの中にリンクやボタンを入れない。label の中の操作部品は押し分けにくく、どちらが反応するか分からなくなる
- 複数選べる場合は radio を checkbox に替える。見た目が同じでも、1つだけか複数かを legend や補足文で言葉にする

## アクセシビリティの要件
- div と onclick で作らず、input type="radio" を label で包む。矢印キーでの移動・Space での選択・フォーム送信がそのまま動く
- radio を display:none や visibility:hidden で消さない。フォーカスも読み上げも無くなる。見せたくないときは見た目だけ隠し、カードの枠に :focus-visible の輪郭を出す
- グループは fieldset と legend で囲み、何を選ぶのかを言葉にする(1.3.1 情報及び関係性)
- カード全体が label だと、中の文章がすべて名前として読まれて長くなる。aria-labelledby でタイトルだけを名前にし、説明と料金は aria-describedby で結ぶ
- 選択の表示は色だけに頼らない(1.4.1 色の用途)。カードの枠は背景に対して 3:1 以上にする(1.4.11 非テキストのコントラスト)

## 参考にする実装
この形を出発点にして、プロジェクトの命名規則・色・余白に合わせて調整してください。

```html
<fieldset class="x-choice-card">
  <legend class="x-choice-card__lg">プランを選ぶ</legend>
  <!-- カード全体が label なので、どこを押しても中の radio が選ばれる。
       名前はタイトルだけにし、説明と料金は aria-describedby で後から読ませる -->
  <div class="x-choice-card__list">
    <label class="x-choice-card__c">
      <input class="x-choice-card__in" type="radio" name="plan" value="lite"
             aria-labelledby="x-choice-card-t1" aria-describedby="x-choice-card-d1">
      <i class="x-choice-card__mk fa-solid fa-circle-check" aria-hidden="true"></i>
      <span class="x-choice-card__t" id="x-choice-card-t1">ライト</span>
      <span class="x-choice-card__d" id="x-choice-card-d1">1人で使う。保存容量 5GB。月 500円</span>
    </label>
    <label class="x-choice-card__c">
      <input class="x-choice-card__in" type="radio" name="plan" value="team" checked
             aria-labelledby="x-choice-card-t2" aria-describedby="x-choice-card-d2">
      <i class="x-choice-card__mk fa-solid fa-circle-check" aria-hidden="true"></i>
      <span class="x-choice-card__t" id="x-choice-card-t2">チーム</span>
      <span class="x-choice-card__d" id="x-choice-card-d2">10人まで。保存容量 100GB。月 2,400円</span>
    </label>
  </div>
</fieldset>
```

```css
/* 貼った先のリセットに頼らないよう、この部品の中だけ border-box にする */
.x-choice-card,
.x-choice-card *:not([class*="fa-"]),
.x-choice-card *:not([class*="fa-"])::before,
.x-choice-card *:not([class*="fa-"])::after {
  box-sizing: border-box;
  /* 貼った先の既定の書体に引きずられないようにする。書体が変わると
     文字の幅と高さが変わり、枠のサイズまでずれる */
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Hiragino Sans", "Noto Sans JP", "Yu Gothic UI", Meiryo, sans-serif;
}

.x-choice-card {
  width: 320px;
  max-width: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  color: #1b2028;
}
.x-choice-card__lg {
  margin-bottom: 8px;
  padding: 0;
  font-size: 12px;
  font-weight: 700;
}
.x-choice-card__list {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
}
/* カード全体が押せる範囲。選ばれたときは枠の太さ・背景・チェックの印の3つで示し、色だけに頼らない */
.x-choice-card__c {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-height: 118px;
  padding: 12px 12px 14px;
  border: 1px solid #7f8a99;
  border-radius: 10px;
  background: #fff;
  cursor: pointer;
}
.x-choice-card__c:hover {
  border-color: #1b2028;
}
.x-choice-card__c:has(.x-choice-card__in:checked) {
  border-color: #1d4ed8;
  box-shadow: 0 0 0 2px #1d4ed8;
  background: #eff4ff;
}
.x-choice-card__c:has(.x-choice-card__in:focus-visible) {
  outline: 2px solid #1d4ed8;
  outline-offset: 4px;
}
/* 本物の radio は残して見せる。形(塗りつぶした丸)でも選択が分かり、強制カラーモードでも消えない */
.x-choice-card__in {
  width: 18px;
  height: 18px;
  margin: 0 0 4px;
  accent-color: #1d4ed8;
}
.x-choice-card__mk {
  position: absolute;
  top: 10px;
  right: 10px;
  color: #1d4ed8;
  font-size: 18px;
  visibility: hidden;
}
.x-choice-card__c:has(.x-choice-card__in:checked) .x-choice-card__mk {
  visibility: visible;
}
.x-choice-card__t {
  font-size: 14px;
  font-weight: 700;
}
.x-choice-card__d {
  color: #4b5563;
  font-size: 11.5px;
  line-height: 1.6;
}
```

## 出力の約束
- HTML と CSS を分けて出す。JavaScript が要るときは素の JavaScript で書き、UIフレームワークは使わない。
- 参考実装がアイコンに Font Awesome のクラスを使っている場合は、プロジェクトで使っているアイコンかインライン SVG に置き換えてよい。
- 上のアクセシビリティ要件を満たす。満たせない箇所があるときは、理由を添えて先に知らせる。
- 色・角丸・余白は既存のデザイントークンがあればそれを使う。無ければ CSS 変数として切り出す。

使いどころ

  • 料金プラン・配送方法・支払い方法のように、選択肢ごとに説明や金額を見比べてから選んでほしいとき
  • 選択肢が2〜4個で、1行の文言では違いが伝わらないとき

注意点

  • ラジオボタンとの違い: 中身は同じ「1つだけ選ぶ」入力。選択肢に説明や料金が付き、見比べさせたいときだけカードにする。名前だけで分かる選択肢をカードにすると、場所を取るだけで読む量が増える
  • カード(container/card)との違い: あちらは情報のまとまりを見せる器で、押しても選択の状態を持たない。選択カードは中に本物の radio があり、フォームとして値を送る
  • 選んだ状態を色の差だけで示さない。枠の太さ・チェックの印・radio の塗りのように形でも変える
  • カードの中にリンクやボタンを入れない。label の中の操作部品は押し分けにくく、どちらが反応するか分からなくなる
  • 複数選べる場合は radio を checkbox に替える。見た目が同じでも、1つだけか複数かを legend や補足文で言葉にする

アクセシビリティの要点

  • div と onclick で作らず、input type="radio" を label で包む。矢印キーでの移動・Space での選択・フォーム送信がそのまま動く
  • radio を display:none や visibility:hidden で消さない。フォーカスも読み上げも無くなる。見せたくないときは見た目だけ隠し、カードの枠に :focus-visible の輪郭を出す
  • グループは fieldset と legend で囲み、何を選ぶのかを言葉にする(1.3.1 情報及び関係性)
  • カード全体が label だと、中の文章がすべて名前として読まれて長くなる。aria-labelledby でタイトルだけを名前にし、説明と料金は aria-describedby で結ぶ
  • 選択の表示は色だけに頼らない(1.4.1 色の用途)。カードの枠は背景に対して 3:1 以上にする(1.4.11 非テキストのコントラスト)

関連するパーツ