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.