List 1 — リスト 1 — 基本スタイル

データ表示 初級

このコンポーネントについて

リストはテーブルよりシンプルな構造でデータを一覧表示するUIです。 社員名簿・メンバー紹介・連絡先リストなど、1〜2カラム程度の情報をコンパクトに見せる場面に向いています。

このページでは、イニシャルから自動生成したアバター・氏名・役職・部署・状態バッジを組み合わせたメンバーリストの基本スタイルを紹介します。 JavaScriptでJSONデータから動的に描画するため、データの差し替えが容易です。

  • イニシャルアバター — 氏名の先頭1文字をアバターとして表示。インデックスで5色を自動サイクルする
  • 状態バッジdata-status 属性とCSSの属性セレクタで在籍(緑)・休職(黄)・退職(グレー)を色分け
  • ホバーハイライト — マウスオーバーでリストアイテム全体を明るい背景色にし、現在の行を示す
  • 動的レンダリングfetch でJSONを取得し、JavaScriptのDOMで各アイテムを生成。データ差し替えが容易
  • 横スクロール不要 — テーブルと異なり縦方向のレイアウトのため、スマホ幅でも崩れない

実装のポイント・注意点

アバターの背景色は data-color 属性とCSSの属性セレクタで切り替えています。 JavaScriptで直接 style.background を書くよりも、CSSに色管理を集約できるためカスタマイズが容易です。 色を変えたい場合は :root のカラー変数(--dl1-av1--dl1-av5)を書き換えるだけです。

状態バッジは data-status="在籍" のような属性セレクタで色を定義しています。 クラス名に日本語を使わず属性で管理することで、ツールによる誤動作を防いでいます。

動的なDOM挿入は textContent のみを使っています。 innerHTML に外部データを直接渡すとXSS(クロスサイトスクリプティング)のリスクが生まれるため、テキストを表示するときは必ず textContent を使いましょう。

HTML・CSS・バニラJavaScriptのみで実装しており、フレームワーク不要でコピペすぐに動きます。

