Expandable object tree view
React, Components, Object, State, Recursion · Nov 16, 2020

Renders a tree view of a JSON object or array with collapsible content.
- Use the value of the
toggled
prop to determine the initial state of the content (collapsed/expanded). - Use the
useState()
hook to create theisToggled
state variable and give it the value of thetoggled
prop initially. - Render a
<span>
element and bind itsonClick
event to alter the component'sisToggled
state. - Determine the appearance of the component, based on
isParentToggled
,isToggled
,name
and checking forArray.isArray()
ondata
. - For each child in
data
, determine if it is an object or array and recursively render a sub-tree or a text element with the appropriate style.
.tree-element {
margin: 0 0 0 4px;
position: relative;
}
.tree-element.is-child {
margin-left: 16px;
}
div.tree-element::before {
content: '';
position: absolute;
top: 24px;
left: 1px;
height: calc(100% - 48px);
border-left: 1px solid gray;
}
p.tree-element {
margin-left: 16px;
}
.toggler {
position: absolute;
top: 10px;
left: 0px;
width: 0;
height: 0;
border-top: 4px solid transparent;
border-bottom: 4px solid transparent;
border-left: 5px solid gray;
cursor: pointer;
}
.toggler.closed {
transform: rotate(90deg);
}
.collapsed {
display: none;
}
const TreeView = ({
data,
toggled = true,
name = null,
isLast = true,
isChildElement = false,
isParentToggled = true
}) => {
const [isToggled, setIsToggled] = React.useState(toggled);
const isDataArray = Array.isArray(data);
return (
<div
className={`tree-element ${isParentToggled && 'collapsed'} ${
isChildElement && 'is-child'
}`}
>
<span
className={isToggled ? 'toggler' : 'toggler closed'}
onClick={() => setIsToggled(!isToggled)}
/>
{name ? <strong> {name}: </strong> : <span> </span>}
{isDataArray ? '[' : '{'}
{!isToggled && '...'}
{Object.keys(data).map((v, i, a) =>
typeof data[v] === 'object' ? (
<TreeView
key={`${name}-${v}-${i}`}
data={data[v]}
isLast={i === a.length - 1}
name={isDataArray ? null : v}
isChildElement
isParentToggled={isParentToggled && isToggled}
/>
) : (
<p
key={`${name}-${v}-${i}`}
className={isToggled ? 'tree-element' : 'tree-element collapsed'}
>
{isDataArray ? '' : <strong>{v}: </strong>}
{data[v]}
{i === a.length - 1 ? '' : ','}
</p>
)
)}
{isDataArray ? ']' : '}'}
{!isLast ? ',' : ''}
</div>
);
};
const data = {
lorem: {
ipsum: 'dolor sit',
amet: {
consectetur: 'adipiscing',
elit: [
'duis',
'vitae',
{
semper: 'orci'
},
{
est: 'sed ornare'
},
'etiam',
['laoreet', 'tincidunt'],
['vestibulum', 'ante']
]
},
ipsum: 'primis'
}
};
ReactDOM.createRoot(document.getElementById('root')).render(
<TreeView data={data} name="data" />
);
Written by Angelos Chalaris
I'm Angelos Chalaris, a JavaScript software engineer, based in Athens, Greece. The best snippets from my coding adventures are published here to help others learn to code.
If you want to keep in touch, follow me on GitHub.