こんにちは、かつコーチです。
前回は、フォームの入力値を取得する方法を解説しました。
今回は、HTML要素に独自の情報を持たせられる「data属性」の活用方法を扱います。
data属性を使いこなせるようになると、「HTML側にデータを持たせて、JavaScript側でそれを読み取る」という設計ができるようになり、コードの見通しがぐっと良くなります。
data属性とは?
基本の書き方
data属性とは、HTML要素に data-〇〇 という形式で自由に情報を埋め込める仕組みです。
<button data-user-id="123" data-role="admin">ユーザー情報を表示</button>
data- から始まる属性名であれば、user-id や role のように自分で好きな名前を付けられます。
class属性やid属性とは違い、あくまで「データを持たせるための属性」という位置づけです。
なぜdata属性が必要なのか
「そのデータをJavaScriptの変数にそのまま書けばいいのでは?」と思うかもしれません。
しかし、たとえば一覧表示された商品カードのように、同じ構造で中身のデータだけが違う要素が何十個もある場合、1つずつ変数を用意するのは非現実的です。
data属性を使えば、「どの要素がクリックされたか」に応じて、その要素が持つデータをその場で取り出せます。
サーバーサイドでHTMLを生成する場合も、テンプレート側でdata属性にデータを埋め込んでおけば、JavaScript側の実装がシンプルになります。
JavaScriptからdata属性を扱う
dataset プロパティで読み取る
data属性の値は、dataset プロパティを使って読み取ります。
<button id="userBtn" data-user-id="123" data-role="admin">
ユーザー情報を表示
</button>
const button = document.querySelector("#userBtn");
button.addEventListener("click", () => {
console.log(button.dataset.userId); // "123"
console.log(button.dataset.role); // "admin"
});
ここで注目してほしいのが、HTML側では data-user-id(ハイフン区切り)と書いているのに、JavaScript側では dataset.userId(キャメルケース)でアクセスしている点です。
data- の後のハイフン区切りは、JavaScriptで扱うときに自動的にキャメルケースへ変換されるというルールがあります。
dataset で値を書き換える
dataset は読み取りだけでなく、値を書き換えることもできます。
const button = document.querySelector("#userBtn");
button.dataset.role = "member";
console.log(button.dataset.role); // "member"
書き換えた値は、そのままHTML上の data-role 属性にも反映されます。
実践パターン:一覧要素からデータを取り出す
イベント委譲と組み合わせる
data属性は、以前解説したイベント委譲と組み合わせると特に威力を発揮します。
<ul id="productList">
<li data-product-id="p001" data-price="1500">Tシャツ</li>
<li data-product-id="p002" data-price="3200">パーカー</li>
<li data-product-id="p003" data-price="800">キャップ</li>
</ul>
const productList = document.querySelector("#productList");
productList.addEventListener("click", (event) => {
const item = event.target;
if (item.tagName === "LI") {
const productId = item.dataset.productId;
const price = Number(item.dataset.price);
console.log(`商品ID: ${productId}, 価格: ${price}円`);
}
});
親要素の #productList にイベントを1つ設定するだけで、どの <li> がクリックされても、そのdata属性から商品IDと価格を取り出せます。
商品が何十個に増えても、コードを変更する必要がないという点が大きなメリットです。
タブ切り替えUIでの活用例
タブメニューのように「クリックされたボタンに応じて表示するコンテンツを切り替える」UIでも、data属性が役立ちます。
<button data-tab="profile">プロフィール</button>
<button data-tab="settings">設定</button>
<div id="profile" class="tab-content">プロフィール内容</div>
<div id="settings" class="tab-content">設定内容</div>
const tabButtons = document.querySelectorAll("[data-tab]");
const tabContents = document.querySelectorAll(".tab-content");
tabButtons.forEach((btn) => {
btn.addEventListener("click", () => {
const targetId = btn.dataset.tab;
tabContents.forEach((content) => {
content.classList.toggle("hidden", content.id !== targetId);
});
});
});
data-tab の値と、表示したい要素の id を一致させておくことで、どのボタンが押されても同じロジックで表示切り替えができます。
つまずきやすいポイント:型変換の落とし穴
かつコーチが実際につまずいた話
商品の在庫管理画面で、data属性に在庫数を持たせて「在庫があれば購入ボタンを有効化する」処理を書いたことがあります。
<button id="buyBtn" data-stock="0">購入する</button>
const buyBtn = document.querySelector("#buyBtn");
if (buyBtn.dataset.stock) {
console.log("在庫あり、ボタンを有効化します");
} else {
console.log("在庫なし、ボタンを無効化します");
}
在庫数が 0 のはずなのに、コンソールには「在庫あり、ボタンを有効化します」と表示されてしまいました。
原因は、dataset.stock が返す値は常に文字列型だという点でした。
"0" という文字列は、空文字ではないため if 文の条件式では「真」と判定されてしまいます。
数値の 0 であれば「偽」と判定されるところが、文字列の "0" では挙動が変わってしまうというわけです。
❌ Before:文字列のままif文の条件に使う
const buyBtn = document.querySelector("#buyBtn");
if (buyBtn.dataset.stock) {
console.log("在庫あり");
// data-stock="0" でも文字列"0"は真と判定されてしまう
} else {
console.log("在庫なし");
}
✅ After:Numberで数値に変換してから比較する
const buyBtn = document.querySelector("#buyBtn");
const stock = Number(buyBtn.dataset.stock);
if (stock > 0) {
console.log("在庫あり");
} else {
console.log("在庫なし");
// data-stock="0" のときは正しく在庫なしと判定される
}
Number() で数値に変換したうえで stock > 0 という条件にすることで、意図した通りの判定になりました。
フォームの value プロパティのときと同様、dataset の値も常に文字列で返ってくるという点は、忘れた頃につまずきやすいポイントなので覚えておいてください。
まとめ
この記事のポイント
- data属性は
data-〇〇の形式でHTML要素に独自データを持たせる仕組み - JavaScriptからは
datasetプロパティでキャメルケースに変換されてアクセスする - イベント委譲と組み合わせると、一覧要素のデータ取得を効率化できる
datasetの値は常に文字列型なので、数値として扱う場合はNumber()での変換が必要- タブ切り替えなど、HTML構造とJavaScriptロジックを疎結合にするUIパターンでも活躍する
次に読むべき記事
data属性の活用ができるようになったら、次はDOM操作を行う際に気をつけたいパフォーマンスの注意点を見ていきましょう。
→ 次の記事:DOM操作のパフォーマンスに関する注意点