Build a File Tree / Folder Navigation Component

File-tree navigation appears in IDEs (VS Code), file managers, document apps (Google Drive), and CMSes. The interview tests whether you understand recursive rendering, lazy loading, virtualization, and keyboard navigation patterns.

Functional requirements

  • Render tree of folders and files
  • Click folder → expand/collapse
  • Click file → select / open
  • Lazy-load children when expanding (for large trees)
  • Keyboard navigation
  • Drag-drop to reorganize
  • Context menu (rename, delete)

Data structure

Tree nodes:

{
  id: string,
  name: string,
  type: 'folder' | 'file',
  children?: Node[],
  isLoaded?: boolean // for lazy loading
}

Recursive rendering

Each node renders itself and (if folder + expanded) its children:

function TreeNode({ node, depth }) {
  const [expanded, setExpanded] = useState(false);
  return (
    <>
      <div onClick={() => setExpanded(!expanded)} style={{ paddingLeft: depth * 16 }}>
        {node.name}
      </div>
      {expanded && node.children?.map(c => (
        <TreeNode key={c.id} node={c} depth={depth + 1} />
      ))}
    </>
  );
}

Lazy loading

For trees with thousands of nodes, don’t load everything:

  • Folder shows expand chevron
  • Click expand → fetch children if not yet loaded
  • Show loading indicator
  • Cache loaded children

Virtualization

For long trees (10K+ nodes visible), virtualize:

  • react-arborist: built specifically for trees
  • react-window with manual flattening

Render only visible rows. Calculate item heights from depth + collapsed/expanded state.

Keyboard navigation

WAI-ARIA tree pattern:

  • Down: next visible item
  • Up: previous visible item
  • Right: expand if collapsed; first child if expanded
  • Left: collapse if expanded; parent if collapsed
  • Home: first item
  • End: last visible item
  • Enter: select / open

Selection

  • Single selection: click highlights
  • Multi-selection: Cmd+click toggles individual; Shift+click selects range
  • Indicate selected with background color

Drag and drop

Drag a file/folder onto another folder to move:

  • Use HTML5 DnD or a library (dnd-kit)
  • Drop indicator shows where the item will land
  • Validate: do not drop folder into its own descendant
  • Auto-expand folders on hover during drag

Context menu

Right-click on item → menu with actions (rename, delete, copy, paste).

  • Position menu near cursor; flip if near viewport edge
  • Keyboard accessible (context-menu key on Windows/Linux)
  • Close on click outside or Escape

Performance

  • Memoize node components
  • Use stable IDs for keys
  • Avoid re-rendering entire tree on small changes

Common mistakes

  • Re-rendering all nodes on every state change
  • Loading entire tree upfront
  • No keyboard support
  • Drag-drop allows invalid moves (folder into descendant)
  • Selection state not visually clear

ARIA

  • Wrapper: role="tree"
  • Each node: role="treeitem"
  • aria-expanded for folders
  • aria-selected for selected items
  • aria-level for depth
  • aria-setsize and aria-posinset for siblings count

Frequently Asked Questions

Should I use react-arborist or react-window?

react-arborist is built for trees specifically. react-window with manual flattening is more flexible but more code.

How do I handle a folder being renamed?

Inline edit: double-click name → input field. Save on blur or Enter. Update tree state and persist.

What about file icons?

Map file extension to icon. Library: vscode-icons, file-icons-js. Or build a small icon set.

Scroll to Top