webdevpuneet.com

File Tree Explorer with Filter and Tabs — Free HTML CSS JS

File Tree Explorer · Navigation · Plain HTML, CSS & JS · Live preview

CategoryNavigation

Copy & paste

Source Code

<div class="ide" id="ide" data-theme="dark">
  <div class="ide-bar">
    <span class="ide-dots" aria-hidden="true"><i></i><i></i><i></i></span>
    <span class="ide-title">acme-app</span>
    <button type="button" class="ide-theme" id="themeBtn" aria-label="Switch to light theme" title="Switch theme">
      <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z"/></svg>
    </button>
  </div>

  <div class="ide-body">
    <aside class="side">
      <div class="side-head">
        <span class="side-title">EXPLORER</span>
        <div class="side-actions">
          <button type="button" id="expandAll" aria-label="Expand all folders" title="Expand all"><svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m7 15 5 5 5-5"/><path d="m7 9 5-5 5 5"/></svg></button>
          <button type="button" id="collapseAll" aria-label="Collapse all folders" title="Collapse all"><svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m7 20 5-5 5 5"/><path d="m7 4 5 5 5-5"/></svg></button>
        </div>
      </div>
      <label class="filter">
        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/></svg>
        <input id="filter" type="search" placeholder="Filter files" aria-label="Filter files" autocomplete="off" spellcheck="false">
        <kbd>/</kbd>
      </label>
      <ul class="tree" id="tree" role="tree" aria-label="Project files"></ul>
      <p class="empty" id="empty" hidden>No files match that filter</p>
    </aside>

    <section class="editor" aria-label="File preview">
      <div class="tabs" id="tabs" role="group" aria-label="Open files"></div>
      <div class="crumbs" id="crumbs" aria-label="File path"></div>
      <div class="code" id="code" tabindex="0"></div>
      <div class="welcome" id="welcome">
        <strong>Pick a file to preview it</strong>
        <span><kbd>↑</kbd> <kbd>↓</kbd> move &nbsp; <kbd>→</kbd> <kbd>←</kbd> open or close &nbsp; <kbd>Enter</kbd> open &nbsp; <kbd>/</kbd> filter</span>
      </div>
    </section>
  </div>

  <div class="ide-status">
    <span id="branch">main</span>
    <span id="changes"></span>
    <span class="sp"></span>
    <span id="lang"></span>
    <span>UTF-8</span>
  </div>
</div>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

Real measured height animation (scrollHeight + max-height), with a two-frame close
Live filter that highlights matches, opens their folders and restores the old state when cleared
Git status badges (M, A, U, D) with coloured names, and a dot on folders that contain changes
Per-extension file badges and tinted folder icons that switch between closed and open
Click a file to open it in a tab with a breadcrumb, line numbers and syntax colours
Tiny built-in syntax highlighter for JS, CSS, HTML, JSON, Markdown and env files, no library
Indent guides drawn with one pseudo-element and a depth variable
Dark and light themes switched by one data attribute, all colours as CSS variables
Expand all and Collapse all buttons
Full keyboard support: arrows, Home, End, Enter, Space, type-ahead and / to filter
Correct ARIA tree roles with a roving tabindex, and reduced-motion support
Responsive: the editor drops under the tree on phones

About this UI Snippet

File Tree Explorer — Animated Folders, Live Filter, Git Status and a Code Preview in Vanilla JS

Screenshot of the File Tree Explorer snippet rendered live

A good file tree does more than open and close folders. In a code editor, a cloud drive or a docs sidebar, people scan it, filter it, move through it with the keyboard and expect to see what they picked. This snippet builds that whole experience in plain JavaScript: folders slide open with a measured height transition, a filter box narrows the tree and highlights matches, changed files carry git status badges, a click opens a file in a tab next to the tree, and every action works from the keyboard.

The height: auto problem, solved

CSS cannot transition to or from height: auto or max-height: none, because the browser has no fixed number to interpolate toward. Hardcoding a guess such as max-height: 500px either clips tall folders or leaves a visible gap under short ones. animateHeight() uses the measure-then-transition technique instead. When a folder opens, it reads the child list's scrollHeight (which reports the true content height even while max-height is clamped to 0) and writes that pixel value, so the transition has two real numbers. A transitionend listener then switches max-height to none, so a folder opened later inside it can still grow without being clipped.

Closing needs two frames

If max-height is none and you set it straight to 0px, the browser has no starting number and the change is instant. So closing first writes the current scrollHeight (visually a no-op), waits one animation frame for the browser to commit it as the starting point, and sets 0px on a second frame. The chevron rotation, the folder icon swap (closed to open) and the slide are all plain CSS transitions after that.

A filter that keeps the tree readable

Typing in the filter keeps every row whose name matches, plus every folder above a match, opens those folders without animation, and wraps the matching letters in a <mark>. If a folder's own name matches, its whole subtree stays visible, so searching for "src" shows the entire source folder. The folders' normal open or closed state is remembered, and clearing the filter restores it exactly. Enter opens the first matching file, ArrowDown moves into the results, and Escape clears the box.

Per-file icons, folder colours and git status

File badges come from a plain object, EXT, keyed by the lowercased extension, with an other fallback; add a key to support a new type. Special folders such as src, components and public get their own tint from FOLDER_TINT. A node with git: 'M', 'A', 'U' or 'D' shows a status letter and a matching name colour, and any folder that contains a changed file shows a small dot, the way an editor does. The status bar counts the changes.

