オートコンプリート Autocomplete

テキスト入力に応じて候補を表示し選択できるコンボボックス。

使用場面: 都市名検索・ユーザー名入力・住所入力など候補の絞り込みが必要な場合 採用例: Google Search, GitHub

ライブデモ

    ソースコード

    <div class="demo-autocomplete">
      <label class="demo-autocomplete-label" for="demo-ac-input">都道府県を検索</label>
      <div class="demo-autocomplete-wrap">
        <input class="demo-autocomplete-input" id="demo-ac-input" type="text" placeholder="入力して検索..." autocomplete="off" role="combobox" aria-expanded="false" aria-autocomplete="list" aria-controls="demo-ac-list" />
        <ul class="demo-autocomplete-list" id="demo-ac-list" role="listbox"></ul>
      </div>
    </div>
    .demo-autocomplete { max-width: 320px; min-height: 350px; }
    .demo-autocomplete-label { display: block; font-size: 13px; font-weight: 600; color: #333; margin-bottom: 6px; }
    .demo-autocomplete-wrap { position: relative; }
    .demo-autocomplete-input {
      width: 100%; padding: 10px 12px; border: 2px solid #d1d5db; border-radius: 8px;
      font-size: 14px; outline: none; transition: border-color 0.2s, box-shadow 0.2s;
      box-sizing: border-box;
    }
    .demo-autocomplete-input:focus {
      border-color: var(--ui-primary);
      box-shadow: 0 0 0 3px color-mix(in srgb, var(--ui-primary) 20%, transparent);
    }
    .demo-autocomplete-list {
      display: none; position: absolute; top: 100%; left: 0; right: 0;
      margin: 4px 0 0; padding: 4px; list-style: none;
      background: #fff; border: 1px solid #e5e7eb; border-radius: 8px;
      box-shadow: 0 4px 12px rgba(0,0,0,0.1); max-height: 180px; overflow-y: auto; z-index: 10;
    }
    .demo-autocomplete-list.open { display: block; }
    .demo-autocomplete-item {
      padding: 8px 12px; border-radius: 6px; font-size: 13px; color: #333; cursor: pointer;
      transition: background 0.15s;
    }
    .demo-autocomplete-item:hover,
    .demo-autocomplete-item.active {
      background: color-mix(in srgb, var(--ui-primary) 10%, transparent);
      color: var(--ui-primary);
    }
    .demo-autocomplete-match { font-weight: 700; color: var(--ui-primary); }
    .demo-autocomplete-empty { padding: 12px; text-align: center; font-size: 13px; color: #9ca3af; }
    (function(){
      var items = ['北海道','青森県','岩手県','宮城県','秋田県','山形県','福島県','茨城県','栃木県','群馬県','埼玉県','千葉県','東京都','神奈川県','新潟県','富山県','石川県','福井県','山梨県','長野県','岐阜県','静岡県','愛知県','三重県','滋賀県','京都府','大阪府','兵庫県','奈良県','和歌山県','鳥取県','島根県','岡山県','広島県','山口県','徳島県','香川県','愛媛県','高知県','福岡県','佐賀県','長崎県','熊本県','大分県','宮崎県','鹿児島県','沖縄県'];
      var input = document.querySelector('#demo-ac-input');
      var list = document.querySelector('#demo-ac-list');
      var activeIdx = -1;
      function render(query) {
        if (!query) { list.classList.remove('open'); input.setAttribute('aria-expanded','false'); return; }
        var filtered = items.filter(function(s){ return s.indexOf(query) !== -1; });
        if (filtered.length === 0) {
          list.innerHTML = '<li class="demo-autocomplete-empty">候補なし</li>';
        } else {
          list.innerHTML = filtered.map(function(s){
            var hl = s.replace(query, '<span class="demo-autocomplete-match">' + query + '</span>');
            return '<li class="demo-autocomplete-item" role="option">' + hl + '</li>';
          }).join('');
        }
        activeIdx = -1;
        list.classList.add('open');
        input.setAttribute('aria-expanded','true');
      }
      input.addEventListener('input', function(){ render(this.value); });
      list.addEventListener('click', function(e){
        var item = e.target.closest('.demo-autocomplete-item');
        if (item) { input.value = item.textContent; list.classList.remove('open'); input.setAttribute('aria-expanded','false'); }
      });
      input.addEventListener('keydown', function(e){
        var items = list.querySelectorAll('.demo-autocomplete-item');
        if (!items.length) return;
        if (e.key === 'ArrowDown') { e.preventDefault(); activeIdx = Math.min(activeIdx + 1, items.length - 1); }
        else if (e.key === 'ArrowUp') { e.preventDefault(); activeIdx = Math.max(activeIdx - 1, 0); }
        else if (e.key === 'Enter' && activeIdx >= 0) { e.preventDefault(); input.value = items[activeIdx].textContent; list.classList.remove('open'); return; }
        else if (e.key === 'Escape') { list.classList.remove('open'); return; }
        else return;
        items.forEach(function(el){ el.classList.remove('active'); });
        if (activeIdx >= 0) items[activeIdx].classList.add('active');
      });
      document.addEventListener('click', function(e){ if (!e.target.closest('.demo-autocomplete')) list.classList.remove('open'); });
    })();

    AIプロンプト

    Basic
    オートコンプリート付き入力欄をHTML/CSS/JSで作ってください。文字入力に応じて候補リストが表示されます。
    Custom
    以下の仕様でオートコンプリートを実装してください。
    - 入力に応じてリアルタイムで候補を絞り込み
    - マッチ部分をハイライト表示
    - プライマリカラー: #2563eb
    - キーボード操作(上下矢印で候補移動、Enterで選択)
    - 候補がない場合「該当なし」を表示
    - debounce処理(300ms)
    - 候補リストのスクロール対応
    Advanced
    WAI-ARIA Combobox パターン準拠のオートコンプリートを実装してください。
    - role="combobox", aria-expanded, aria-autocomplete, aria-activedescendant
    - role="listbox" / role="option" による候補リスト
    - 上下矢印・Enter・Escキーの完全なキーボード操作
    - スクリーンリーダーで選択中の候補を読み上げ
    - debounce + AbortController による非同期候補取得
    - バーチャルスクロール(大量候補時のパフォーマンス対策)
    - モバイルでのタッチ操作最適化