Skip to content
Harness Design System Harness Design System Harness Design System

TreeView

The TreeView component is used to display hierarchical data in an expandable/collapsible tree structure. It supports features like selection, status indicators, execution details, and RTL/LTR text direction.

Usage

import { Tree, Folder, File, CollapseButton, type TreeViewElement } from '@harnessio/ui/components'
import { ExecutionState } from '@harnessio/ui/views'
//...
return (
<Tree initialSelectedId="1-1" className="h-96 w-full rounded-md border">
<Folder
element="Documents"
value="folder-1"
status={ExecutionState.SUCCESS}
level={0}
>
<File value="1-1" status={ExecutionState.SUCCESS} level={1}>
File 1
</File>
</Folder>
</Tree>
)

Basic Tree Structure

Create a simple tree with folders and files. The tree automatically handles expand/collapse interactions.

With Status Indicators

The TreeView component displays status icons based on the ExecutionState. It supports states like SUCCESS, RUNNING, FAILURE, PENDING, and more.

With Initial Selection

You can specify an initial selected item using the initialSelectedId prop. The tree will automatically expand parent folders to show the selected item.

With Initial Expanded Items

Control which folders are initially expanded using the initialExpendedItems prop.

Non-Selectable Items

You can make specific items non-selectable by setting isSelectable: false on the element.

With Collapse Button

Add a collapse/expand all button using the CollapseButton component.

RTL Support

The TreeView component supports right-to-left (RTL) text direction using the dir prop.

This comprehensive example demonstrates all features of the TreeView component including:

  • Multiple nested levels
  • Various execution states with status icons
  • Duration display for each item
  • Initial selection and expansion
  • Collapse/expand all functionality
  • Mix of selectable and non-selectable items
  • Real-world CI/CD pipeline structure

API Reference

TreeViewElement Type

type TreeViewElement = {
id: string; // Unique identifier for the tree item
name: string; // Display name of the item
isSelectable?: boolean; // Whether the item can be selected (default: true)
children?: TreeViewElement[]; // Nested child elements
status: ExecutionState; // Execution status (see ExecutionState enum)
duration?: string; // Formatted duration string (e.g., "2m 30s")
};

ExecutionState Enum

enum ExecutionState {
PENDING = "pending",
RUNNING = "running",
SUCCESS = "success",
FAILURE = "failure",
ERROR = "error",
SKIPPED = "skipped",
KILLED = "killed",
BLOCKED = "blocked",
WAITING_ON_DEPENDENCIES = "waiting_on_dependencies",
UNKNOWN = "unknown",
}

Tree Component Props

Prop
Required
Default
Type
elementsfalseTreeViewElement[]
initialSelectedIdfalsestring
initialExpendedItemsfalsestring[]
indicatorfalsetrueboolean
dirfalse'ltr''rtl' | 'ltr'
classNamefalsestring
openIconfalseReact.ReactNode
closeIconfalseReact.ReactNode

Folder Component Props

Prop
Required
Default
Type
elementtruestring
valuetruestring
statustrueExecutionState
durationfalsestring
leveltruenumber
isSelectablefalsetrueboolean
isSelectfalseboolean
expendedItemsfalsestring[]

File Component Props

Prop
Required
Default
Type
valuetruestring
childrentrueReact.ReactNode
statustrueExecutionState
durationfalsestring
leveltruenumber
isSelectablefalsetrueboolean
isSelectfalseboolean
handleSelectfalse(id: string) => void

CollapseButton Component Props

Prop
Required
Default
Type
elementstrueTreeViewElement[]
expandAllfalsefalseboolean
childrenfalseReact.ReactNode

Helper Utility: Rendering Tree Elements

You can create a helper utility to recursively render tree elements from data:

import { ReactNode } from 'react'
import { File, Folder, type TreeViewElement } from '@harnessio/ui/components'
interface RenderTreeElementProps {
element: TreeViewElement
handleClick?: (params: { parentNode: TreeViewElement | null; childNode: TreeViewElement }) => void
parentElement?: TreeViewElement | null
level?: number
}
// Main render function
export const renderTree = (
elements: TreeViewElement[],
handleClick?: (params: { parentNode: TreeViewElement | null; childNode: TreeViewElement }) => void
): ReactNode => {
if (elements.length === 0) return []
return elements.map(element => (
<div key={element.id}>
{renderTreeElement({ element, handleClick, parentElement: null })}
</div>
))
}
// Render folder with children
const renderTreeFolder = ({ element: folderElement, handleClick, level = 0 }: RenderTreeElementProps): ReactNode => {
return (
<Folder
element={folderElement.name}
value={folderElement.id}
status={folderElement.status}
duration={folderElement.duration}
isSelectable={folderElement.isSelectable}
level={level}
>
{folderElement.children?.map(childElement => (
<div key={childElement.id}>
{renderTreeElement({
parentElement: folderElement,
element: childElement,
handleClick,
level: level + 1
})}
</div>
))}
</Folder>
)
}
// Render file (leaf node)
const renderTreeFile = ({
element: fileElement,
handleClick,
parentElement,
level = 0
}: RenderTreeElementProps): ReactNode => {
return (
<File
value={fileElement.id}
status={fileElement.status}
duration={fileElement.duration}
isSelectable={fileElement.isSelectable}
handleSelect={() => handleClick?.({ parentNode: parentElement, childNode: fileElement })}
level={level}
>
{fileElement.name}
</File>
)
}
// Decide whether to render folder or file
const renderTreeElement = ({
element,
handleClick,
parentElement,
level = 0
}: RenderTreeElementProps): ReactNode => {
if (element.children && element.children.length > 0) {
return renderTreeFolder({ element, handleClick, parentElement, level })
}
return renderTreeFile({ element, handleClick, parentElement, level })
}
// Usage example:
const treeData: TreeViewElement[] = [
{
id: '1',
name: 'Folder',
status: 'success',
children: [
{ id: '1-1', name: 'File 1', status: 'success' }
]
}
]
<Tree className="h-96 w-full rounded-md border">
{renderTree(treeData, ({ parentNode, childNode }) => {
console.log('Selected:', childNode.name)
})}
</Tree>