Web Componentsで実装する手書き風リストボックス:wired-listboxの導入と活用

Web Components技術に基づいたライブラリ「wired-elements」は、SVGを用いた独特なスケッチ調のビジュアルをWebページに提供します。中でもwired-listboxコンポーネントは、標準的なセレクトボックスやリストコントロールに視覚的なアクセントを加え、ユーザー体験を向上させるための強力なツールです。本記事では、このコンポーネントをプロジェクトに統合し、スタイルのカスタマイズやイベント駆動のインタラクションを実装する具体的な手順を解説します。

環境構築と導入

プロジェクトへの導入は、npmパッケージマネージャーを利用する方法と、CDN経由でモジュールを読み込む方法の2通りがあります。Web Componentsの仕様に準拠しているため、ReactやVueなどのフレームワークを使用している環境でも、DOM操作を行うコンポーネントとしてシームレスに統合可能です。

npmを使用する場合のインストールコマンドとインポート文は以下の通りです。

npm install wired-elements
import { WiredListbox } from 'wired-elements';

また、手軽に試す場合はHTML内で以下のスクリプトタグを使用してCDNから読み込みます。

<script type="module" src="https://unpkg.com/wired-elements/lib/wired-listbox.js?module"></script>
<script type="module" src="https://unpkg.com/wired-elements/lib/wired-item.js?module"></script>

基本的な実装とレイアウト

wired-listboxの基本的な構造は、親要素となるwired-listboxタグの中に、選択肢となるwired-itemタグを配置する形をとります。デフォルトでは垂直方向のリストが描画されますが、horizontal属性を付与することで、水平方向に展開されるUIモードに切り替えることが可能です。

以下に、システム設定メニューを想定した垂直レイアウトの実装例を示します。

<div class="control-group">
  <label>システムモード選択:</label>
  <wired-listbox id="mode-selector" selected="standard">
    <wired-item value="eco">エコモード (Eco)</wired-item>
    <wired-item value="standard">標準モード (Standard)</wired-item>
    <wired-item value="performance">ハイパフォーマンス (High)</wired-item>
  </wired-listbox>
</div>

スタイルのカスタマイズ

コンポーネントのデザイン調整には、CSS Custom Properties(CSS変数)を利用します。wired-listboxは、選択中の項目(wired-item)の背景色やテキスト色を変数経由で上書きすることをサポートしています。これにより、ダークモードやブランドカラーへの適応が容易になります。

例えば、選択項目の背景を青系の色にし、文字色を白くするスタイル定義は以下のようになります。

.custom-theme {
  /* 選択されたアイテムの背景色を変更 */
  --wired-item-selected-bg: #2962FF;
  /* 選択されたアイテムの文字色を変更 */
  --wired-item-selected-color: #ffffff;
}

イベントハンドリングと動的な制御

ユーザーがリスト内の項目を選択すると、wired-listboxselectedというカスタムイベントを発火します。開発者はこのイベントをリッスンし、event.detail.selectedプロパティを通じて選択された値を取得できます。この仕組みを利用して、選択内容に応じたUIの動的変更やデータの送信処理を実装します。

const listBoxElement = document.querySelector('#mode-selector');
const statusDisplay = document.querySelector('#current-status');

if (listBoxElement) {
  listBoxElement.addEventListener('selected', (evt) => {
    const selectedValue = evt.detail.selected;
    // 選択値に基づいて画面を更新
    statusDisplay.textContent = `現在の設定: ${selectedValue}`;
    
    // ロジックの分岐例
    switch(selectedValue) {
      case 'eco':
        console.log('省電力設定を適用しました');
        break;
      case 'performance':
        console.log('最大出力設定を適用しました');
        break;
      default:
        console.log('標準設定を適用しました');
    }
  });
}

実装サンプル

以下に、垂直および水平レイアウト、カスタムスタイル、JavaScriptによるイベント処理を統合した完全なHTMLコードのサンプルを示します。このコードをブラウザで開くことで、手書き風のインタラクティブなリストボックスの動作を確認できます。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>Wired Listbox Demo</title>
  <script type="module" src="https://unpkg.com/wired-elements/lib/wired-listbox.js?module"></script>
  <script type="module" src="https://unpkg.com/wired-elements/lib/wired-item.js?module"></script>
  <style>
    body {
      padding: 40px;
      font-family: 'Helvetica Neue', Arial, sans-serif;
      background-color: #f5f5f5;
    }
    .container {
      background: white;
      padding: 20px;
      border-radius: 8px;
      box-shadow: 0 2px 10px rgba(0,0,0,0.1);
      margin-bottom: 30px;
    }
    h3 {
      margin-top: 0;
      color: #333;
    }
    wired-listbox {
      margin-top: 15px;
      width: 100%;
      max-width: 300px;
    }
    /* カスタムテーマの適用 */
    .theme-dark {
      --wired-item-selected-bg: #212121;
      --wired-item-selected-color: #76FF03;
    }
    #log-output {
      margin-top: 10px;
      font-weight: bold;
      color: #444;
    }
  </style>
</head>
<body>

  <div class="container">
    <h3>アカウント権限(垂直レイアウト)</h3>
    <wired-listbox id="role-select" selected="guest">
      <wired-item value="admin">管理者 (Admin)</wired-item>
      <wired-item value="user">一般ユーザー (User)</wired-item>
      <wired-item value="guest">ゲスト (Guest)</wired-item>
    </wired-listbox>
    <div id="log-output">選択中の権限: guest</div>
  </div>

  <div class="container">
    <h3>データ密度(水平レイアウト・カスタムスタイル)</h3>
    <wired-listbox id="density-select" horizontal class="theme-dark" selected="high">
      <wired-item value="low">低</wired-item>
      <wired-item value="medium">中</wired-item>
      <wired-item value="high">高</wired-item>
    </wired-listbox>
  </div>

  <script>
    // 垂直リストのイベント監視
    const roleSelector = document.getElementById('role-select');
    const roleLog = document.getElementById('log-output');
    
    roleSelector.addEventListener('selected', (e) => {
      roleLog.textContent = `選択中の権限: ${e.detail.selected}`;
      // 実際のアプリケーションではここでAPIリクエスト等を行う
    });

    // 水平リストのイベント監視
    const densitySelector = document.getElementById('density-select');
    densitySelector.addEventListener('selected', (e) => {
      console.log(`表示密度が ${e.detail.selected} に変更されました`);
    });
  </script>
</body>
</html>

6月28日 21:51 投稿