This question was asked in Postman’s SDE2 frontend machine-coding interview to my friend and the CTC offered was 50 LPA base. He had competing offer from Rippling, where the base was 56 LPA.
Two other system design questions where also asked
Problem statement
Create a file explorer like Google drive in React that allows users to browse an arbitrarily nested folder/file hierarchy. Your task is to:
- Define a suitable data model (in JSON) to represent folders and files, where each folder can contain children (folders or files) and files are leaf nodes.
- Render the contents of the “current” folder as a grid of tiles. Folders should be distinguishable from files and should be clickable to drill down into that folder. Files need only be displayed (no further action).
- Maintain a breadcrumb trail at the top that reflects the path from the root down to the currently open folder. Clicking:
- “Home” resets the view back to top-level items.
- Any intermediate breadcrumb folder jumps back up to that level.
- Support unlimited nesting—whatever depth the JSON provides, navigating should remain correct.
Focus on clean React code, state management for the current path, and clear UX for entering/leaving folders via both tile clicks and breadcrumb clicks. Do not include any fixed styling or CSS details; you may choose any reasonable styling/layout approach you prefer.

Building a File Explorer like Google drive in React
The most critical part of this question is how your are defining your state or managing it. If you follow the nested structure:
const fileExplorerState = {
items: {
id: "root",
name: "Root",
type: "folder",
children: [{
{
id: "folder1",
name: "Documents 1",
type: "folder",
children: [
{
id: "file1",
name: "file1.pdf",
type: "file",
metadata: {
size: 1024,
lastModified: new Date(),
},
},
{
id: "file2",
name: "file2.pdf",
type: "file",
metadata: {
size: 1024,
lastModified: new Date(),
},
},
]
},
{
id: "folder2",
name: "Documents 2",
type: "folder",
}
}]
}
}
Having this nested structure will be complex in handling and in the iteration as well, if you have to search a file or folder then you will have to do the DFS as this is a tree like structure with N leaves.
Adding and removing items from the N-ary tree will take O(N) time.
function findWithId(tree, targetId) {
// Check if the current item matches the target ID
if (tree.id === targetId) {
return tree;
}
// If the current branch has children, recursively search again
if (tree.children && tree.children.length > 0) {
for (const child of tree.children) {
const result = findWithId(child, targetId);
if (result) {
return result;
}
}
}
// Return null if not found
return null;
}
The optimum approach is to have the normalized state, where we can store all the entities at the root level with each having its parent id present.
const fileExplorerState = {
items: {
root: {
id: "root",
name: "Root",
type: "folder",
parentId: null,
},
folder1: {
id: "folder1",
name: "Documents 1",
type: "folder",
parentId: "root",
},
folder2: {
id: "folder2",
name: "Documents 2",
type: "folder",
parentId: "root",
},
file1: {
id: "file1",
name: "file1.pdf",
type: "file",
parentId: "folder1",
metadata: {
size: 1024,
lastModified: new Date(),
},
},
file2: {
id: "file2",
name: "file2.pdf",
type: "file",
parentId: "folder1",
metadata: {
size: 1024,
lastModified: new Date(),
},
},
folder3: {
id: "folder3",
name: "Projects",
type: "folder",
parentId: "folder1",
},
file3: {
id: "file1",
name: "file3.pdf",
type: "file",
parentId: "folder2",
metadata: {
size: 1024,
lastModified: new Date(),
},
},
},
activeItem: null,
};
Following the byId and allIds structure helps to adding, removing, moving node in the O(1) time as we have just add or access the items byId.
Here the root items parent is null and the active item’s is also null which will help us to render the root item first.
We can have the helper function, that will get all the children of the active item and the breadcrumb path.
// Get children of a folder
const getChildren = (state, parentId) => {
return Object.values(state.items).filter(
(item) => item.parentId === parentId
);
};
// Get path to an item
const getItemPath = (state, itemId) => {
// root path the at the beginning always
const basePath = { name: "Home", id: null };
const path = [];
let currentId = itemId;
while (currentId) {
const item = state.items[currentId];
if (!item) {
break;
}
path.unshift({ name: item.name, id: item.id });
currentId = item.parentId;
}
return [basePath, ...path];
};
When you click on any folder or breadcrumb item, just update the active item in the state with the id of that folder and everything will render properly.
With this we can create the file explorer in React.
import { useMemo, useState } from "react";
import "./styles.css";
const fileExplorerState = {
items: {
root: {
id: "root",
name: "Root",
type: "folder",
parentId: null,
},
folder1: {
id: "folder1",
name: "Documents 1",
type: "folder",
parentId: "root",
},
folder2: {
id: "folder2",
name: "Documents 2",
type: "folder",
parentId: "root",
},
file1: {
id: "file1",
name: "file1.pdf",
type: "file",
parentId: "folder1",
metadata: {
size: 1024,
lastModified: new Date(),
},
},
file2: {
id: "file2",
name: "file2.pdf",
type: "file",
parentId: "folder1",
metadata: {
size: 1024,
lastModified: new Date(),
},
},
folder3: {
id: "folder3",
name: "Projects",
type: "folder",
parentId: "folder1",
},
file3: {
id: "file1",
name: "file3.pdf",
type: "file",
parentId: "folder2",
metadata: {
size: 1024,
lastModified: new Date(),
},
},
},
expandedFolders: new Set(["root", "folder1"]),
selectedItems: new Set(["file1"]),
activeItem: null,
};
export default function App() {
const [state, setState] = useState(fileExplorerState);
const setActiveItem = (itemId) => {
setState((prevState) => {
return {
...prevState,
activeItem: itemId,
};
});
};
// Get children of a folder
const getChildren = (state, parentId) => {
return Object.values(state.items).filter(
(item) => item.parentId === parentId
);
};
// Get path to an item
const getItemPath = (state, itemId) => {
const basePath = { name: "Home", id: null };
const path = [];
let currentId = itemId;
while (currentId) {
const item = state.items[currentId];
if (!item) {
break;
}
path.unshift({ name: item.name, id: item.id });
currentId = item.parentId;
}
return [basePath, ...path];
};
const pathArray = useMemo(
() => getItemPath(state, state.activeItem),
[state]
);
const childrensToRender = useMemo(
() => getChildren(state, state.activeItem),
[state]
);
return (
<div className="App">
<div className="header">
{pathArray.map(({ name, id }, i) => (
<>
<span
className={i !== pathArray.length - 1 && "breadcrumb"}
onClick={() => setActiveItem(id)}
>
{name}
</span>
{i !== pathArray.length - 1 && <span> > </span>}
</>
))}
</div>
<div className="box-wrapper">
{childrensToRender.map((e) => (
<div
onClick={() => {
if (e.type === "folder") {
setActiveItem(e.id);
}
}}
key={e.id}
className={`box ${e.type}`}
>
{e.name}
</div>
))}
</div>
</div>
);
}
//style.css
.App {
font-family: sans-serif;
text-align: center;
}
.folder {
background-color: green;
cursor: pointer;
}
.file {
background-color: gray;
}
.box {
width: 100px;
height: 100px;
display: flex;
align-items: center;
justify-content: center;
}
.box-wrapper {
display: flex;
align-items: center;
gap: 4px;
}
.header {
background-color: red;
padding: 10px;
text-align: left;
margin-bottom: 10px;
}
.breadcrumb {
cursor: pointer;
color: blue;
}

Benefits of using the normalized state
- Move the items (files or folders) by updating their parent id.
- Add a new item, folder or file with ease by just making a new entry with the parent id.
If you are asked to create the sidebar that list files and folder (create the file explorer tree), you can do it with ease by maintaining two new states expandedFolders, selectedItems for bulk updates.
const fileExplorerState = {
items: { ... },
expandedFolders: new Set(["root", "folder1"]),
selectedItems: new Set(["file1"]),
activeItem: null,
};
In the next article we will see how to create the file-explorer tree.