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" /> );