
はじめに
DOM 操作のフックに、
<button type="button" class="js-toggle-menu">開く</button>
みたいなクラス指定、よく使いますよね。
でもこれ、CSS のスタイル用クラスと、JS の機能用クラスがごっちゃになって、「どっちのためのクラス?」って後から迷子になりがちです。
そんな悩みを解決してくれるのが、data 属性による JavaScript フック設計です!
クラス指定のよくある悩み
- ・CSSとJSの責務が混ざってて壊れやすい
- ・命名ルールが人によってバラバラ
- ・別担当者あるいは非エンジニアがクラスを変更→JS が壊れる
…という感じで、規模が大きくなると特にツラい。
data-js-**属性で全部スッキリ解決!
そこでオススメしたいのが、data 属性です!!
HTML5 から使えるようになったdata-**属性、実はめっちゃ便利です。
特に、JavaScriptのフック用途に使うと爆発的に管理しやすくなります。
例をどうぞ
<button
data-js-trigger="menu"
data-js-toggle-class="is-open"
>
メニュー開く
</button>
<div data-js-target="menu" class="menu">中身</div>
const dataPref = "data-js";
const trigger = document.querySelector(`[${dataPref}-trigger]`);
const key = trigger.getAttribute(`${dataPref}-trigger`);
const target = document.querySelector(`[${dataPref}-target="${key}"]`);
const className = trigger.getAttribute(`${dataPref}-toggle-class`);
target?.classList.toggle(className);
ほら、クラス名をJSに直書きしてない!
クラス名すら HTML 側で宣言できるってめっちゃ柔軟じゃないですか?
これが data属性フック設計のいいところ
【1】見た目とJSの責任が完全に分かれる!
- ・クラスは見た目用(btn, menu, is-open など)
- ・data 属性は JS 用(data-js-trigger, data-js-target など)
→ もう「このクラスってJS 用?」って迷わない!
【2】data 属性って、値を持てるんです(これ最強)
クラスって「ラベル」だけなんですよね。
でも data属性なら、値を埋め込める!
<button
data-js-modal-trigger="type01"
data-js-modal-toggle-class="is-active"
>
モーダル開く
</button>
<div data-js-modal-target="type01" class="modal">中身</div>
const dataPref = "data-js-modal";
const trigger = document.querySelector(`[${dataPref}-trigger]`);
const key = trigger.getAttribute(`${dataPref}-trigger`);
const target = document.querySelector(`[${dataPref}-target="${key}"]`);
const className = trigger.getAttribute(`${dataPref}-toggle-class`);
target?.classList.toggle(className);
→ いろんなUIに使い回せる、無限汎用トグル関数の爆誕!
【3】タブUIも値でつなぐだけで OK
<!-- タブ -->
<button data-js-tab-trigger="a">A</button>
<button data-js-tab-trigger="b">B</button>
<!-- 中身 -->
<div data-js-tab-target="a">Aの内容</div>
<div data-js-tab-target="b">Bの内容</div>
const dataPref = "data-js-tab";
const triggersAttr = `${dataPref}-trigger`;
const targetsAttr = `${dataPref}-target`;
document.querySelectorAll(`[${triggersAttr}]`).forEach((trigger) => {
trigger.addEventListener("click", () => {
const key = trigger.getAttribute(triggersAttr);
document.querySelectorAll(`[${targetsAttr}]`).forEach((content) => {
content.hidden = content.getAttribute(targetsAttr) !== key;
});
});
});
if 文なしでタブ切り替え、楽すぎる。
【4】非エンジニアや別担当者が触っても壊れにくい!
- ・クラス名を変えても、JSに影響しない(JSはdata-**で管理してるから)
- ・data属性さえ守れば、機能は絶対に壊れない
- ・非エンジニアでも「これとこれが対応してるのね」って分かる
【5】命名ルール:data-js-役割-機能で統一感出る
属性名 | 意味 |
---|---|
data-js-modal-trigger |
モーダルを開くボタン |
data-js-tab-trigger |
タブ切り替えボタン |
data-js-tab-target |
タブの中身 |
data-js-toggle-class |
トグルするクラス名 |
フックの一例
→ 名前見ただけで「何のための属性か」一発で分かる!
よくある疑問
Q. data属性ってクラスよりセレクタ遅くない?
→ ほぼ誤差です。現代ブラウザなら体感ゼロ。
Q. SEOやアクセシビリティに問題ある?
→ ないです。data属性はHTML5で正式に OK な書き方!
まとめ:data属性フックで快適 JS ライフを
比較項目 | クラス指定 | data 属性フック(おすすめ) |
---|---|---|
スタイルとの責務分離 | 難しい | しっかり分離できる |
柔軟性 | if 文だらけ | 値ベースで楽ちん |
再利用性 | 構造に縛られる | 汎用ロジックでどこでも使える |
チーム開発 | 壊れやすい | 安定&安全 |
命名統一 | バラバラになりがち | data-js-役割-機能 で超わかりやすい |
最後に
data属性でフックするだけで、JSがこんなに整理されて、HTML側で「動き方」まで決められるようになるなんて、素晴らしいですよね。
今では、もうクラスでフックする気になれません。もしあなたのプロジェクトでも「JS がごちゃついてきたな…」と思ったら、data属性ぜひ試してみてください!