デモ

    サンプルソース

    4つのファイルを同じフォルダに保存し、簡易サーバーで index.html を開くと動作確認できます。
    ファイル構成:index.html / style.css / script.js / data/data.jsondata フォルダを作って中に配置)
    保存時の文字コードは 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>
    
    <ul class="lst" id="js-list"></ul>
    
    <script src="./script.js"></script>
    </body>
    </html>
    /* リスト(基本スタイル)— style.css */
    :root {
      --av1: #2B7FE8; /* アバター色1(青) */
      --av2: #10B981; /* アバター色2(緑) */
      --av3: #F59E0B; /* アバター色3(黄) */
      --av4: #8B5CF6; /* アバター色4(紫) */
      --av5: #EF4444; /* アバター色5(赤) */
    }
    
    *, *::before, *::after { box-sizing: border-box; }
    
    body {
      font-family: sans-serif;
      padding: 24px;
      background: #f8f9fa;
    }
    
    /* リスト本体 */
    .lst {
      list-style: none;
      margin: 0;
      padding: 0;
      background: #fff;
      border-radius: 8px;
      box-shadow: 0 1px 6px rgba(0, 0, 0, 0.10);
      overflow: hidden;
      max-width: 560px;
    }
    
    /* リストアイテム */
    .lst-item {
      display: flex;
      align-items: center;
      gap: 12px;
      padding: 12px 16px;
      border-bottom: 1px solid #E5E9F2;
      transition: background 0.1s;
    }
    
    .lst-item:last-child { border-bottom: none; }
    .lst-item:hover { background: #F4F7FF; }
    
    /* アバター(イニシャル円形) */
    .lst-avatar {
      flex-shrink: 0;
      width: 40px;
      height: 40px;
      border-radius: 50%;
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: 16px;
      font-weight: 700;
      color: #fff;
    }
    
    /* data-color 属性で背景色を切り替える */
    .lst-avatar[data-color="1"] { background: var(--av1); }
    .lst-avatar[data-color="2"] { background: var(--av2); }
    .lst-avatar[data-color="3"] { background: var(--av3); }
    .lst-avatar[data-color="4"] { background: var(--av4); }
    .lst-avatar[data-color="5"] { background: var(--av5); }
    
    /* 本文エリア */
    .lst-body {
      flex: 1;
      min-width: 0;
    }
    
    .lst-name {
      font-size: 14px;
      font-weight: 700;
      color: #1A2332;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    
    .lst-meta {
      font-size: 12px;
      color: #6B7280;
      margin-top: 2px;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    
    /* 状態バッジ */
    .lst-status {
      flex-shrink: 0;
      display: inline-block;
      padding: 2px 10px;
      border-radius: 9999px;
      font-size: 12px;
      font-weight: 600;
    }
    
    /* data-status 属性セレクタで色分けする */
    .lst-status[data-status="在籍"] { background: #D1FAE5; color: #065F46; }
    .lst-status[data-status="休職"] { background: #FEF3C7; color: #92400E; }
    .lst-status[data-status="退職"] { background: #F3F4F6; color: #6B7280; }
    
    @media (max-width: 480px) {
      body { padding: 12px; }
      .lst { max-width: 100%; }
      .lst-item { gap: 10px; padding: 10px 12px; }
      .lst-avatar { width: 36px; height: 36px; font-size: 14px; }
    }
    // アバター色のサイクル数(:root のカラー変数に対応)
    var AVATAR_COLORS = ['1', '2', '3', '4', '5'];
    
    // JSONを読み込んでリストを描画する
    fetch('./data/data.json')
      .then(function (res) {
        if (!res.ok) { throw new Error('HTTP ' + res.status); }
        return res.json();
      })
      .then(function (data) { renderList(data.rows); })
      .catch(function (err) {
        console.error('データ読み込みエラー:', err);
        var ul = document.getElementById('js-list');
        var msg = document.createElement('p');
        msg.style.cssText = 'color:#9B1C1C; font-size:14px;';
        msg.textContent = 'データを読み込めませんでした。';
        ul.parentNode.appendChild(msg);
      });
    
    // リストを描画する
    function renderList(rows) {
      var ul = document.getElementById('js-list');
      ul.innerHTML = '';
    
      rows.forEach(function (row, index) {
        var li = document.createElement('li');
        li.className = 'lst-item';
    
        // アバター(氏名の先頭1文字)
        var avatar = document.createElement('div');
        avatar.className = 'lst-avatar';
        avatar.setAttribute('data-color', AVATAR_COLORS[index % AVATAR_COLORS.length]);
        avatar.textContent = row.name ? row.name.charAt(0) : '?';
    
        // 本文エリア
        var body = document.createElement('div');
        body.className = 'lst-body';
    
        var nameEl = document.createElement('div');
        nameEl.className = 'lst-name';
        nameEl.textContent = row.name || '';
    
        var meta = document.createElement('div');
        meta.className = 'lst-meta';
        meta.textContent = (row.role || '') + ' · ' + (row.department || '');
    
        body.appendChild(nameEl);
        body.appendChild(meta);
    
        // 状態バッジ
        var status = document.createElement('span');
        status.className = 'lst-status';
        status.setAttribute('data-status', row.status || '');
        status.textContent = row.status || '';
    
        li.appendChild(avatar);
        li.appendChild(body);
        li.appendChild(status);
        ul.appendChild(li);
      });
    }
    
    {
      "rows": [
        { "name": "田中 一郎", "department": "開発部",           "role": "リードエンジニア",       "status": "在籍" },
        { "name": "鈴木 花子", "department": "デザイン部",       "role": "UIデザイナー",           "status": "在籍" },
        { "name": "佐藤 次郎", "department": "開発部",           "role": "バックエンドエンジニア", "status": "在籍" },
        { "name": "山田 三枝", "department": "営業部",           "role": "セールスマネージャー",   "status": "在籍" },
        { "name": "伊藤 健太", "department": "開発部",           "role": "エンジニア",             "status": "休職" },
        { "name": "渡辺 美咲", "department": "マーケティング部", "role": "コンテンツディレクター", "status": "在籍" },
        { "name": "中村 剛",   "department": "インフラ部",       "role": "インフラエンジニア",     "status": "在籍" },
        { "name": "小林 奈々", "department": "人事部",           "role": "HRマネージャー",         "status": "退職" }
      ]
    }

    AI用プロンプト

    このプロンプトをChatGPTやClaudeに渡すと、同様のリストコンポーネントをゼロから生成・カスタマイズできます。

    ※ このプロンプトを使ってもデモとまったく同じ動作にならない場合があります。AIの解釈や生成タイミングによって差が出ることをご了承ください。

    💡 jQuery・Vue・React など特定のライブラリで実装したい場合は、プロンプトの末尾に「〇〇を使って実装してください」と追記してください。

    # リスト(基本スタイル)作成依頼
    
    ## 概要
    メンバー一覧などのデータをリスト形式で表示するUIを実装してください。
    イニシャルアバター・氏名・役職・部署・状態バッジを横並びに並べたシンプルなリストです。
    
    ## 要件
    - 氏名の先頭1文字をアバター(円形)として表示する
    - アバターの背景色はインデックスで5色をサイクルする
    - 各アイテムに氏名(太字)・役職と部署(サブテキスト)・状態バッジを表示する
    - 状態バッジは data-status 属性とCSSの属性セレクタで在籍(緑)・休職(黄)・退職(グレー)を色分けする
    - 行ホバーで背景色を変化させる(transition: background 0.1s)
    - リストデータは rows 配列からJavaScriptのDOMで動的に生成する
    
    ## 技術仕様
    - HTML / CSS / バニラJavaScript で実装
    - 外部ライブラリ:なし
    - レスポンシブ対応:必要
    
    ## 動作詳細
    rows 配列は { name, department, role, status } のプロパティを持つオブジェクトの配列とする。
    renderList(rows) 関数が ul 要素に li を createElement + appendChild で追加する。
    アバター文字は name.charAt(0)、背景色は (index % 5) + 1 で決定し data-color 属性で切り替える。
    状態バッジは span タグに data-status 属性を付与し、CSSの属性セレクタで色分けする。
    動的データのDOM挿入は textContent を使い innerHTML に変数を直接渡さない。
    
    ## 出力形式
    HTML・CSS・JavaScriptを分けて出力してください。
    各ファイルは単独でコピー&ペーストして使えるよう記述してください。