Tabs, breadcrumb and a tiny syntax highlighter

Clicking a file opens it in a tab, shows its path as a breadcrumb and renders its lines with line numbers. A short hand-written tokenizer, with no library, colours keywords, strings, numbers, comments, CSS properties, JSON keys, HTML tags and Markdown headings. Tabs can be closed, and picking a tab opens every folder above that file in the tree so you can see where it lives.

Indent guides and two themes

Each open folder draws a thin vertical guide under its chevron with one ::before pseudo-element positioned from a --cd depth variable, so deep trees stay easy to read. Every colour is a CSS variable, and the moon button swaps a data-theme attribute between dark and light.

Keyboard and accessibility

The tree uses the standard pattern: role="tree" with role="treeitem" rows, aria-expanded, aria-selected and aria-level, and a roving tabindex so Tab enters and leaves the tree as a single stop. ArrowDown and ArrowUp move between visible rows, Home and End jump to the ends, ArrowRight opens a folder or steps into it, ArrowLeft closes it or steps up to its parent, Enter or Space opens, a letter jumps to the next name that starts with it, and / jumps to the filter. Animation is skipped for visitors who prefer reduced motion.

Step by step

How to Use

  1. 1
    Open and close foldersClick a folder row, or press Enter or Space on it. The chevron turns, the folder icon opens and the contents slide in with a measured max-height transition.
  2. 2
    Open a fileClick any file. It opens in a tab with a breadcrumb, line numbers and syntax colours. Open several and switch between them, or close one with the cross.
  3. 3
    Filter the treePress / or click the filter box and type. Matching rows are highlighted, their folders open, and everything else hides. Press Enter to open the first matching file and Escape to clear.
  4. 4
    Use only the keyboardArrow keys move, Right opens a folder or steps into it, Left closes it or steps to the parent, Home and End jump to the ends, and typing a letter jumps to the next name starting with it.
  5. 5
    Expand or collapse everythingUse the two buttons beside EXPLORER to open or close every folder at once. The filter is cleared first.
  6. 6
    Switch themeClick the moon button in the title bar to swap between the dark and light themes. Every colour is a CSS variable on the .ide element.
  7. 7
    Use your own filesEdit the DATA object in the JS panel. Give a file git: "M" for a status badge and lines: [...] for its preview, and add new extensions to the EXT table.

Real-world uses

Common Use Cases

In-browser code editor and IDE sidebars
Use it as the file navigation in a web-based editor or docs playground, the role a tree menu or checkbox tree plays for other nested lists.
File manager and cloud storage UIs
Pair it with a file manager UI or a file dropzone for a browse-and-upload flow over nested folders.
Documentation and API reference navigation
Organise pages by section and sub-section, with the filter box doing the job of a search for a long hierarchy.
Teaching the height: auto problem
A working reference for the classic "why won't my accordion animate" question, alongside a JSON tree viewer.
Admin dashboards with nested settings
Represent permission scopes or category trees where users drill down and keyboard operation is a real accessibility requirement.
Related: Hover Reveal List
See the Hover Reveal List for a related navigation pattern worth pairing with this one.

Got questions?

Frequently Asked Questions

display: none has no in-between state, so the folder would snap open and shut with no animation. The max-height plus scrollHeight approach gives the browser two real numbers to interpolate, which is the only way to get a true slide without a JavaScript frame loop.

After opening, max-height is none, and going from none to 0px has no starting number, so it would apply instantly. The code writes the current scrollHeight first, waits one frame for the browser to commit it as the start, and sets 0px on a second frame so the transition can run.

Each folder remembers whether you opened it (meta.open). While a filter is active, folders open to show matches without changing that value. Clearing the filter calls paintOpen() with the remembered state, so the tree returns exactly as you left it.

For status, set git on the node to "M", "A", "U" or "D". For a new extension, add a key to the EXT object, for example ts: { c: "#3178c6", fg: "#fff", t: "TS" }. Anything not listed falls back to EXT.other.

tokenize() walks each line character by character and groups it into keywords, strings, numbers, comments, properties and tags, then adds neighbouring tokens of the same kind together. It is one short function and good enough for a short preview; use a real highlighter for long files.

Yes. Keep each node's open state in component state (a Set of open ids works well), run the scrollHeight measurement in a layout effect after the node renders, and keep the filter query as state. The animation is CSS-driven, so there is no timer to clean up.

Yes. visibleItems() rebuilds the flat top-to-bottom list of rows that are actually shown on every key press, so ArrowDown and ArrowUp skip collapsed subtrees at any depth and ArrowLeft steps up one parent at a time.

Yes. While the File Tree Explorer snippet gives you one pattern to copy, the free Responsive Navbar Builder at webdevpuneet.com/navbar-builder/ designs a whole navigation bar: logo, links and dropdown menus, a mobile hamburger menu (dropdown panel, slide-in drawer or full screen) and a scroll effect (sticky, shrink, hide on scroll or transparent). It has six presets, a live preview that runs the real code, and exports HTML + CSS + vanilla JS, React, Tailwind, Vue 3 or Angular — or you can click Fork & Edit to keep editing it in My Code.