Table 1 — テーブル 1 — 基本スタイル
このコンポーネントについて
テーブルは業務アプリでデータ一覧を表示する最もポピュラーなUIです。 ただ行と列を並べるだけでは視認性が低く、行数が増えるほど「どの行を見ているか」を見失いやすくなります。
このページでは、HTML tableに視認性を高める3つのスタイルを加える方法を紹介します。 ヘッダーの背景色設定・1行おきのストライプ・マウスオーバーのホバーハイライトを組み合わせることで、 大量データ行でも目線を追いやすい一覧が作れます。 また状態カラムにはピル型バッジを使い、在籍・休職・退職を色で一目で判別できるようにしています。
HTML・CSS・バニラJavaScriptのみで実装しており、フレームワーク不要でコピペすぐに動きます。
- ヘッダースタイル — ヘッダー行に背景色と白文字を設定。列の役割をひと目で把握できる
- ストライプ行 —
:nth-child(even)で偶数行に薄い背景色を付け、行間の境界を視覚的に強調する - ホバーハイライト — マウスオーバーで行全体を明るい背景色にし、「いまどの行にいるか」を示す
- 状態バッジ —
data-status属性とCSSで在籍(緑)・休職(黄)・退職(グレー)を色分け表示 - 横スクロール対応 —
overflow-x: autoのラッパーで、スマホ幅でもレイアウトが崩れない - 動的レンダリング —
columns / rows形式のデータからJavaScriptでテーブルを動的生成。データの差し替えが容易
デモ
サンプルソース
4つのファイルを同じフォルダに保存し、簡易サーバーで index.html を開くと動作確認できます。
ファイル構成:index.html / style.css / script.js / data/data.json(data フォルダを作って中に配置)
保存時の文字コードは UTF-8 を指定してください。fetch() は file:// では動作しないため、VS Code の Live Server 等で開いてください。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>テーブル(基本スタイル)サンプル</title>
<link rel="stylesheet" href="./style.css">
</head>
<body>
<div class="tbl-scroll">
<table class="tbl" id="js-table">
<thead><tr id="js-thead-row"></tr></thead>
<tbody id="js-tbody"></tbody>
</table>
</div>
<script src="./script.js"></script>
</body>
</html>
/* テーブル(基本スタイル)— style.css */
:root {
--tbl-header-bg: #2B7FE8; /* ヘッダー背景 */
--tbl-header-txt: #ffffff; /* ヘッダー文字 */
--tbl-stripe-bg: #F4F7FF; /* 偶数行の背景 */
--tbl-hover-bg: #EBF2FF; /* ホバー時の背景 */
--tbl-border: #E5E9F2; /* 行の区切り線 */
--tbl-txt: #1A2332; /* 本文テキスト */
}
*, *::before, *::after { box-sizing: border-box; }
body {
font-family: sans-serif;
padding: 24px;
background: #f8f9fa;
}
/* 横スクロール可能なラッパー */
.tbl-scroll {
overflow-x: auto;
border-radius: 8px;
box-shadow: 0 1px 6px rgba(0, 0, 0, 0.10);
}
.tbl {
border-collapse: collapse;
width: 100%;
font-size: 14px;
background: #fff;
white-space: nowrap;
}
/* ヘッダー行 */
.tbl th {
background: var(--tbl-header-bg);
color: var(--tbl-header-txt);
padding: 10px 16px;
text-align: left;
font-weight: 600;
}
/* データ行 */
.tbl td {
padding: 10px 16px;
border-bottom: 1px solid var(--tbl-border);
color: var(--tbl-txt);
}
/* 最終行の下ボーダーを消す */
.tbl tbody tr:last-child td { border-bottom: none; }
/* ストライプ(偶数行) */
.tbl tbody tr:nth-child(even) td {
background: var(--tbl-stripe-bg);
}
/* ホバー */
.tbl tbody tr:hover td {
background: var(--tbl-hover-bg);
transition: background 0.1s;
}
/* 状態バッジ */
.tbl-status {
display: inline-block;
padding: 2px 10px;
border-radius: 9999px;
font-size: 12px;
font-weight: 600;
}
.tbl-status[data-status="在籍"] { background: #D1FAE5; color: #065F46; }
.tbl-status[data-status="休職"] { background: #FEF3C7; color: #92400E; }
.tbl-status[data-status="退職"] { background: #F3F4F6; color: #6B7280; }
@media (max-width: 600px) {
body { padding: 12px; }
.tbl th, .tbl td { padding: 8px 12px; }
}
// JSONファイルを読み込んでテーブルを描画する
fetch('./data/data.json')
.then(function (res) {
if (!res.ok) { throw new Error('HTTP ' + res.status); }
return res.json();
})
.then(function (data) { renderTable(data); })
.catch(function (err) {
console.error('データ読み込みエラー:', err);
var wrap = document.getElementById('js-wrap');
var msg = document.createElement('p');
msg.style.cssText = 'color:#9B1C1C; font-size:14px;';
msg.textContent = 'データを読み込めませんでした。';
wrap.appendChild(msg);
});
function renderTable(data) {
var theadRow = document.getElementById('js-thead-row');
var tbody = document.getElementById('js-tbody');
// ヘッダー行を生成する
data.columns.forEach(function (col) {
var th = document.createElement('th');
th.textContent = col.label;
if (col.width) { th.style.width = col.width; }
theadRow.appendChild(th);
});
// データ行を生成する
data.rows.forEach(function (row) {
var tr = document.createElement('tr');
data.columns.forEach(function (col) {
var td = document.createElement('td');
var val = row[col.key];
if (col.key === 'status') {
// 状態列はピル型バッジで表示する
var span = document.createElement('span');
span.className = 'tbl-status';
span.setAttribute('data-status', val != null ? val : '');
span.textContent = val != null ? val : '';
td.appendChild(span);
} else {
td.textContent = val != null ? val : '';
}
tr.appendChild(td);
});
tbody.appendChild(tr);
});
}
{
"columns": [
{ "key": "id", "label": "ID", "width": "56px" },
{ "key": "name", "label": "氏名", "width": "140px" },
{ "key": "department", "label": "部署", "width": "110px" },
{ "key": "role", "label": "役職", "width": "150px" },
{ "key": "status", "label": "状態", "width": "80px" }
],
"rows": [
{ "id": 1, "name": "田中 一郎", "department": "開発部", "role": "リードエンジニア", "status": "在籍" },
{ "id": 2, "name": "鈴木 花子", "department": "デザイン部", "role": "UIデザイナー", "status": "在籍" },
{ "id": 3, "name": "佐藤 次郎", "department": "開発部", "role": "バックエンドエンジニア", "status": "在籍" },
{ "id": 4, "name": "山田 三枝", "department": "営業部", "role": "セールスマネージャー", "status": "在籍" },
{ "id": 5, "name": "伊藤 健太", "department": "開発部", "role": "エンジニア", "status": "休職" },
{ "id": 6, "name": "渡辺 美咲", "department": "マーケティング部", "role": "コンテンツディレクター", "status": "在籍" },
{ "id": 7, "name": "中村 剛", "department": "インフラ部", "role": "インフラエンジニア", "status": "在籍" },
{ "id": 8, "name": "小林 奈々", "department": "人事部", "role": "HRマネージャー", "status": "退職" }
]
}
AI用プロンプト
このプロンプトをChatGPTやClaudeに渡すと、同様のテーブルコンポーネントをゼロから生成・カスタマイズできます。
※ このプロンプトを使ってもデモとまったく同じ動作にならない場合があります。AIの解釈や生成タイミングによって差が出ることをご了承ください。
💡 表示するカラムやデータの種類は要件に合わせて書き換えてください。ソート・検索・ページネーションなど追加機能を要件に追記することで拡張版も生成できます。
# テーブル(基本スタイル)作成依頼
## 概要
社員一覧などの表形式データを表示するテーブルを実装してください。
ヘッダーの色設定・ストライプ行・ホバーハイライト・状態バッジを備えたデザインです。
## 要件
- ヘッダー行に背景色(青系: #2B7FE8)と白文字を設定する
- 偶数行に薄い背景色を付けてストライプにする
- 行ホバーで行全体の背景色を変化させる
- 「状態」カラムをピル型バッジで表示する(在籍:緑、休職:黄、退職:グレー)
- テーブルデータは columns(列定義)と rows(行データ)のオブジェクトで定義し、JavaScriptのDOMで動的に生成する
- overflow-x: auto のラッパーで横スクロール対応にする
## 技術仕様
- HTML / CSS / バニラJavaScript で実装
- 外部ライブラリ:なし
- レスポンシブ対応:必要
## 動作詳細
columns 配列は { key, label, width } の形式で列を定義する。
rows 配列は各列の key に対応するプロパティを持つオブジェクトの配列とする。
JavaScript で thead の th と tbody の tr/td を createElement で生成する。
状態セルは span タグで囲み data-status 属性を付与し、CSSの属性セレクタで色分けする。
動的データの DOM 挿入は textContent を使い innerHTML に変数を直接渡さない。
## 出力形式
HTML・CSS・JavaScriptを分けて出力してください。
各ファイルは単独でコピー&ペーストして使えるよう記述してください。