ラジオボタンを未選択の状態にする方法を考えよう

2022年3月30日 2023年11月8日
カテゴリ: プログラミング
JavaScript HTML

HTML で作成した入力フォームのラジオボタン (オプションボタンとも) について、一度選択した後で未選択の状態にする方法を考えてみましょう。

そもそもラジオボタンは必須入力の項目に使われることが多く、同一グループのラジオボタンのいずれかが必ずチェックされている状態になるという仕様なのか、一度選択すると未選択の状態には戻せません。
それでも入力のケースとしては「ラジオボタンが未選択の状態」もありうるという設計にしたかったので、その対処方法を考えました。

以下のような3つの方針を立てました。
1. 「未選択」の選択肢を作る
2. 選択解除のボタンを作る
3. 選択状態でクリックすると選択解除する機能を作る

1. 「未選択」の選択肢を作る

たとえば性別を入力する選択肢ではたまに「未選択」とか「未回答」というような選択肢があったりしますよね。

こんな感じ。

コードとしてはこんな感じでしょうか。

HTML
<input type="radio" name="sex" id="man"><label for="man">男</label>
<input type="radio" name="sex" id="woman"><label for="woman">女</label>
<input type="radio" name="sex" id="none"><label for="none">未選択</label>

HTML のみで実現できるので対処方法としては十分にアリだと思います。
ですが、ラジオボタンの項目が多くなるほど「未選択」の選択肢をいちいち用意しなければならないのでちょっと手間ですよね。

2. 選択解除のボタンを作る

もっとわかりやすく「選択解除」ボタンを作るという方法もあります。

HTML
<input type="radio" name="sex" id="man"><label for="man">男</label>
<input type="radio" name="sex" id="woman"><label for="woman">女</label>
<button class="clear-radio-button" name="sex">選択解除</button>
JavaScript
const clearButtons = document.querySelectorAll("button.clear-radio-button");

clearButtons.forEach(clearButton => {
  clearButton.addEventListener("click", func =()=> {
    let queryStr = 'input[name="' + clearButton.name + '"]'
    let radioButtons = document.querySelectorAll(queryStr);
    radioButtons.forEach(radioButton => {
      radioButton.checked = false;
    });
  });
});

この方法の問題は、ラジオボタンの各グループに対してそれぞれ選択解除のボタンを作らなければならないことでしょう。
これもラジオボタンの項目が少なければいいですが、ラジオボタンの項目が多くなるほどボタン追加の手間がかかります。

ただ、この例のように「選択解除」と明記しておけるので操作の意図が分かりやすく、ユーザフレンドリーであるとも言えます。

3. 選択状態でクリックすると選択解除する機能を作る

チェックボックスのように、クリックするごとに ON と OFF を切り替えられるようにします。
また、label がある場合は label をクリックしても切り替えられるようにします。

HTML
<input type="radio" name="sex" id="man"><label for="man">男</label>
<input type="radio" name="sex" id="woman"><label for="woman">女</label>
JavaScript
const radioButtons = document.querySelectorAll('input[type="radio"]');

const clearRadioButton = (radioButton) => {
  setTimeout(func =()=>{
    radioButton.checked = false;
  },100)
}

radioButtons.forEach(radioButton => {
  let queryStr = 'label[for="' + radioButton.id + '"]'
  let label = document.querySelector(queryStr)

  radioButton.addEventListener("mouseup", func=()=>{
    if(radioButton.checked){
      clearRadioButton(radioButton)
    }
  });

  if(label){
    label.addEventListener("mouseup", func=()=>{
      if(radioButton.checked){
        clearRadioButton(radioButton)
      }
    });
  }

});

ポイントになるのは、「マウスをクリックして指を離したタイミングでラジオボタンが OFF なら ON にする」というラジオボタンの挙動です。
mouseup イベント時、単純にラジオボックスが ON(checked=true) なら OFF(checked=false) という風にすると

指を離す

JavaScript の処理でラジオボタンを OFF にする

指を離したタイミングでラジオボタンが OFF なので ON になる

という一連の処理が瞬時に行われるようで、ON/OFF の切り替えがうまくできません。
そのため、setTimeout で ラジオボタンを OFF にするタイミングを少しだけずらしています。

直感的な操作になるので、ユーザにこの機能があることを伝えておかないとラジオボタンのチェックが取消せることに気づかないなんてこともあり得るので注意が必要です。

関連の記事

【Django】CSS や JavaScript の変更が反映されないときの対処法

文章を全部読むまで押せないチェックボックスを作ってみよう

Sphinxで作ったドキュメントの外部リンクを新しいタブで開く方法を考える

CSSで色見本のアイコンを作ろう