ちいつる

ナビ・リスト操作

ツリービュー

フォルダを開閉できるファイルツリー。クリックでフォルダが開き、キャレットが回転する。階層はインデントで表現し、キーボード(矢印キー)でも操作できる。

ENGLISH

Tree View

  • JS
173ナビ・リスト操作 の一覧 →

プレビュー

クリック

操作クリック/タップで動きます。

実装メモ

WAI-ARIA の tree パターンに倣い、フォルダ(tv-node)に aria-expanded、行に role=treeitem を付けています。フォーカスは常にツリー内で1つの行だけ tabindex=0 にする「ローミング tabindex」方式。矢印キーで上下移動、→で展開/子へ、←で折りたたみ/親へ、Enter/Space で開閉できます。開閉アニメは grid-template-rows: 0fr→1fr。グリッドアイテムは .tv-group の1つだけにし(複数だと暗黙行が潰れず内容がはみ出す)、折りたたみ中は visibility:hidden で操作対象からも外しています。

コード(コピーして使えます)

<ul class="tv" role="tree" aria-label="ファイル">
  <li class="tv-node" role="treeitem" aria-expanded="true">
    <div class="tv-row" tabindex="0" style="--depth:0">
      <svg class="tv-caret" width="12" height="12" viewBox="0 0 12 12" fill="none"><polyline points="4,2 8,6 4,10" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg>
      <svg class="tv-ic tv-folder" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6a1 1 0 0 1 1-1h5l2 2h8a1 1 0 0 1 1 1v9a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1z"/></svg>
      <span class="tv-name">src</span>
    </div>
    <div class="tv-children"><ul class="tv-group" role="group">
      <li class="tv-node" role="treeitem" aria-expanded="false">
        <div class="tv-row" tabindex="-1" style="--depth:1">
          <svg class="tv-caret" width="12" height="12" viewBox="0 0 12 12" fill="none"><polyline points="4,2 8,6 4,10" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg>
          <svg class="tv-ic tv-folder" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6a1 1 0 0 1 1-1h5l2 2h8a1 1 0 0 1 1 1v9a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1z"/></svg>
          <span class="tv-name">components</span>
        </div>
        <div class="tv-children"><ul class="tv-group" role="group">
          <li class="tv-leaf" role="treeitem">
            <div class="tv-row" tabindex="-1" style="--depth:2">
              <span class="tv-caret tv-caret--empty"></span>
              <svg class="tv-ic" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M6 3h8l4 4v14a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1z"/><polyline points="14,3 14,7 18,7"/></svg>
              <span class="tv-name">Button.tsx</span>
            </div>
          </li>
          <li class="tv-leaf" role="treeitem">
            <div class="tv-row" tabindex="-1" style="--depth:2">
              <span class="tv-caret tv-caret--empty"></span>
              <svg class="tv-ic" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M6 3h8l4 4v14a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1z"/><polyline points="14,3 14,7 18,7"/></svg>
              <span class="tv-name">Card.tsx</span>
            </div>
          </li>
        </ul></div>
      </li>
      <li class="tv-leaf" role="treeitem">
        <div class="tv-row" tabindex="-1" style="--depth:1">
          <span class="tv-caret tv-caret--empty"></span>
          <svg class="tv-ic" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M6 3h8l4 4v14a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1z"/><polyline points="14,3 14,7 18,7"/></svg>
          <span class="tv-name">index.ts</span>
        </div>
      </li>
    </ul></div>
  </li>
  <li class="tv-leaf" role="treeitem">
    <div class="tv-row" tabindex="-1" style="--depth:0">
      <span class="tv-caret tv-caret--empty"></span>
      <svg class="tv-ic" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M6 3h8l4 4v14a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1z"/><polyline points="14,3 14,7 18,7"/></svg>
      <span class="tv-name">package.json</span>
    </div>
  </li>
</ul>

タグ

関連パーツ