チェックボックスの状態でON/OFF以外に第3の状態があるのをご存知ですか?
上記の画像の「トップス」の部分のindeterminate
という状態がそれにあたります。
ARCHETYPではShopify ExpertとしてECサイトのテーマ開発やカスタマイズをやっているのですが、検索や絞り込みのUIに親子関係があるチェックボックスをよく実装します。
今回はそんな親子階層を利用したユーザーがわかりやすいチェックボックスUIをindeterminate
を用いて実装する方法をご紹介します。
jQueryを利用した実装を紹介されていたWebSpaceBlog様の記事を参考にさせていただきました。
結果
最初に結果のcodepenを貼り付けておきます。
See the Pen 中途半端なcheckbox(vanilla) by kamipoo (@kamipoo) on CodePen.
解説
HTML
HTMLはごくごくシンプルにリストの入れ子にチェックボックスを入れています。
グループを括る親のinputのclassにparent
を指定します。
子アイテムを括るulのclassにchild
を指定します。
ちなみにindeterminate
はタグ属性では設定できず、JavaScriptを用いて設定する必要があります。
<ul>
<li><label><input type="checkbox" class="parent"> カテゴリ1</label>
<ul class="child">
<li><label><input type="checkbox"> アイテム1</label></li>
<li><label><input type="checkbox" checked> アイテム2</label></li>
<li><label><input type="checkbox"> アイテム3</label></li>
</ul></li>
<li><label><input type="checkbox" class="parent"> カテゴリ2</label>
<ul class="child">
<li><label><input type="checkbox"> アイテム1</label></li>
<li><label><input type="checkbox" checked> アイテム2</label></li>
<li><label><input type="checkbox"> アイテム3</label></li>
</ul></li>
</ul>
JavaScript
jQueryのコードを元にVanilla化させていただきました。
処理1
子チェックボックスをクリックした際の動作を定義します。
子チェックボックスの属するグループのチェックされた数を比較して、親チェックボックスの状態を制御しています。
条件
- 全てがチェックされていれば
checked = true
indeterminate = false
- なにもチェックされていなければ
checked = false
indeterminate = false
- 上記以外は
checked = false
indeterminate = true
処理2
親チェックボックスをクリックした際の動作を定義します。
親チェックボックスのチェック状態を子チェックボックスに適用します。
document.addEventListener("DOMContentLoaded", () => {
//子要素をクリックした時に親要素のチェック状態をコントロール
document.querySelectorAll('.child').forEach((child) => {
child.addEventListener('click', (e) => {
const parent = child.closest('li').querySelector('input[type=checkbox]');
const checkboxCount = child.querySelectorAll('input[type=checkbox]').length;
const selectedCount = child.querySelectorAll('input[type=checkbox]:checked').length;
if (checkboxCount === selectedCount) {
parent.indeterminate = false;
parent.checked = true;
} else if(0 === selectedCount) {
parent.indeterminate = false;
parent.checked = false;
} else {
parent.indeterminate = true;
parent.checked = false;
}
});
let e = new Event('click');
child.dispatchEvent( e );
});
//親要素をクリックした時に子要素のチェック状態をコントロール
document.querySelectorAll('.parent').forEach((parent) => {
parent.addEventListener('click', (e) => {
parent.closest('li').querySelectorAll('.child input[type=checkbox]').forEach((items) => {
items.checked = parent.checked;
});
});
});
});
Shopifyのテーマ開発はjQueryや各種フレームワークを使用しているアプリが多くコンフリクトを起こすことがしばしばあり、ARCHETYPのエンジニアチームでは脱jQuery、Vanilla推奨で開発しています。
ARCHETYPでは、Shopifyのテーマ開発やアプリ開発をやりたいエンジニアを募集しております!
気になった方はお気軽にエントリーをお待ちしております!
https://www.archetyp.jp/recruit/