Top
TreeView API - API
TreeView API
Props (61)
Callback Props (8)
Styling Props (13)
Methods (17)
String|Number
default: undefined
Specifies which node is active. The active node is updated via keyboard (Arrow up/down when the <TreeView /> has focus) or when the user clicks a node in the tree.
The value for the activeNode is using either the idProperty (if specified) or the pathProperty prop (for more details, see the Using node path property page).
This is a controlled prop. Make sure you also specify the onActiveNodeChange function prop in order to update the <TreeView /> when the active node changes - or use the uncontrolled defaultActiveNode.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'
import components from './components'

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = { activeNode: null }
  }
  render() {
    return <div>
      <p>{this.state.activeNode == null ? <i>No active node</i>: <span>Active node: <b>{this.state.activeNode}</b></span>}.</p>
      <TreeView
        activeNode={this.state.activeNode}
        onActiveNodeChange={({ activeNode }) => {
          this.setState({ activeNode })
        }}
        dataSource={components}
      />
   </div>
  }
}

export default () => <App />
Bool
default: true
Whether to render the node checkbox before the node icon.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/TreeView/index.css'
import '@zippytech/react-toolkit/CheckBox/index.css'

import components from './components'

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      checkBeforeIcon: true
    }
  }

  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={this.state.checkBeforeIcon}
          onChange={(checkBeforeIcon) => {
            this.setState({
              checkBeforeIcon
            })
          }}
        >
          Render checkbox before icon
        </CheckBox>
      </div>
      <TreeView
        enableChecked
        leafNodeIcon={
          <svg fill="#000000" height="16" viewBox="0 0 24 24" width="16" style={{verticalAlign: 'middle'}}>
            <path d="M6 2c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8l-6-6H6zm7 7V3.5L18.5 9H13z"/>
            <path d="M0 0h24v24H0z" fill="none"/>
          </svg>
        }
        nodeIcon={
          <svg fill="#000000" height="16" viewBox="0 0 24 24" width="16" style={{verticalAlign: 'middle'}}>
            <path d="M10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z"/>
            <path d="M0 0h24v24H0z" fill="none"/>
          </svg>
        }
        checkBeforeIcon={this.state.checkBeforeIcon}
        dataSource={components}
      />
    </div>
  }
}

export default () => <App />
Object
default: undefined
Object that controls checked state of the entire <TreeView />. Its keys identify a particular node (see Using the path property page), and its value specifies whether the node is checked.
For recursively checking nodes, use checkNodesRecursive=true (true is the default value).
This is a controlled prop. For uncontrolled behaviour, see defaultChecked. You can use onCheckedChange in order to be notified of checked property changes.
For this prop to have effect enableChecked must be true.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/TreeView/index.css'
import '@zippytech/react-toolkit/CheckBox/index.css'

import components from './components'

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      enableChecked: true,
      checked: {},
      checkNodesRecursive: true
    }
  }
  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={this.state.enableChecked}
          onChange={(enableChecked) => {
            this.setState({
              enableChecked
            })
          }}
        >Enable checked
        </CheckBox>
      </div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={this.state.checkNodesRecursive}
          onChange={(checkNodesRecursive) => {
            this.setState({
              checkNodesRecursive
            })
          }}
        >Check nodes recursive
        </CheckBox>
      </div>
      <p>Currently checked: <code>{JSON.stringify(this.state.checked, null, 2)}</code>.</p>
      <TreeView
        enableChecked={this.state.enableChecked}
        checked={this.state.checked}
        checkNodesRecursive={this.state.checkNodesRecursive}
        onCheckedChange={({ checkedMap }) => {
          this.setState({ checked: checkedMap })
        }}
        dataSource={components}
      />
    </div>
  }
}

export default () => <App />
Bool
default: true
Whether node checking should be recursive - when is true, checking a root node will also check all its child nodes. Interaction also goes upwards - so checking the last unchecked leaf in a root node will change the checked state for the root. Basically, it's the normal behaviour one expects from checking nodes in a tree structure - for any given a node:
  • if it's children are all checked, it will also be rendered as checked.
  • if only some of it's children are checked, it will have undeterminated state.
  • if only some of the children are checked and the user checks the node, all of node's children will be checked.
  • if all of it's children are checked and the user clicks to uncheck the node, all of node's children will be unchecked.
For this prop to have effect, the <TreeView /> must have checkboxes - see enableChecked.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/TreeView/index.css'
import '@zippytech/react-toolkit/CheckBox/index.css'
import components from './components'

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      enableChecked: true,
      checked: {},
      checkNodesRecursive: true
    }
  }
  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={this.state.enableChecked}
          onChange={(enableChecked) => {
            this.setState({
              enableChecked
            })
          }}
        >Enable checked
        </CheckBox>
      </div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={this.state.checkNodesRecursive}
          onChange={(checkNodesRecursive) => {
            this.setState({
              checkNodesRecursive
            })
          }}
        >Check nodes recursive
        </CheckBox>
      </div>
      <p>Currently checked: <code>{JSON.stringify(this.state.checked, null, 2)}</code>.</p>
      <TreeView
        enableChecked={this.state.enableChecked}
        checked={this.state.checked}
        checkNodesRecursive={this.state.checkNodesRecursive}
        onCheckedChange={({ checkedMap }) => {
          this.setState({ checked: checkedMap })
        }}
        dataSource={components}
      />
    </div>
  }
}

export default () => <App />
Bool
default: true
Whether to check a node when the node.label is clicked. If checkOnClick=false the user needs to click the checkbox in order to toggle the node check.
For this prop to have effect, checkboxes must be enabled - see enableChecked.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/TreeView/index.css'
import '@zippytech/react-toolkit/CheckBox/index.css'
import components from './components'

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      enableChecked: true,
      checkOnClick: true,
      checked: {},
      checkNodesRecursive: true
    }
  }
  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={this.state.enableChecked}
          onChange={(enableChecked) => {
            this.setState({
              enableChecked
            })
          }}
        >Enable checked
        </CheckBox>
      </div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={this.state.checkOnClick}
          onChange={(checkOnClick) => {
            this.setState({
              checkOnClick
            })
          }}
        >Check on click
        </CheckBox>
      </div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={this.state.checkNodesRecursive}
          onChange={(checkNodesRecursive) => {
            this.setState({
              checkNodesRecursive
            })
          }}
        >Check nodes recursive
        </CheckBox>
      </div>
      <p>Current checked state: <code>{JSON.stringify(this.state.checked, null, 2)}</code>.</p>
      <TreeView
        enableChecked={this.state.enableChecked}
        checked={this.state.checked}
        checkOnClick={this.state.checkOnClick}
        checkNodesRecursive={this.state.checkNodesRecursive}
        onCheckedChange={({ checkedMap }) => {
          this.setState({ checked: checkedMap })
        }}
        dataSource={components}
      />
    </div>
  }
}

export default () => <App />
Bool
default: false
If true, it will also check the node when it gets selected.
For this prop to have effect, the <TreeView /> must show checkboxes (see enableChecked) and enableSelection must be true.
checkOnClick must be false for this prop to have effect, because a node is already selected when clicked.
The <TreeView /> supports both checked nodes and selected nodes - but it's probably not a good idea to configure both at the same time.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'

import components from './components'

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      selected: { '0/0/3': true, '0/0/4': true, '0/1': true },
      checkNodesRecursive: true,
      checkOnSelect: true,
      enableChecked: true,
      enableSelection: true,
      enableKeyboardNavigation: true
    }
  }

  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={this.state.enableKeyboardNavigation}
          onChange={(enableKeyboardNavigation) => {
            this.setState({
              enableKeyboardNavigation
            })
          }}
        >Enable keyboard navigation
        </CheckBox>
      </div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={this.state.enableSelection}
          onChange={(enableSelection) => {
            this.setState({
              enableSelection
            })
          }}
        >Enable selection
        </CheckBox>
      </div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={this.state.checkOnSelect}
          onChange={(checkOnSelect) => {
            this.setState({
              checkOnSelect
            })
          }}
        >Check on select
        </CheckBox>
      </div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={this.state.enableChecked}
          onChange={(enableChecked) => {
            this.setState({
              enableChecked
            })
          }}
        >Use checkboxes
        </CheckBox>
      </div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={this.state.checkNodesRecursive}
          onChange={(checkNodesRecursive) => {
            this.setState({
              checkNodesRecursive
            })
          }}
        >Check nodes recursive
        </CheckBox>
      </div>
      <p>
          Current selected state: <code>{JSON.stringify(this.state.selected, null, 2)}</code>.
      </p>
      <TreeView
        key={this.state.singleSelect+""}
        selected={this.state.selected}
        checkOnClick={false}
        enableSelection={this.state.enableSelection}
        onSelectionChange={({selectedMap}) => {
          this.setState({ selected: selectedMap })
        }}
        enableChecked={this.state.enableChecked}
        checkNodesRecursive={this.state.checkNodesRecursive}
        checkOnSelect={this.state.checkOnSelect}
        enableKeyboardNavigation={this.state.enableKeyboardNavigation}
        dataSource={components}
      />
    </div>
  }
}

export default () => <App />
Object
default: undefined
Object that controls collapse state of the entire <TreeView />. Its keys identify a particular node (see the Using the path property page), and its values specify whether nodes are collapsed.
This is a controlled prop. Use onCollapsedChange({ collapsedMap }) to update the value of this prop. For uncontrolled behaviour, see defaultCollapsed.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

const components = [
  {
    label: <strong>components:</strong>,
    nodes: [
      {
        label: <i>DataGrid</i>,
        nodes: [
          { label: <i>Getting started</i> },
          {
            label: <i>Configuring columns</i>,
            nodes: [
              { label: <i>Normal columns</i> },
              { label: <i>Locked start columns</i> },
              { label: <i>Locked end columns</i> }
            ]
          },
          { label: <i>Using a data source</i> },
          { label: <i>Sorting</i> },
          { label: <i>Keyboard navigation</i> },
          { label: <i>Filtering</i> },
        ]
      },
      {
        label: <i>ComboBox</i>,
        nodes: [
          { label: <i>Getting started</i> },
          { label: <i>Multiselect</i> },
          { label: <i>Dropdown</i> },
          { label: <i>Autocomplete</i> },
          { label: <i>Styling</i> }
        ]
      },
      {
        label: <i>TreeView</i>,
        nodes: [
          { label: <i>Getting started</i> },
          { label: <i>Async nodes</i> },
          { label: <i>Navigation</i> },
          { label: <i>Search TreeView</i> },
          { label: <i>API</i> }
        ]
      },
      {
        label: <i>Button</i>,
        nodes: [
          {
            label: <i>DropdownButton</i>,
            nodes: [
              { label: <i>Getting started</i> },
              { label: <i>Callback props</i> },
              { label: <i>API</i> }
            ]
          },
          { label: <i>SplitButton</i> },
          { label: <i>GroupButton</i> }
        ]
      }
    ]
  },
  {
    label: <strong>guides:</strong>,
    nodes: [
      { label: <i>Getting started with React</i> },
      { label: <i>Understanding React state</i> },
      { label: <i>Using Redux for state management</i> }
    ]
  }
];

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      collapsed: {
        '0/0/1': true,
        '0/1': true,
        '0/2': true,
        '0/3': true
      }
    }
  }
  render() {
    return <div>
      <p>Currently collapsed: <code>{JSON.stringify(this.state.collapsed, null, 2)}</code>.</p>
      <TreeView
        collapsed={this.state.collapsed}
        onCollapsedChange={({ collapsedMap: collapsed }) => {
          this.setState({ collapsed })
        }}
        dataSource={components}
      />
    </div>
  }
}

export default () => <App />
Number
default: undefined
Controls from which level the tree is collapsed. If null the tree will render all its nodes expanded. To render only the first level as expanded, specify collapsedDepth=0.
For fine-grained control over which nodes are collapsed, use the collapsed controlled prop (or the defaultCollapsed uncontrolled alternative).
This is a controlled prop. Use onCollapsedDepthChange to be notified when the collapsedDepth changes. For the uncontrolled alternative, see defaultCollapsedDepth. To allow user interaction with the <TreeView /> component to freely expand/collpase nodes (as well as using the setCollapsed method), update the value of this prop to null when onCollapsedDepthChange is called by the <TreeView /> component to notify changes.
For uncontrolled behaviour, see defaultCollapsedDepth.
This prop has no effect if collapsed or defaultCollapsed are set.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'
import components from './components'

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = { collapsedDepth: 1  }
  }
  render() {
    return <TreeView
      collapsedDepth={this.state.collapsedDepth}
      onCollapsedDepthChange={() => this.setState({ collapsedDepth: null })}
      dataSource={components}
    />
  }
}

export default () => <App />
Array|Promise: Array[]|Fn: Array| Fn: Promise
default: undefined
<TreeView /> nodes are configured using dataSource prop.
Objects in the dataSource prop can have the following shape:
  • label - the content (React.Node) to display for the node.
  • icon - an optional icon for the tree node. When a string, an <img /> with src being set to the value of icon is rendered. Otherwise, the given React.Node is rendered.
  • nodes - optional child nodes for the node. A leaf node is a node with nodes=null or nodes=undefined.
  • className - an optional className for the tree node.
  • labelClassName - an optional className for the node label.
  • contentClassName - an optional className for the node content.
  • disabled - whether to render the node as disabled or not.
  • labelStyle - an optional style for the node label.
  • contentStyle - an optional style for the node content.
For non-async trees, a leaf node is a node that has nodes=null or nodes=undefined. When a node is a leaf, the expand tool is not rendered. A node with an empty array for the nodes property, is not a leaf, because you can have a node that is expandable without children (e.g. a folder with no files).
For async trees, that have loadNode or loadNodeOnce specified, a node with node.nodes===null is an async node, which will be loaded once it is expanded. See the page on Async data and nodes for more details.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

const dataSource = [
  {
    label: 'components:',
    nodes: [
      {
        label: 'DataGrid',
        nodes: [
          { label: 'Getting started' },
          {
            label: 'Configuring columns',
            nodes: [
              { label: 'Normal columns' },
              { label: 'Locked start columns' },
              { label: 'Locked end columns' }
            ]
          },
          { label: 'Using a data source' },
          { label: 'Sorting' },
          { label: 'Keyboard navigation' },
          { label: 'Filtering' }
        ]
      },
      {
        label: 'ComboBox',
        nodes: [
          { label: 'Getting started' },
          { label: 'Multiselect' },
          { label: 'Dropdown' },
          { label: 'Autocomplete' },
          { label: 'Styling' }
        ]
      },
      {
        label: 'TreeView',
        nodes: [
          { label: 'Getting started' },
          { label: 'Async nodes' },
          { label: 'Navigation' },
          { label: 'Search TreeView' },
          { label: 'API' }
        ]
      },
      {
        label: 'Button',
        nodes: [
          {
            label: 'DropdownButton',
            nodes: [
              { label: 'Getting started' },
              { label: 'Callback props' },
              { label: 'API' }
            ]
          },
          { label: 'SplitButton' },
          { label: 'GroupButton' }
        ]
      }
    ]
  },
  {
    label: 'guides:',
    nodes: [
      { label: 'Getting started with React' },
      {
        label: 'React state (has disabled: true in dataSource)',
        disabled: true
      },
      { label: 'Using Redux for state management' }
    ]
  }
];

export default () => <TreeView dataSource={dataSource} />
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

const dataSource = [
  {
    label: 'Components',
    nodes: [
      { label: 'DataGrid', nodes: null },
      { label: 'ComboBox', nodes: null },
      { label: 'TreeView', nodes: null },
      { label: 'Button' },
    ]
  },
]

function loadNodeOnce({ node, path }) {
  const nodes = node.label.indexOf('API') != -1 ?
    [
      { label: 'General props' },
      { label: 'Callback props' },
      { label: 'Methods' }
    ]
    :
    [
      { label: 'Using the ' + node.label },
      { label: node.label + ' API', nodes: null }
    ]

  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(nodes)
    }, 500)
  })
}

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      lastLoaded: null
    }

    this.onNodeLoad = this.onNodeLoad.bind(this)
  }

  onNodeLoad(newNodes, { node }) {
    this.setState({
      lastLoaded: node.label
    })
  }

  render() {
    return <div>
      <p>{this.state.lastLoaded ? 'Last async-loaded node: ' + this.state.lastLoaded: 'No async node loaded yet'}</p>
      <TreeView
        onNodeLoad={this.onNodeLoad}
        loadNodeOnce={loadNodeOnce}
        dataSource={dataSource}
      />
    </div>
  }
}

export default () => <App />
String|Number
default: undefined
Specifies which node is the default active node. The active node is updated via keyboard (Arrow up/down when the <TreeView /> has focus) or when the user clicks a node in the tree.
The value for the defaultActiveNode is using either the idProperty (if specified) or the pathProperty prop (for more details, see the Using node path property page).
This is an uncontrolled prop. Specify the onActiveNodeChange function prop in order to get updates from the <TreeView /> when the active node changes.
For controlled behaviour use the defaultActiveNode prop.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'
import components from './components'

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = { activeNode: "0/0" }
  }
  render() {
    return <div>
      <p>Active node: <b>{this.state.activeNode || "none"}</b>.</p>
      <TreeView
        defaultActiveNode="0/0"
        onActiveNodeChange={({ activeNode }) => {
          this.setState({ activeNode })
        }}
        dataSource={components}
      />
   </div>
  }
}

export default () => <App />
Object
default: undefined
Object that controls the initial checked state of the <TreeView />. Its keys identify a particular node (see Using the path property page), and its value specifies whether the node is checked.
For recursively checking nodes, use checkNodesRecursive=true (true is the default value).
This is an uncontrolled prop. For controlled behaviour, see checked. You can use onCheckedChange in order to be notified of checked property changes.
For this prop to have effect enableChecked must be true.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/TreeView/index.css'
import '@zippytech/react-toolkit/CheckBox/index.css'

import components from './components'

const defaultChecked = {
  "0": null,
  "0/0/1/0": true,
  "0/0/1": null,
  "0/0": null,
  "0/0/1/1": true
}

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      enableChecked: true,
      checked: defaultChecked,
      checkNodesRecursive: true
    }
  }
  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={this.state.enableChecked}
          onChange={(enableChecked) => {
            this.setState({
              enableChecked
            })
          }}
        >Enable checked
        </CheckBox>
      </div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={this.state.checkNodesRecursive}
          onChange={(checkNodesRecursive) => {
            this.setState({
              checkNodesRecursive
            })
          }}
        >Check nodes recursive
        </CheckBox>
      </div>
      <p>Currently checked: <code>{JSON.stringify(this.state.checked, null, 2)}</code>.</p>
      <TreeView
        enableChecked={this.state.enableChecked}
        defaultChecked={defaultChecked}
        checkNodesRecursive={this.state.checkNodesRecursive}
        onCheckedChange={({ checkedMap }) => {
          this.setState({ checked: checkedMap })
        }}
        dataSource={components}
      />
    </div>
  }
}

export default () => <App />
idMap|pathMap: Object
default: undefined
Sets the initial value for the collapsed state of the <TreeView />.
For controlled behaviour, see collapsed. Use onCollapsedChange({ collapsedMap }) to get notifications user actions that change node collapse/expand state.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

const components = [
  {
    label: <strong>components:</strong>,
    nodes: [
      {
        label: <i>DataGrid</i>,
        nodes: [
          { label: <i>Getting started</i> },
          {
            label: <i>Configuring columns</i>,
            nodes: [
              { label: <i>Normal columns</i> },
              { label: <i>Locked start columns</i> },
              { label: <i>Locked end columns</i> }
            ]
          },
          { label: <i>Using a data source</i> },
          { label: <i>Sorting</i> },
          { label: <i>Keyboard navigation</i> },
          { label: <i>Filtering</i> },
        ]
      },
      {
        label: <i>ComboBox</i>,
        nodes: [
          { label: <i>Getting started</i> },
          { label: <i>Multiselect</i> },
          { label: <i>Dropdown</i> },
          { label: <i>Autocomplete</i> },
          { label: <i>Styling</i> }
        ]
      },
      {
        label: <i>TreeView</i>,
        nodes: [
          { label: <i>Getting started</i> },
          { label: <i>Async nodes</i> },
          { label: <i>Navigation</i> },
          { label: <i>Search TreeView</i> },
          { label: <i>API</i> }
        ]
      },
      {
        label: <i>Button</i>,
        nodes: [
          {
            label: <i>DropdownButton</i>,
            nodes: [
              { label: <i>Getting started</i> },
              { label: <i>Callback props</i> },
              { label: <i>API</i> }
            ]
          },
          { label: <i>SplitButton</i> },
          { label: <i>GroupButton</i> }
        ]
      }
    ]
  },
  {
    label: <strong>guides:</strong>,
    nodes: [
      { label: <i>Getting started with React</i> },
      { label: <i>Understanding React state</i> },
      { label: <i>Using Redux for state management</i> }
    ]
  }
];

export default () => <TreeView
  defaultCollapsed={{
    '0/0/1': true,
    '0/1': true,
    '0/2': true,
    '0/3': true
  }}
  dataSource={components}
/>
Number
default: undefined
Uncontrolled version of collapsedDepth - specifies the initial collapsedDepth for the tree.
For the controlled alternative, see collapsedDepth.
This prop has no effect if collapsed or defaultCollapsed are set.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

import components from './components'

export default () => <TreeView
  defaultCollapsedDepth={1}
  dataSource={components}
/>
String
default: undefined
Sets the initial searchText for the SearchTreeView.
For controlled behaviour, see searchText.
Use onSearchTextChange to get notifications of searchText value changes.
import React from 'react'
import SearchTreeView from '@zippytech/react-toolkit/TreeView/SearchTreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

import components from './components-text'

export default () => <SearchTreeView
  defaultSearchText="at"
  dataSource={components}
/>
Object
default: undefined
This prop controls the selection initial state of the entire <TreeView />. Its keys identify a particular node (see using the path property page), and its values specify whether specific node are selected.
In order to show checkboxes for the tree nodes, see enableChecked and defaultChecked.
For single selection, see singleSelect.
This is an uncontrolled prop. Use onSelectionChange({ selectedMap }) to react to selection changes in the <TreeView />.
For controlled behaviour, see selected.
For this prop to have effect enableSelection must be true.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'
import components from './components'

const defaultSelected = {
  "0/0/0/1":true,
  "0/0/0/2":true,
  "0/0/1/1":true,
  "0/0/1/2":true,
  "0/0/1/0":true,
  "1/0":true
}

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      selected: null
    }
  }
  render() {
    return <div>
    <p>Current selection: <code>{JSON.stringify(this.state.selected || defaultSelected)}</code>.</p>
     <TreeView
       enableSelection
       defaultSelected={defaultSelected}
       onSelectionChange={({ selectedMap }) => {
        this.setState({ selected: selectedMap })
       }}
       dataSource={components}
     />
   </div>
  }
}

export default () => <App />
Object
default: undefined
This prop controls the disabled state of all <TreeView /> nodes. Its keys identify a particular node (see using the path property page), and its values specify whether specific nodes are disabled.
If a node is disabled all actions are prevented (collapse, active, selection, navigation, checked). Also a disabled node is always collapsed , event if isNodeCollapsed is true.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'
import components from './components'

const disabledMap = {
  "0/0/0/1":true,
  "0/0/0/2":true,
  "0/0/1/1":true,
  "0/0/1/2":true,
  "0/0/1/0":true,
  "1/0":true
}

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      selected: null
    }
  }
  render() {
    return <div>
      <p>Currently disabled: <code>{JSON.stringify(disabledMap, null, 2)}</code>.</p>
      <TreeView
        disabled={disabledMap}
        dataSource={components}
      />
    </div>
  }
}

export default () => <App />
Bool
default: undefined
Specifies if the <TreeView /> should render a checkbox for nodes.
The checked value is managed via the controlled checked prop or the uncontrolled defaultChecked prop. In order to be notified of changes, use onCheckedChange({ checkedMap }).
By default, checkboxes are checked recursively - this is configured via the checkNodesRecursive prop.
If this prop is undefined (which is the default value), checkboxes will be visible if checked or defaultChecked are specified. Otherwise, if this prop has a boolean value, checkboxes will be visible depending on that.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/TreeView/index.css'
import '@zippytech/react-toolkit/CheckBox/index.css'

import components from './components'

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      enableChecked: true,
      checkBeforeIcon: true,
      checked: {},
      checkNodesRecursive: true
    }
  }
  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={this.state.enableChecked}
          onChange={(enableChecked) => {
            this.setState({
              enableChecked
            })
          }}
        >Enable checked
        </CheckBox>
      </div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={this.state.checkNodesRecursive}
          onChange={(checkNodesRecursive) => {
            this.setState({
              checkNodesRecursive
            })
          }}
        >Check nodes recursive
        </CheckBox>
      </div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={this.state.checkBeforeIcon}
          onChange={(checkBeforeIcon) => {
            this.setState({
              checkBeforeIcon
            })
          }}
        >
          Render checkbox before icon
        </CheckBox>
      </div>
      <p>Current checked state: <code>{JSON.stringify(this.state.checked, null, 2)}</code>.</p>
      <TreeView
        enableChecked={this.state.enableChecked}
        checked={this.state.checked}
        checkNodesRecursive={this.state.checkNodesRecursive}
        leafNodeIcon={
          <svg fill="#000000" height="16" viewBox="0 0 24 24" width="16" style={{verticalAlign: 'middle'}}>
            <path d="M6 2c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8l-6-6H6zm7 7V3.5L18.5 9H13z"/>
            <path d="M0 0h24v24H0z" fill="none"/>
          </svg>
        }
        nodeIcon={
          <svg fill="#000000" height="16" viewBox="0 0 24 24" width="16" style={{verticalAlign: 'middle'}}>
            <path d="M10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z"/>
            <path d="M0 0h24v24H0z" fill="none"/>
          </svg>
        }
        checkBeforeIcon={this.state.checkBeforeIcon}
        onCheckedChange={({ checkedMap }) => {
          this.setState({ checked: checkedMap })
        }}
        dataSource={components}
      />
    </div>
  }
}

export default () => <App />
Bool
default: true
If true, the nodes in the <TreeView /> will show a hover style. This property adds zippy-toolkit-react-tree-view--enable-hover-style className to the <TreeView />. The "default" theme will add a hover style for tree nodes.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/TreeView/index.css'
import '@zippytech/react-toolkit/CheckBox/index.css'
import components from './components'

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      enableHoverStyle: true
    }
  }
  render() {
    return <div>
      <div style={{ marginBottom: 20}}>
        <CheckBox
          checked={this.state.enableHoverStyle}
          onChange={(enableHoverStyle) => {
            this.setState({
              enableHoverStyle
            })
          }}
        >
          Enable hover style
        </CheckBox>
      </div>
      <TreeView
        enableHoverStyle={this.state.enableHoverStyle}
        dataSource={components}
      />
    </div>
  }
}

export default () => <App />
Bool
default: true
Whether the <TreeView /> should be navigateable via keyboard actions. See the Keyboard navigation page for more details.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/TreeView/index.css'
import '@zippytech/react-toolkit/CheckBox/index.css'
import components from './components'

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      enableKeyboardNavigation: true
    }
  }
  render() {
    return <div>
      <div style={{ marginBottom: 20}}>
        <CheckBox
          checked={this.state.enableKeyboardNavigation}
          onChange={(enableKeyboardNavigation) => {
            this.setState({
              enableKeyboardNavigation
            })
          }}
        >
          Enable keyboard navigation
        </CheckBox>
      </div>
      <TreeView
        enableKeyboardNavigation={this.state.enableKeyboardNavigation}
        dataSource={components}
      />
    </div>
  }
}

export default () => <App />
Bool
default: true
Whether to bring the activeNode into the view by scrolling the <TreeView />. This works in combination with navigating with arrows.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/TreeView/index.css'
import '@zippytech/react-toolkit/CheckBox/index.css'

import components from './components'

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      enableScrollNodeIntoView: true
    }
  }
  render() {
    return <div>
      <div style={{ marginBottom: 20}}>
        <CheckBox
          checked={this.state.enableScrollNodeIntoView}
          onChange={(enableScrollNodeIntoView) => {
            this.setState({
              enableScrollNodeIntoView
            })
          }}
        >
          Enable scroll activeNode into view
        </CheckBox>
      </div>
      <TreeView
        style={{ maxHeight: 300, overflow: 'auto' }}
        enableScrollNodeIntoView={this.state.enableScrollNodeIntoView}
        dataSource={components}
      />
    </div>
  }
}

export default () => <App />
Bool
default: false
Whether the <TreeView /> nodes can be selected. A node can be selected by clicking on it.
For specifying which nodes should be selected, see selected (controlled) and defaultSelected (uncontrolled) props. Use onSelectionChange to be notified of changes in selection.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'

import components from './components'

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      selected: {
        "0/0/0/1":true,
        "0/0/0/2":true,
        "0/0/1/1":true,
        "0/0/1/2":true,
        "0/0/1/0":true,
        "1/0":true
      },
      enableSelection: true,
      singleSelect: false
    }
  }

  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={this.state.enableSelection}
          onChange={(enableSelection) => {
            this.setState({
              enableSelection
            })
          }}
        >Enable selection
        </CheckBox>
      </div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={this.state.singleSelect}
          onChange={(singleSelect) => {
            this.setState({
              singleSelect
            })
          }}
        >Single select
        </CheckBox>
      </div>
      <p>
          Current selected state: <code>{JSON.stringify(this.state.selected, null, 2)}</code>.
      </p>
      <TreeView
        key={this.state.singleSelect+""}
        selected={this.state.selected}
        enableSelection={this.state.enableSelection}
        onSelectionChange={({ selectedMap }) => {
          this.setState({ selected: selectedMap })
        }}
        singleSelect={this.state.singleSelect}
        dataSource={components}
      />
    </div>
  }
}

export default () => <App />
Bool
default: false
Whether to expand/collapse a node by double clicking or single click. When false, will expand on single click. Otherwise, on double-click.
When expandOnToolOnly is true, the double-click should be on the expand tool.
When expandOnToolOnly is false, the double-click can be on the expand tool or on the node.label.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/TreeView/index.css'
import '@zippytech/react-toolkit/CheckBox/index.css'
import components from './components'

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      expandOnDoubleClick: true,
      expandOnToolOnly: true
    }
  }
  render() {
    return <div>
      <div style={{ marginBottom: 20}}>
        <CheckBox
          checked={this.state.expandOnToolOnly}
          onChange={(expandOnToolOnly) => {
            this.setState({
              expandOnToolOnly
            })
          }}
        >
          Expand on tool only
        </CheckBox>
      </div>
      <div style={{ marginBottom: 20}}>
        <CheckBox
          checked={this.state.expandOnDoubleClick}
          onChange={(expandOnDoubleClick) => {
            this.setState({
              expandOnDoubleClick
            })
          }}
        >
          Expand on double click
        </CheckBox>
      </div>
      <TreeView
        expandOnToolOnly={this.state.expandOnToolOnly}
        expandOnDoubleClick={this.state.expandOnDoubleClick}
        dataSource={components}
      />
    </div>
  }
}

export default () => <App />
Bool
default: true
Whether to expand/collapse tree nodes only by clicking on the expander icon. When false it will also expand by clicking the node labels.
To expand on doubleclick instead of single click, see expandOnDoubleClick.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/TreeView/index.css'
import '@zippytech/react-toolkit/CheckBox/index.css'
import components from './components'

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      expandOnToolOnly: true
    }
  }
  render() {
    return <div>
      <div style={{ marginBottom: 20}}>
        <CheckBox
          checked={this.state.expandOnToolOnly}
          onChange={(expandOnToolOnly) => {
            this.setState({
              expandOnToolOnly
            })
          }}
        >
          Expand on tool only
        </CheckBox>
      </div>
      <TreeView
        expandOnToolOnly={this.state.expandOnToolOnly}
        dataSource={components}
      />
    </div>
  }
}

export default () => <App />
React.Node|Fn(domProps, nodeProps)
default: undefined
Allows to specify a custom expand tool for <TreeView /> nodes. Can either be a React.Node or a custom render function for collapse/expand tool arrow.
When using a function, you can return new React.Node or return undefined and mutate domProps.
If the function returns undefined the mutated domProps are applied on the default implementation.
For more details on using nodeProps see Node Props page.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/TreeView/index.css'
import '@zippytech/react-toolkit/CheckBox/index.css'
import components from './components'

const customExpandTool = <svg fill="#000000" height="14" viewBox="0 0 24 24" width="14">
  <path d="M8 5v14l11-7z"/>
  <path d="M0 0h24v24H0z" fill="none"/>
</svg>

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      customExpandTool: false
    }
  }
  render() {
    return <div>
      <div style={{ marginBottom: 20}}>
        <CheckBox
          checked={this.state.customExpandTool}
          onChange={(customExpandTool) => {
            this.setState({
              customExpandTool
            })
          }}
        >
          Use custom expand tool
        </CheckBox>
      </div>
      <TreeView
        expandTool={this.state.customExpandTool ? customExpandTool : undefined}
        dataSource={components}
      />
    </div>
  }
}

export default () => <App />
Number
default: 14
Configures the size of the expandTool.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/TreeView/index.css'
import '@zippytech/react-toolkit/CheckBox/index.css'
import components from './components'

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      largeExpandTool: false
    }
  }
  render() {
    return <div>
      <div style={{ marginBottom: 20}}>
        <CheckBox
          checked={this.state.largeExpandTool}
          onChange={(largeExpandTool) => {
            this.setState({
              largeExpandTool
            })
          }}
        >
          Expand tool size: 30
        </CheckBox>
      </div>
      <TreeView
        expandToolSize={this.state.largeExpandTool ? 30 : undefined}
        dataSource={components}
      />
    </div>
  }
}

export default () => <App />
Fn(nodeProps): Bool
default: undefined
Specifies a filter function that is used to filter the dataSource.
It's called with the nodeProps object - see Node Props page for more details.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'
import components from './components'

function filterFunction(nodeProps, text) {
  const label = nodeProps.node.label.toLowerCase()
  return label.indexOf(text) == 0
}

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = { value: '' }
  }
  render() {
    return <div>
      <div style={{ marginBottom: 20}}>
        <input
          value={this.state.value}
          onChange={(event) => this.setState({ value: event.target.value })}
        />
      </div>
      <TreeView
        filter={(nodeProps) => filterFunction(nodeProps, this.state.value)}
        dataSource={components}
      />
   </div>
  }
}

export default () => <App />
String|Fn(node):String/Number
default: undefined
Each node has a path to itself, starting from the root of the tree. The node path is a string that uniquely identifies a node from dataSource.
The node path is used to indicate which nodes are collapsed, expanded, active or selected.
There are two ways to configure how the <TreeView /> uses node paths and indexes nodes based on their path:
  • using the pathProperty prop - if this is specified, the node path is built by joining together all values of curentNode[pathProperty] starting from the root to the targeted node. Those values are joined together using the value specified by pathSeparator.
  • using the idProperty - if this is specified, the node path is just the value of node[idProperty] property, as it already uniquely identifies the node.
If neither pathProperty nor idProperty are specified, the path of a node is built by joining the indexes of all parent nodes from root to the targeted node (the indexes are joined using the pathSeparator prop value). So for the third child of the first dataSource item, the path would be "0/2". For the second child of this node, the path would be "0/2/1".
The most important thing about node paths and how you configure them is that they have to be unique! Unless paths are not unique, it can make the <TreeView /> behave in unexpected ways.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

function renderLabel(domProps, nodeProps) {
  domProps.children = [
    domProps.children,
    <span>{' '}(<i key="path">path: {nodeProps.path}</i>)</span>
  ]
}

const dataSource = [
  {
    id: 'js',
    label: 'JavaScript',
    nodes: [
      { id: 'reactjs', label: 'ReactJS' },
      { id: 'angular', label: 'Angular JS' }
    ]
  },
  {
    id: 'py',
    label: 'Python',
    nodes: [
      { id: 'django', label: 'Django Framework' },
      { id: 'flask', label: 'Flask MicroFramework' }
    ]
  }
];

export default () => <div>
  <code style={{ whiteSpace: 'pre-wrap' }}>
    const dataSource = {JSON.stringify(dataSource, null, 2)}
  </code>

  <p>
  <strong>Default case:</strong><br />
  <div>In this case the path for the node with id of 'angular', will be '0/1'.</div>
  <div>The path for the node with id of 'django', will be '1/0'.</div>
  </p>

  <TreeView dataSource={dataSource} renderLabel={renderLabel} />

  <p>
    <strong>Case <i>pathProperty="label"</i></strong><br />
    <div>In this case the path for the node with id of 'reactjs', will be 'JavaScript/ReactJS'</div>
    <div>The path for the node with id of 'flask', will be 'Python/Flask MicroFramework'</div>
  </p>

  <TreeView dataSource={dataSource} renderLabel={renderLabel} pathProperty="label" />

  <p>
  <strong>Case <i>idProperty="id"</i></strong><br />
  <div>In this case the path for the node with id of 'flask', will be just 'flusk'</div>
  </p>
  <TreeView dataSource={dataSource} renderLabel={renderLabel} idProperty="id" />
</div>;
Fn(nodeProps): Bool
default: undefined
When specified, it determines which <TreeView /> nodes are async. Called if either loadNode or loadNodeOnce is defined (since specifying one of those props makes the <TreeView /> async).
For more details about async nodes see the Asynchronous data and nodes page.
This function is called with nodeProps object. For more details on nodeProps see Node Props page.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

const dataSource = [
  {
    label: 'Components',
    nodes: [
      { label: 'DataGrid', async: true },
      { label: 'ComboBox', async: true },
      { label: 'TreeView', async: true },
      { label: 'Button' },
    ]
  },
]

const isNodeAsync = ({ node }) => {
  return node.async
}

function loadNodeOnce({ node, path }) {
  const nodes = node.label.indexOf('API') != -1 ?
    [
      { label: 'General props' },
      { label: 'Callback props' },
      { label: 'Methods' }
    ]
    :
    [
      { label: 'Using the ' + node.label },
      { label: node.label + ' API', async: true }
    ]

  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(nodes)
    }, 500)
  })
}

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      lastLoaded: null
    }

    this.onNodeLoad = this.onNodeLoad.bind(this)
  }

  onNodeLoad(newNodes, { node }) {
    this.setState({
      lastLoaded: node.label
    })
  }

  render() {
    return <div>
      <p>{this.state.lastLoaded ? 'Last async-loaded node: ' + this.state.lastLoaded: 'No async node loaded yet'}</p>
      <TreeView
        isNodeAsync={isNodeAsync}
        onNodeLoad={this.onNodeLoad}
        loadNodeOnce={loadNodeOnce}
        dataSource={dataSource}
      />
    </div>
  }
}

export default () => <App />
Fn(nodeProps)
default: undefined
Determines if a node is checked. Overwrites the checked prop (and the uncontrolled defaultChecked).
For this prop to have effect, the <TreeView /> must have checkboxes - see enableChecked.
For more details on nodeProps see Node Props page.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

const data = [
  {
    label: 'components:',
    nodes: [
      {
        label: 'DataGrid',
        nodes: [
          { label: 'Getting started' },
          {
            label: 'Configuring columns',
            nodes: [
              { label: 'Normal columns' },
              { label: 'Locked start columns' },
              { label: 'Locked end columns' }
            ]
          },
          { label: 'Using a data source' },
          { label: 'Sorting' },
          { label: 'Keyboard navigation', checked: true },
          { label: 'Filtering', checked: true }
        ]
      },
      {
        label: 'ComboBox',
        nodes: [
          { label: 'Getting started' },
          { label: 'Multiselect' },
          { label: 'Dropdown' },
          { label: 'Autocomplete' },
          { label: 'Styling' }
        ]
      },
      {
        label: 'TreeView',
        nodes: [
          { label: 'Getting started' },
          { label: 'Async nodes' },
          { label: 'Navigation' },
          { label: 'Search TreeView' },
          { label: 'API' }
        ]
      }
    ]
  }
]

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      dataSource: [...data],
      lastUnchecked: null,
      lastChecked: null
    }

    this.isNodeChecked = this.isNodeChecked.bind(this)
    this.onCheckedChange = this.onCheckedChange.bind(this)
  }

  isNodeChecked({ node, checked }) {
    if (node.checked !== undefined) {
      return node.checked
    }

    if (node.label === 'Sorting' || node.label === 'Dropdown') {
      return true
    }

    // return the checked value, as specified for this node by the defaultChecked prop
    return checked
  }

  onCheckedChange({ getUpdatedDataSource, node, checked }) {
    if (checked) {
      this.setState({
        lastChecked: node.label
      })
    } else {
      this.setState({
        lastUnchecked: node.label
      })
    }

    const updateNode = ({ node, checked }) => {
      return Object.assign({}, node, { checked })
    }

    const dataSource = getUpdatedDataSource(updateNode)

    this.setState({
      dataSource
    })
  }

  render() {
    return <div>
      <p>{this.state.lastUnchecked ? 'Last unchecked node: ' + this.state.lastUnchecked: 'No node has been unchecked yet'}.</p>
      <p>{this.state.lastChecked ? 'Last checked node: ' + this.state.lastChecked: 'No node has been checked yet'}.</p>
      <TreeView
        enableChecked
        checkNodesRecursive={false}
        defaultChecked={{
          '0/2/0': true,
          '0/2/1': true
        }}
        isNodeChecked={this.isNodeChecked}
        onCheckedChange={this.onCheckedChange}
        dataSource={this.state.dataSource}
      />
      <p>
        DataSource: <code style={{ whiteSpace: 'pre-wrap' }}>{JSON.stringify(this.state.dataSource, null, 2)}</code>.
      </p>

    </div>
  }
}

export default () => <App />
Fn(nodeProps)
default: undefined
When specified, it determines which <TreeView /> nodes are collapsed.
This function is called with nodeProps object. For more details on nodeProps see Node Props page.
Overwrites the controlled collapsed object prop (and the uncontrolled the controlled defaultCollapsed prop).
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

const data = [
  {
    label: 'components:',
    nodes: [
      {
        label: 'DataGrid',
        nodes: [
          { label: 'Getting started' },
          {
            label: 'Configuring columns',
            nodes: [
              { label: 'Normal columns' },
              { label: 'Locked start columns' },
              { label: 'Locked end columns' }
            ]
          },
          { label: 'Using a data source' },
          { label: 'Sorting' },
          { label: 'Keyboard navigation' },
          { label: 'Filtering' }
        ]
      },
      {
        label: 'ComboBox',
        nodes: [
          { label: 'Getting started' },
          { label: 'Multiselect' },
          { label: 'Dropdown' },
          { label: 'Autocomplete' },
          { label: 'Styling' }
        ]
      },
      {
        label: 'TreeView',
        nodes: [
          { label: 'Getting started' },
          { label: 'Async nodes' },
          { label: 'Navigation' },
          { label: 'Search TreeView' },
          { label: 'API' }
        ]
      }
    ]
  }
]

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      dataSource: [...data],
      lastCollapsed: null,
      lastExpanded: null
    }

    this.isNodeCollapsed = this.isNodeCollapsed.bind(this)
    this.onCollapsedChange = this.onCollapsedChange.bind(this)
  }

  isNodeCollapsed({ node }) {
    if (node.collapsed !== undefined) {
      return node.collapsed
    }

    if (node.label === 'DataGrid' || node.label === 'ComboBox') {
      return true
    }

    return false
  }

  onCollapsedChange({ getUpdatedDataSource, node, collapsed }) {
    if (collapsed) {
      this.setState({
        lastCollapsed: node.label
      })
    } else {
      this.setState({
        lastExpanded: node.label
      })
    }

    const updateNode = ({ node, collapsed }) => {
      return Object.assign({}, node, { collapsed })
    }

    const dataSource = getUpdatedDataSource(updateNode)

    this.setState({
      dataSource
    })
  }

  render() {
    return <div>
      <p>{this.state.lastCollapsed ? 'Last collapsed node: ' + this.state.lastCollapsed: 'No node has been collapsed yet'}.</p>
      <p>{this.state.lastExpanded ? 'Last expanded node: ' + this.state.lastExpanded: 'No node has been expanded yet'}.</p>
      <TreeView
        isNodeCollapsed={this.isNodeCollapsed}
        onCollapsedChange={this.onCollapsedChange}
        dataSource={this.state.dataSource}
      />
    </div>
  }
}

export default () => <App />
Fn(nodeProps): Bool
default: undefined
Determines which nodes in the <TreeView /> are disabled. When specified, it overwrites disabledand defaultDisabled props.
This function is called with the nodePropsobject. For more details on nodeProps see Node Props page.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

import components from './components'

function isNodeDisabled({ node, disabled }) {
  if (node.label === 'DataGrid' || node.label === 'ComboBox') {
    return true
  }

  //otherwise, return the disabled value, as specified via the disabled prop
  return disabled
}

export default () => <TreeView
  enableChecked
  enableSelection
  isNodeDisabled={isNodeDisabled}
  disabled={{ '0/2': true, '1': true }}
  dataSource={components}
/>
React.Node|String
default: undefined
Custom icon rendered for leaf nodes. See dataSource for more information on leaf nodes.
Will render an image with src to the specified value (if leafNodeIcon is a string). Otherwise, if a React.Node is specified, it will be rendered as it is.
If you need to access the node state, you can use a function for rendering icons - see node.icon or renderIcon.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

import components from './components'

export default () => <TreeView
  defaultCollapsedDepth={1}
  leafNodeIcon={
    <svg key="leaf_node" fill="#000000" height="16" viewBox="0 0 24 24" width="16" style={{verticalAlign: 'middle'}}>
      <path d="M6 2c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8l-6-6H6zm7 7V3.5L18.5 9H13z"/>
      <path d="M0 0h24v24H0z" fill="none"/>
    </svg>
  }
  nodeIcon={
    <svg key="node_icon" fill="#000000" height="16" viewBox="0 0 24 24" width="16" style={{verticalAlign: 'middle'}}>
      <path d="M10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z"/>
      <path d="M0 0h24v24H0z" fill="none"/>
    </svg>
  }
  dataSource={components}
/>
Bool
default: false
Specify whether the component should be rendered as loading. This overwrites the internal loading state.
When using an asynchronous dataSource, the <TreeView /> is rendered as loading initially, until the dataSource promise resolves.
Use the renderLoader to customize loading text and appearance.
This is different from the loading state for an async node.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/TreeView/index.css'
import '@zippytech/react-toolkit/CheckBox/index.css'
import components from './components'

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      loading: true
    }
  }
  render() {
    return <div>
      <div style={{ marginBottom: 20}}>
        <CheckBox
          checked={this.state.loading }
          onChange={(loading) => {
            this.setState({
              loading
            })
          }}
        >
          Show as loading
        </CheckBox>
      </div>
      <TreeView
        loading={this.state.loading}
        dataSource={components}
      />
    </div>
  }
}

export default () => <App />
Fn(nodeProps): nodes[]|Promise
default: undefined
Called when a node is expanded. Should return/resolve to an array of child nodes, or null.
When loadNode is specified, all nodes are considered async & non-leaf by default. In this case, you can use isNodeAsync to determine which nodes should not be async.
For more about async nodes see dataSource and Asynchronous data and nodes page.
When a promise is returned a loading icon is rendered.
For more details on nodeProps see Node Props page
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

const dataSource = [
  {
    label: 'Components',
    nodes: [
      { label: 'DataGrid', nodes: null },
      { label: 'ComboBox', nodes: null },
      { label: 'TreeView', nodes: null },
      { label: 'Button' },
    ]
  },
]

function loadNode({ node, path }) {
  const nodes = node.label.indexOf('API') != -1 ?
    [
      { label: 'General props' },
      { label: 'Callback props' },
      { label: 'Methods' }
    ]
    :
    [
      { label: 'Using the ' + node.label },
      { label: node.label + ' API', nodes: null }
    ]

  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(nodes)
    }, 500)
  })
}

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      lastLoaded: null
    }

    this.onNodeLoad = this.onNodeLoad.bind(this)
  }

  onNodeLoad(newNodes, { node }) {
    this.setState({
      lastLoaded: node.label
    })
  }

  render() {
    return <div>
      <p>{this.state.lastLoaded ? 'Last async-loaded node: ' + this.state.lastLoaded: 'No async node loaded yet'}</p>
      <TreeView
        onNodeLoad={this.onNodeLoad}
        loadNode={loadNode}
        dataSource={dataSource}
      />
    </div>
  }
}

export default () => <App />
Fn(nodeProps): nodes[]|Promise
default: undefined
Called when an async node is expanded. Should return/resolve to an array of child nodes, or null.
Like loadNode but only called once per node.
When this props is specified, only nodes that have nodes === null are considered async nodes.
For more about async nodes see dataSource and Asynchronous data and nodes page.
When a promise is returned a loading icon is rendered.
For more details on nodeProps see Node Props page
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

const dataSource = [
  {
    label: 'Components',
    nodes: [
      { label: 'DataGrid', nodes: null },
      { label: 'ComboBox', nodes: null },
      { label: 'TreeView', nodes: null },
      { label: 'Button' },
    ]
  },
]

function loadNode({ node, path }) {
  const nodes = node.label.indexOf('API') != -1 ?
    [
      { label: 'General props' },
      { label: 'Callback props' },
      { label: 'Methods' }
    ]
    :
    [
      { label: 'Using the ' + node.label },
      { label: node.label + ' API', nodes: null }
    ]

  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(nodes)
    }, 500)
  })
}

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      lastLoaded: null
    }

    this.onNodeLoad = this.onNodeLoad.bind(this)
  }

  onNodeLoad(newNodes, { node }) {
    this.setState({
      lastLoaded: node.label
    })
  }

  render() {
    return <div>
      <p>{this.state.lastLoaded ? 'Last async-loaded node: ' + this.state.lastLoaded: 'No async node loaded yet'}</p>
      <TreeView
        onNodeLoad={this.onNodeLoad}
        loadNodeOnce={loadNode}
        dataSource={dataSource}
      />
    </div>
  }
}

export default () => <App />
React.Node|Fn(nodeProps): React.Node
default: undefined
Loading icon rendered instead of expandTool while loadNode or loadNodeOnce resolves.
For more details on nodeProps see Node Props page
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

const dataSource = [
  {
    label: 'Components',
    nodes: [
      { label: 'DataGrid', nodes: null },
      { label: 'ComboBox', nodes: null },
      { label: 'TreeView', nodes: null },
      { label: 'Button' },
    ]
  },
]

function loadNode({ node, path }) {
  const nodes = node.label.indexOf('API') != -1 ?
    [
      { label: 'General props' },
      { label: 'Callback props' },
      { label: 'Methods' }
    ]
    :
    [
      { label: 'Using the ' + node.label },
      { label: node.label + ' API', nodes: null }
    ]

  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(nodes)
    }, 2500)
  })
}

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      lastLoaded: null
    }

    this.onNodeLoad = this.onNodeLoad.bind(this)
  }

  onNodeLoad(newNodes, { node }) {
    this.setState({
      lastLoaded: node.label
    })
  }

  render() {
    return <div>
      <p>{this.state.lastLoaded ? 'Last async-loaded node: ' + this.state.lastLoaded: 'No async node loaded yet'}</p>
      <TreeView
        loadTool={<div className="tree-view-loader" />}
        onNodeLoad={this.onNodeLoad}
        loadNode={loadNode}
        dataSource={dataSource}
      />
    </div>
  }
}

export default () => <App />
Number
default: 20
Specifies size of the indentation to be used for nesting nodes inside the <TreeView />.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import ComboBox from '@zippytech/react-toolkit/ComboBox'
import '@zippytech/react-toolkit/TreeView/index.css'
import '@zippytech/react-toolkit/CheckBox/index.css'
import '@zippytech/react-toolkit/ComboBox/index.css'

import components from './components'

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      nestingIndentation: 20
    }
  }
  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        Nesting indentation: <ComboBox
          inlineFlex
          style={{width: 100}}
          dataSource={[
            { label: '10px', id: 10 },
            { label: '20px', id: 20 },
            { label: '40px', id: 40 },
            { label: '60px', id: 60 }
          ]}
          value={this.state.nestingIndentation}
          collapseOnSelect
          multiple={false}
          searchable={false}
          clearIcon={false}
          changeValueOnNavigation
          onChange={(nestingIndentation) => {
            this.setState({
              nestingIndentation
            })
          }}
        />
      </div>
      <TreeView
        nestingIndentation={this.state.nestingIndentation}
        dataSource={components}
      />
    </div>
  }
}

export default () => <App />
Bool
default: undefined
Specifies if the node is disabled - overwrites global disabled state.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

const components = [
  {
    label: <strong>components:</strong>,
    nodes: [
      {
        label: <i>DataGrid</i>,
        nodes: [
          { label: <i>Getting started</i> },
          {
            label: <i>Configuring columns</i>,
            nodes: [
              { label: <i>Normal columns</i> },
              { label: <i>Locked start columns</i> },
              { label: <i>Locked end columns</i> }
            ]
          },
          { label: <i>Using a data source</i> },
          { label: <i>Sorting</i> },
          { label: <i>Keyboard navigation</i> },
          { label: <i>Filtering</i> },
        ]
      },
      {
        label: <i>ComboBox</i>,
        disabled: true,
        nodes: [
          { label: <i>Getting started</i> },
          { label: <i>Multiselect</i> },
          { label: <i>Dropdown</i> },
          { label: <i>Autocomplete</i> },
          { label: <i>Styling</i> }
        ]
      },
      {
        label: <i>TreeView</i>,
        nodes: [
          { label: <i>Getting started</i> },
          { label: <i>Async nodes</i> },
          { label: <i>Navigation</i> },
          { label: <i>Search TreeView</i> },
          { label: <i>API</i> }
        ]
      },
      {
        label: <i>Button</i>,
        disabled: true,
        nodes: [
          {
            label: <i>DropdownButton</i>,
            nodes: [
              { label: <i>Getting started</i> },
              { label: <i>Callback props</i> },
              { label: <i>API</i> }
            ]
          },
          { label: <i>SplitButton</i> },
          { label: <i>GroupButton</i> }
        ]
      }
    ]
  },
  {
    label: <strong>guides:</strong>,
    nodes: [
      { label: <i>Getting started with React</i> },
      { label: <i>Understanding React state</i> },
      { label: <i>Using Redux for state management</i> }
    ]
  }
];

export default () => <TreeView
  defaultCollapsedDepth={2}
  dataSource={components}
/>
React.Node|Fn(nodeProps)|String
default: undefined
A custom icon for the node. It's rendered between checkbox and label.
When it is a String, an img tag will be rendered with the specified value used for the src attribute.
When a function is specified, it will be called with the nodeProps object - so it can use all the node state to render custom icons. For more details on nodeProps see Node Props page.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

const dataSource = [
  {
    label: 'Menu',
    nodes: [
      { label: 'open' },
      { label: 'edit' },
      { label: 'paste', disabled: true },
      {
        label: 'save',
        icon: <svg height={20} viewBox="0 0 24 24" width={20}>
          <path
            d="M17 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V7l-4-4zm-5 16c-1.66 0-3-1.34-3-3s1.34-3 3-3 3 1.34 3 3-1.34 3-3 3zm3-10H5V5h10v4z"
          />
        </svg>,
      }
    ],
  }
];

export default () => <TreeView
  dataSource={dataSource}
/>
React.Node|Fn(nodeProps)|String
default: undefined
Content to be rendered as the node label.
This property can be a function - which is especially useful when you want to render a label which needs to access the node collapsed/checked/selected state.
For more details on nodeProps see Node Props page.
Also see renderIcon.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

const dataSource = [
  {
    label: ({ collapsed }) => <b>components {collapsed? ' - expand to view more':''}:</b>,
    nodes: [
      {
        label: <b>DataGrid</b>,
        nodes: [
          { label: 'Getting started' },
          {
            label: 'Configuring columns',
            nodes: [
              { label: 'Normal columns' },
              { label: 'Locked start columns' },
              { label: 'Locked end columns' }
            ]
          },
          { label: 'Using a data source' },
          { label: 'Sorting' },
          { label: 'Keyboard navigation' },
          { label: 'Filtering' }
        ]
      },
      {
        label: <b>ComboBox</b>,
        nodes: [
          { label: 'Getting started' },
          { label: 'Multiselect' },
          { label: 'Dropdown' },
          { label: 'Autocomplete' },
          { label: 'Styling' }
        ]
      },
      {
        label: <b>TreeView</b>,
        nodes: [
          { label: 'Getting started' },
          { label: 'Async nodes' },
          { label: 'Navigation' },
          { label: 'Search TreeView' },
          { label: 'API' }
        ]
      },
      {
        label: <b>Button</b>,
        nodes: [
          {
            label: 'DropdownButton',
            nodes: [
              { label: 'Getting started' },
              { label: 'Callback props' },
              { label: 'API' }
            ]
          },
          { label: 'SplitButton' },
          { label: 'GroupButton' }
        ]
      }
    ]
  },
  {
    label: <h3>guides:</h3>,
    nodes: [
      { label: 'Getting started with React' },
      {
        label: 'React state (has disabled: true in dataSource)',
        disabled: true
      },
      { label: 'Using Redux for state management' }
    ]
  }
];

export default () => <TreeView defaultCollapsedDepth={0} dataSource={dataSource} />
node[]
default: undefined
Specifies nodes nested under this node.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

const dataSource = [
  {
    label: <h3>components:</h3>,
    nodes: [
      {
        label: <b>DataGrid</b>,
        nodes: [
          { label: 'Getting started' },
          {
            label: 'Configuring columns',
            nodes: [
              { label: 'Normal columns' },
              { label: 'Locked start columns' },
              { label: 'Locked end columns' }
            ]
          },
          { label: 'Using a data source' },
          { label: 'Sorting' },
          { label: 'Keyboard navigation' },
          { label: 'Filtering' }
        ]
      },
      {
        label: <b>ComboBox</b>,
        nodes: [
          { label: 'Getting started' },
          { label: 'Multiselect' },
          { label: 'Dropdown' },
          { label: 'Autocomplete' },
          { label: 'Styling' }
        ]
      },
      {
        label: <b>TreeView</b>,
        nodes: [
          { label: 'Getting started' },
          { label: 'Async nodes' },
          { label: 'Navigation' },
          { label: 'Search TreeView' },
          { label: 'API' }
        ]
      },
      {
        label: <b>Button</b>,
        nodes: [
          {
            label: 'DropdownButton',
            nodes: [
              { label: 'Getting started' },
              { label: 'Callback props' },
              { label: 'API' }
            ]
          },
          { label: 'SplitButton' },
          { label: 'GroupButton' }
        ]
      }
    ]
  },
  {
    label: <h3>guides:</h3>,
    nodes: [
      { label: 'Getting started with React' },
      {
        label: 'React state (has disabled: true in dataSource)',
        disabled: true
      },
      { label: 'Using Redux for state management' }
    ]
  }
];

export default () => <TreeView defaultCollapsedDepth={1} dataSource={dataSource} />
React.Node|String
default: undefined
Custom icon rendered for collapsed nodes.
Will render an <img /> tag with the specified value used for the src attribute (if nodeCollapsedIcon is a string). Otherwise, if a React.Node is specified, it will be rendered as-is.
If you need to access the node state, you can use a function for rendering icons - see node.icon or renderIcon.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'
import components from './components'

const nodeIcon = <div>
  <svg fill="#000000" height="16" viewBox="0 0 24 24" width="16" style={{verticalAlign: 'middle'}}>
    <path d="M10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z"/>
    <path d="M0 0h24v24H0z" fill="none"/>
  </svg>
</div>

const nodeCollapsedIcon = <div>
  <svg fill="red" height="16" viewBox="0 0 24 24" width="16" style={{verticalAlign: 'middle'}}>
    <path d="M10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z"/>
    <path d="M0 0h24v24H0z" fill="none"/>
  </svg>
</div>

export default () => <TreeView
  defaultCollapsedDepth={1}
  nodeIcon={nodeIcon}
  nodeCollapsedIcon={nodeCollapsedIcon}
  dataSource={components}
/>
React.Node|String
default: undefined
Custom icon rendered for nodes in the <TreeView />.
Will render an <img /> tag with the specified value used for the src attribute (if nodeIcon is a string). Otherwise, if a React.Node is specified, it will be rendered as-is.
For rendering separate icons for leaf nodes, use leafNodeIcon, which will override the icon for leaf nodes.
If you need to access the node state, you can use a function for rendering icons - see node.icon or renderIcon.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

import components from './components'

export default () => <TreeView
  defaultCollapsedDepth={1}
  leafNodeIcon={
    <div>
      <svg fill="#000000" height="16" viewBox="0 0 24 24" width="16" style={{verticalAlign: 'middle'}}>
        <path d="M6 2c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8l-6-6H6zm7 7V3.5L18.5 9H13z"/>
        <path d="M0 0h24v24H0z" fill="none"/>
      </svg>
    </div>
  }
  nodeIcon={
    <div>
      <svg fill="#000000" height="16" viewBox="0 0 24 24" width="16" style={{verticalAlign: 'middle'}}>
        <path d="M10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z"/>
        <path d="M0 0h24v24H0z" fill="none"/>
      </svg>
    </div>
  }
  dataSource={components}
/>
String|Fn(node):String/Number
default: undefined
Each node has a path to itself, starting from the tree root. The node path is a string that uniquely identifies a node from dataSource.
The node path is used to indicate which nodes are collapsed, expanded, active or selected.
There are two ways to configure how the TreeView uses node paths and indexes nodes based on their path:
  • using the pathProperty prop - if this is specified, the node path is built by joining together all values of curentNode[pathProperty] starting from the root to the targeted node. Those values are joined together using the value specified by pathSeparator.
  • using the idProperty - if this is specified, the node path is just the value of node[idProperty] property, as it already uniquely identifies the node.
If neither pathProperty nor idProperty are specified, the path of a node is built by joining the indexes of all parent nodes from root to the targeted node (the indexes are joined using the pathSeparator prop value). So for the third child of the first dataSource item, the path would be "0/2". For the second child of this node, the path would be "0/2/1".
The most important thing about node paths and how you configure them is that they have to be unique! Unless paths are not unique, it can make the <TreeView /> behave in unexpected ways.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

function renderLabel(domProps, nodeProps) {
  domProps.children = [
    domProps.children,
    <span>{' '}(<i key="path">path: {nodeProps && nodeProps.path}</i>)</span>
  ]
}

const dataSource = [
  {
    id: 'js',
    label: 'JavaScript',
    nodes: [
      { id: 'reactjs', label: 'ReactJS' },
      { id: 'angular', label: 'Angular JS' }
    ]
  },
  {
    id: 'py',
    label: 'Python',
    nodes: [
      { id: 'django', label: 'Django Framework' },
      { id: 'flask', label: 'Flask MicroFramework' }
    ]
  }
];

export default () => <div>
  <code style={{ whiteSpace: 'pre-wrap' }}>
    const dataSource = {JSON.stringify(dataSource, null, 2)}
  </code>

  <p>
   <strong>Default case:</strong><br />
   <div>In this case the path for the node with id of 'angular', will be '0/1'.</div>
   <div>The path for the node with id of 'django', will be '1/0'.</div>
   <div>The default pathSeparator is "/".</div>
  </p>

  <TreeView dataSource={dataSource} renderLabel={renderLabel} />

  <p>
    <strong>Case <i>pathProperty="label"</i></strong><br />
    <div>In this case the path for the node with id of 'reactjs', will be 'JavaScript/ReactJS'</div>
    <div>The path for the node with id of 'flask', will be 'Python/Flask MicroFramework'</div>
  </p>

  <TreeView dataSource={dataSource} renderLabel={renderLabel} pathProperty="label" />

  <p>
   <strong>Case <i>idProperty="id"</i></strong><br />
   <div>In this case the path for the node with id of 'flask', will be just 'flusk'</div>
  </p>
  <TreeView dataSource={dataSource} renderLabel={renderLabel} idProperty="id" />
</div>;
String
default: "/"
A string to be used when concatenating path identifiers, to create a unique path for each node in the <TreeView />.
Each node has a path to itself, starting from the root of the tree. The node path is a string that uniquely identifies a node in the dataSource.
The node path is used to indicate which nodes are collapsed, expanded, active or selected.
There are two ways to configure how the <TreeView /> uses node paths and indexes nodes based on their path:
  • using the pathProperty prop - if this is specified, the node path is built by joining together all values of curentNode[pathProperty] starting from the root to the targeted node. Those values are joined together using the value specified by pathSeparator.
  • using the idProperty - if this is specified, the node path is just the value of node[idProperty] property, as it already uniquely identifies the node.
If neither pathProperty nor idProperty are specified, the path of a node is built by joining the indexes of all parent nodes from root to the targeted node (the indexes are joined using the pathSeparator prop value). So for the third child of the first dataSource item, the path would be "0/2". For the second child of this node, the path would be "0/2/1".
The most important thing about node paths and how you configure them is that they have to be unique! Unless paths are not unique, it can make the <TreeView /> behave in unexpected ways.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

function renderLabel(domProps, nodeProps) {
  domProps.children = [
    domProps.children,
    <span>{' '}(<i key="path">path: {nodeProps.path}</i>)</span>
  ]
}

const dataSource = [
  {
    id: 'js',
    label: 'JavaScript',
    nodes: [
      { id: 'reactjs', label: 'ReactJS' },
      { id: 'angular', label: 'Angular JS' }
    ]
  },
  {
    id: 'py',
    label: 'Python',
    nodes: [
      { id: 'django', label: 'Django Framework' },
      { id: 'flask', label: 'Flask MicroFramework' }
    ]
  }
];

export default () => <div>
  <code style={{ whiteSpace: 'pre-wrap' }}>
    const dataSource = {JSON.stringify(dataSource, null, 2)}
  </code>

  <p>
   <strong>Default case:</strong><br />
   <div>In this case the path for the node with id of 'angular', will be '0/1'.</div>
   <div>The path for the node with id of 'django', will be '1/0'.</div>
   <div>The default pathSeparator is "/".</div>
  </p>

  <TreeView dataSource={dataSource} renderLabel={renderLabel} />

  <p>
    <strong>Case <i>pathProperty="label"</i>, <i>pathSeparator="-"</i></strong> <br />
    <div>In this case the path for the node with id of 'reactjs', will be 'JavaScript-ReactJS'</div>
    <div>The path for the node with id of 'flask', will be 'Python-Flask MicroFramework'</div>
  </p>

  <TreeView dataSource={dataSource} renderLabel={renderLabel} pathProperty="label" pathSeparator="-" />

  <p>
   <strong>Case <i>idProperty="id"</i></strong><br />
   <div>In this case the path for the node with id of 'flask', will be just 'flusk'</div>
  </p>
  <TreeView dataSource={dataSource} renderLabel={renderLabel} idProperty="id" />
</div>;
Bool|Fn(domProps, nodeProps)
default: undefined
Custom render function for check.
If false, will not render checkboxes, even if enableChecked=true.
false is the only accepted boolean value.
Any valid CheckBox prop can be added on domProps.
For more details on nodeProps see Node Props page.
Return a new React.Node or return undefined, and mutate domProps.
If it returns undefined, the mutated domProps are applied on the default implementation.
For this prop to have effect, the <TreeView /> must have checkboxes - see enableChecked.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/TreeView/index.css'
import '@zippytech/react-toolkit/CheckBox/index.css'

import components from './components'

function renderCheck(domProps, nodeProps) {
  domProps.style = { fill: 'red' }
}

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      customRenderCheck: true
    }
  }
  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={this.state.customRenderCheck}
          onChange={(customRenderCheck) => {
            this.setState({
              customRenderCheck
            })
          }}
        >Custom renderCheck
        </CheckBox>
      </div>
      <TreeView
        enableChecked
        renderCheck={this.state.customRenderCheck ? renderCheck : undefined}
        dataSource={components}
      />
    </div>
  }
}

export default () => <App />
Fn(domProps, nodeProps)
default: undefined
Custom render function for the node content.
For more details on nodeProps see Node Props page.
Return a new React.Node or return undefined, and mutate domProps.
If it returns undefined, the mutated domProps are applied on the default implementation.
If you want to customize the node.label line, see renderLabel.
If you want to customize the whole node wrapper, use renderNode.
If you only want to customize the node.label without the node icons (loadTool, node.icon and node check), see renderNodeText.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/TreeView/index.css'
import '@zippytech/react-toolkit/CheckBox/index.css'

import components from './components-text'

function renderContent(domProps, nodeProps) {
  if (nodeProps.node.label.indexOf('guides') == 0) {
    domProps.style.color = 'red'
  }
}

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      customRenderContent: true
    }
  }
  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          onChange={(customRenderContent) => {
            this.setState({
              customRenderContent
            })
          }}
          checked={this.state.customRenderContent}
        >
          Use custom renderContent
        </CheckBox>
      </div>
      <TreeView
        defaultCollapsedDepth={1}
        renderContent={this.state.customRenderContent? renderContent : undefined}
        dataSource={components}
      />
    </div>
  }
}

export default () => <App />
Fn(nodeProps)
default: undefined
If specified, will be used to render a custom icon for nodes in the <TreeView />. The returned React.Node will be rendered after the expandTool. It overwrites node.icon, nodeIcon and leafNodeIcon.
For more details on nodeProps see Node Props page.
Also see node.icon.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

import components from './components'

const leafIcon = <svg fill="#000000" height="16" viewBox="0 0 24 24" width="16" style={{verticalAlign: 'middle'}}>
  <path d="M6 2c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8l-6-6H6zm7 7V3.5L18.5 9H13z"/>
  <path d="M0 0h24v24H0z" fill="none"/>
</svg>

const renderIcon = ({ collapsed, hasChildren }) => {
  if (!hasChildren) {
    return leafIcon
  }

  const fill = !collapsed ? "blue" : "black"

  return <div>
    <svg fill={fill} height="16" viewBox="0 0 24 24" width="16" style={{verticalAlign: 'middle'}}>
      <path d="M10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z"/>
      <path d="M0 0h24v24H0z" fill="none"/>
    </svg>
  </div>
}

export default () => <TreeView
  defaultCollapsedDepth={1}
  renderIcon={renderIcon}
  dataSource={components}
/>
Fn(domProps, props)|false
default: undefined
Custom render function for the search input in the <SearchTreeView />.
If false, the search input will not be rendered.
Only applies to the <SearchTreeView />.
You can either return a new React.Node or return undefined and mutate the receiveddomProps - in which case an <input /> with the specified domProps will be rendered. .
import React from 'react'
import SearchTreeView from '@zippytech/react-toolkit/TreeView/SearchTreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

import components from './components-text'

const renderInput = (domProps) => {
  domProps.style = Object.assign({}, domProps.style, { padding: 15, border: '1px dotted blue' })
}

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      searchText: 'at'
    }
  }
  render() {
    return <div>
      <p>
        Current search text: {this.state.searchText || "none"}.
      </p>

      <SearchTreeView
        renderInput={renderInput}
        searchText={this.state.searchText}
        onSearchTextChange={(searchText) => {
          this.setState({
            searchText
          })
        }}
        dataSource={components}
      />
    </div>
  }
}

export default () => <App />
Fn(domProps, nodeProps)
default: undefined
Custom render function for the wrapper that holds the node.label and node icons (loadTool, node.icon and node check).
This is applied to the node.label wrapper, so will not contain the node children. For applying a custom render function to the node children wrapper as well, see renderNode.
If you only want to customize the node.label contents, without the node icons (loadTool, node.icon and node check), see renderNodeText.
For more details on nodeProps see Node Props page.
Return a new React.Node or return undefined, and mutate the given domProps.
If the function returns undefined, the mutated domProps are applied on the default implementation.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/TreeView/index.css'
import '@zippytech/react-toolkit/CheckBox/index.css'

import components from './components-text'

function renderLabel(domProps, nodeProps) {
  if (nodeProps.node.label.indexOf('guides') == 0) {
    domProps.style.color = 'red'
  }
}

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      customRenderLabel: true
    }
  }
  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          onChange={(customRenderLabel) => {
            this.setState({
              customRenderLabel
            })
          }}
          checked={this.state.customRenderLabel}
        >
          Use custom renderLabel
        </CheckBox>
      </div>
      <TreeView
        defaultCollapsedDepth={1}
        renderLabel={this.state.customRenderLabel? renderLabel : undefined}
        dataSource={components}
      />
    </div>
  }
}

export default () => <App />
Fn(props)
default: undefined
Custom loading renderer for when the <TreeView /> is configured with async dataSource.
The dataSource can be a Promise or a function returning a Promise (in which case, it is called the the <TreeView /> props as the first argument). While the async dataSource is resolving, you can display some loading feedback in the tree, using the renderLoader function prop.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'
import colors from './colors'

const colorsPromise = new Promise((resolve) => {
  setTimeout(() => {
    resolve(colors)
  }, 1000)
})
function renderLoader(nodeProps) {
  return <strong>Loading dataSource ...</strong>
}

export default () => <div>
  <TreeView
    renderLoader={renderLoader}
    dataSource={colorsPromise}
  />
</div>
The above example shows a simple lazy-loaded dataSource. But the true power of lazily loaded trees lie in nodes being able to be loaded lazily as they are expanded.
Fn(domProps, nodeProps)
default: undefined
Custom render function for the entire node, both the label and its children.
If you want to customize the node.label line, see renderLabel.
If you only want to customize the node content wrapper, use renderContent.
If you only want to customize the node.label without the node icons (loadTool, node.icon and node check), see renderNodeText.
For more details on nodeProps see Node Props page.
Return a new React.Node or return undefined, and mutate domProps.
If it returns undefined, the mutated domProps are applied on the default implementation.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/TreeView/index.css'
import '@zippytech/react-toolkit/CheckBox/index.css'

import components from './components-text'

function renderNode(domProps, nodeProps) {
  if (nodeProps.node.label.indexOf('guides') == 0) {
    domProps.style.color = 'red'
  }
}

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      customRenderNode: true
    }
  }
  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          onChange={(customRenderNode) => {
            this.setState({
              customRenderNode
            })
          }}
          checked={this.state.customRenderNode}
        >
          Use custom renderNode
        </CheckBox>
      </div>
      <TreeView
        defaultCollapsedDepth={1}
        renderNode={this.state.customRenderNode? renderNode : undefined}
        dataSource={components}
      />
    </div>
  }
}

export default () => <App />
Fn(menuProps, { nodeProps, props, tree })
default: undefined
Specify this function prop if you want to show a custom Menu component as the context menu for tree nodes. This function prop is called with menuProps as a first param. Either modify those props and set the desired properties on this object (like items) and return undefined, or return the <Menu /> component you want to render.
If the renderNodeContextMenu function prop returns undefined, the default Menu is rendered.
Beware, the Menu has no items by default.
The second param passed to the renderNodeContextMenu function prop is an object with { nodeProps, props, tree }, where nodeProps are the props of the clicked node, props are the computed props of the tree and tree is a reference to the tree instance.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/TreeView/index.css'
import '@zippytech/react-toolkit/CheckBox/index.css'

import components from './components-text'

const renderNodeContextMenu = (menuProps, x) => {
  menuProps.items = [
    {
      label: 'Collapse'
    },
    '-',
    {
      label: 'Expand'
    },
    {
      label: 'Refresh'
    },
    '-',
    {
      label: 'Edit'
    }
  ];
};

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      contextMenu: true
    }
  }
  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          onChange={(contextMenu) => {
            this.setState({
              contextMenu
            })
          }}
          checked={this.state.contextMenu}
        >
          Use context menu
        </CheckBox>
      </div>
      <TreeView
        defaultCollapsedDepth={1}
        renderNodeContextMenu={this.state.contextMenu? renderNodeContextMenu : undefined}
        dataSource={components}
      />
    </div>
  }
}

export default () => <App />
Fn(domProps, nodeProps)
default: undefined
Custom render function for node.label.
For more details on nodeProps see Node Props page.
Return new React.Node or return undefined, and mutate the passed domProps.
If it returns undefined, the mutated domProps are applied on the default implementation.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

const dataSource = [
  {
    label: 'Colors',
    id: 'colors',
    nodes: [
      {
        label: ({ collapsed }) => {
          return collapsed
            ? <span style={{color: 'blue'}}>blue - collapsed</span>
            : <span style={{color: 'red'}}>red - expanded</span>
        },
        id: 'blue'
      },
      {
        label: 'green',
        id: 'green'
      },
    ]
  },
  {
    label: 'Vegetables',
    id: 'vegetables',
    nodes: [
      { label: 'tomatoes', id: 'tomatoes' },
      { label: 'potatoes', id: 'potatoes' },
      { label: 'onion', id: 'onion' },
      { label: 'garlic', id: 'garlic' }
    ]
  }
]

const renderNodeText = (domProps, { node }) => {
  return typeof node.label === 'string' ?
    node.label + '!' :
    <div {...domProps} />
}

function loadNode() {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve([
        { label: 'yellow', id: 'yellow' },
        { label: 'purple', id: 'purple' },
        { label: 'brown', id: 'brown' },
      ])
    }, 100)
  })
}

function isNodeAsync({ path, node }) {
  return node.id == 'green' || path == 'blue'
}

export default () => <TreeView
  isNodeAsync={isNodeAsync}
  idProperty="id"
  defaultCollapsed={{
    blue: true
  }}
  renderNodeText={renderNodeText}
  loadNode={loadNode}
  dataSource={dataSource}
/>
renderNodeText can also be specified for <SearchTreeView /> - see the example below.
import React from 'react'
import SearchTreeView from '@zippytech/react-toolkit/TreeView/SearchTreeView'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/TreeView/index.css'
import '@zippytech/react-toolkit/CheckBox/index.css'
import components from './components-text'

const renderNodeText = (domProps, nodeProps) => {
  if (nodeProps.matchText) {
    return (
      <div>
        {nodeProps.matchText.map(what => {
          return typeof what == 'string'
            ? what
            : <span style={{ background: 'lime' }}>
                {what.match}
              </span>;
        })}
      </div>
    );
  }

  return nodeProps.node.label + '!';
};

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      customRenderNodeText: true
    }
  }
  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          onChange={(customRenderNodeText) => {
            this.setState({
              customRenderNodeText
            })
          }}
          checked={this.state.customRenderNodeText}
        >
          Use custom render for matching nodes
        </CheckBox>
      </div>
      <SearchTreeView
        renderNodeText={this.state.customRenderNodeText? renderNodeText : undefined}
        dataSource={components}
      />
    </div>
  }
}

export default () => <App />
Bool
default: false
When true, right-to-left behaviour will be applied to the <TreeView />.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/TreeView/index.css'
import '@zippytech/react-toolkit/CheckBox/index.css'

import components from './components'

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      rtl: false
    }
  }
  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={this.state.rtl}
          onChange={(rtl) => {
            this.setState({
              rtl
            })
          }}
        >Right-to-left
        </CheckBox>
      </div>
      <TreeView
        rtl={this.state.rtl}
        dataSource={components}
      />
    </div>
  }
}

export default () => <App />
String
default: undefined
Specifies the controlled searchText to use for filtering the <SearchTreeView />.
For uncontrolled behaviour, see defaultSearchText.
Use onSearchTextChange to update the searchText value in response to user actions.
import React from 'react'
import SearchTreeView from '@zippytech/react-toolkit/TreeView/SearchTreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

import components from './components-text'

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      searchText: 'at'
    }
  }
  render() {
    return <div>
      <p>
        Current search text: {this.state.searchText || "none"}.
      </p>

      <SearchTreeView
        searchText={this.state.searchText}
        onSearchTextChange={(searchText) => {
          this.setState({
            searchText
          })
        }}
        dataSource={components}
      />
    </div>
  }
}

export default () => <App />
Object
default: undefined
This prop controls the selection state of the entire <TreeView />. Its keys identify a particular node (see using the path property page), and its values specify whether specific nodes are selected.
In order to show checkboxes for the tree nodes, see enableChecked and checked.
For single selection, see singleSelect.
This is a controlled prop. Use onSelectionChange({ selectedMap }) to react to selection changes in the <TreeView />.
For uncontrolled behaviour, see defaultSelected.
For this prop to have effect enableSelection must be true.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'
import components from './components'

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      selected: {
        "0/0/0/1":true,
        "0/0/0/2":true,
        "0/0/1/1":true,
        "0/0/1/2":true,
        "0/0/1/0":true,
        "1/0":true
      }
    }
  }
  render() {
    return <div>
      <p>Current selection: <code>{JSON.stringify(this.state.selected, null, 2)}</code>.</p>
      <TreeView
        enableSelection
        selected={this.state.selected}
        onSelectionChange={({ selectedMap }) => {
          this.setState({ selected: selectedMap })
        }}
        dataSource={components}
      />
    </div>
  }
}

export default () => <App />
Bool
default: false
Specifies if the selection should be single or multiple. By default, the <TreeView /> is configured with multiple selection, when selection is enabled.
For this prop to have effect enableSelection must be true.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'

import components from './components'

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      selected: {
        "0/0/1/1":true
      },
      enableSelection: true,
      singleSelect: true
    }
  }

  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={this.state.enableSelection}
          onChange={(enableSelection) => {
            this.setState({
              enableSelection
            })
          }}
        >Enable selection
        </CheckBox>
      </div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={this.state.singleSelect}
          onChange={(singleSelect) => {
            this.setState({
              singleSelect
            })
          }}
        >Single select
        </CheckBox>
      </div>
      <p>
          Current selected state: <code>{JSON.stringify(this.state.selected, null, 2)}</code>.
      </p>
      <TreeView
        key={this.state.singleSelect+""}
        selected={this.state.selected}
        enableSelection={this.state.enableSelection}
        onSelectionChange={({ selectedMap }) => {
          this.setState({ selected: selectedMap })
        }}
        singleSelect={this.state.singleSelect}
        dataSource={components}
      />
    </div>
  }
}

export default () => <App />
Bool
default: true
Specifies if a transition effect should be used when collapsing/expanding nodes in the <TreeView />.
For the duration of the transition, see transitionDuration.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/TreeView/index.css'
import '@zippytech/react-toolkit/CheckBox/index.css'

import components from './components'

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      transition: true
    }
  }
  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={this.state.transition}
          onChange={(transition) => {
            this.setState({
              transition
            })
          }}
        >Use expand/collapse transition
        </CheckBox>
      </div>
      <TreeView
        transition={this.state.transition}
        dataSource={components}
      />
    </div>
  }
}

export default () => <App />
Number
default: 300
Specifies the duration of the transition animation when nodes are collapsed/expanded.
Is only applicable when transition=true.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import ComboBox from '@zippytech/react-toolkit/ComboBox'
import '@zippytech/react-toolkit/TreeView/index.css'
import '@zippytech/react-toolkit/CheckBox/index.css'
import '@zippytech/react-toolkit/ComboBox/index.css'

import components from './components'

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      transition: true,
      transitionDuration: 300
    }
  }
  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={this.state.transition}
          onChange={(transition) => {
            this.setState({
              transition
            })
          }}
        >Use expand/collapse transition
        </CheckBox>
      </div>
      <div style={{ marginBottom: 20 }}>
        Transition duration: <ComboBox
          inlineFlex
          style={{ width: 100 }}
          dataSource={[
            { label: '300ms', id: 300 },
            { label: '500ms', id: 500 },
            { label: '700ms', id: 700 }
          ]}
          value={this.state.transitionDuration}
          collapseOnSelect
          multiple={false}
          searchable={false}
          clearIcon={false}
          changeValueOnNavigation
          onChange={(transitionDuration) => {
            this.setState({
              transitionDuration
            })
          }}
        />
      </div>
      <TreeView
        transition={this.state.transition}
        transitionDuration={this.state.transitionDuration}
        dataSource={components}
      />
    </div>
  }
}

export default () => <App />
Bool|String
default: true
Specifies whether to show guidelines for tree nodes or not.
If a string is specified, it's used as the border value for tree lines (since they are implemented as CSS border under the hood). eg: 2px solid blue.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/TreeView/index.css'
import '@zippytech/react-toolkit/CheckBox/index.css'

import components from './components'

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      treeLines: true
    }
  }
  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={this.state.treeLines}
          onChange={(treeLines) => {
            this.setState({
              treeLines
            })
          }}
        >Show tree lines
        </CheckBox>
      </div>
      <TreeView
        treeLines={this.state.treeLines ? '1px dotted red' : false}
        dataSource={components}
      />
    </div>
  }
}

export default () => <App />
Fn(nodeProps)
default: undefined
Called when activeNode changes, eather by clicking a node or by keyboard navigation.
For more details on nodeProps see Node Props page.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/CheckBox/index.css'

import components from './components'

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      enableKeyboardNavigation: true
    }
  }

  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={this.state.enableKeyboardNavigation}
          onChange={(enableKeyboardNavigation) => {
            this.setState({
              enableKeyboardNavigation
            })
          }}
        >Enable keyboard navigation
        </CheckBox>
      </div>
      <p>
          Current active node: {this.state.label || "none"}.
      </p>
      <TreeView
        defaultCollapsedDepth={2}
        onActiveNodeChange={({ node }) => {
          this.setState({
            label: node.label
          })
        }}
        enableKeyboardNavigation={this.state.enableKeyboardNavigation}
        dataSource={components}
      />
    </div>
  }
}

export default () => <App />
Fn({ checkedMap, node, collapsed, ...nodeProps, getUpdatedDataSource })
default: undefined
Called when a node changes checked state.
This function is called with the following params:
  • getUpdatedDataSource: Fn() - a function that acceps a callback function to update the current node that was changed. Have a look at the second example to see how it can be used.
  • checkedMap: Object - represents new checked state of the tree.
  • node: Object - data asociated with the node that changed checked state.
  • nodeProps: Object - props of the node that changed its checked state, see Node Props page for more information.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import CheckBox from '@zippytech/react-toolkit/CheckBox'
import '@zippytech/react-toolkit/TreeView/index.css'
import '@zippytech/react-toolkit/CheckBox/index.css'
import components from './components'

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      enableChecked: true,
      checked: {},
      checkNodesRecursive: true
    }
  }
  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={this.state.enableChecked}
          onChange={(enableChecked) => {
            this.setState({
              enableChecked
            })
          }}
        >Enable checked
        </CheckBox>
      </div>
      <div style={{ marginBottom: 20 }}>
        <CheckBox
          checked={this.state.checkNodesRecursive}
          onChange={(checkNodesRecursive) => {
            this.setState({
              checkNodesRecursive
            })
          }}
        >Check nodes recursive
        </CheckBox>
      </div>
      <p>Current checked state: <code>{JSON.stringify(this.state.checked, null, 2)}</code>.</p>
      <TreeView
        enableChecked={this.state.enableChecked}
        checked={this.state.checked}
        checkNodesRecursive={this.state.checkNodesRecursive}
        onCheckedChange={({ checkedMap }) => {
          this.setState({ checked: checkedMap })
        }}
        dataSource={components}
      />
    </div>
  }
}

export default () => <App />
See the example below which illustrates how getUpdatedDataSource can be used.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

const data = [
  {
    label: 'components:',
    nodes: [
      {
        label: 'DataGrid',
        nodes: [
          { label: 'Getting started' },
          {
            label: 'Configuring columns',
            nodes: [
              { label: 'Normal columns' },
              { label: 'Locked start columns' },
              { label: 'Locked end columns' }
            ]
          },
          { label: 'Using a data source' },
          { label: 'Sorting' },
          { label: 'Keyboard navigation', checked: true },
          { label: 'Filtering', checked: true }
        ]
      },
      {
        label: 'ComboBox',
        nodes: [
          { label: 'Getting started' },
          { label: 'Multiselect' },
          { label: 'Dropdown' },
          { label: 'Autocomplete' },
          { label: 'Styling' }
        ]
      },
      {
        label: 'TreeView',
        nodes: [
          { label: 'Getting started' },
          { label: 'Async nodes' },
          { label: 'Navigation' },
          { label: 'Search TreeView' },
          { label: 'API' }
        ]
      }
    ]
  }
]

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      dataSource: [...data],
      lastUnchecked: null,
      lastChecked: null
    }

    this.isNodeChecked = this.isNodeChecked.bind(this)
    this.onCheckedChange = this.onCheckedChange.bind(this)
  }

  isNodeChecked({ node, checked }) {
    if (node.checked !== undefined) {
      return node.checked
    }

    // make those checked by default
    if (node.label === 'Sorting' || node.label === 'Dropdown') {
      return true
    }

    // return the checked value, as specified for this node by the defaultChecked prop
    return checked
  }

  onCheckedChange({ getUpdatedDataSource, node, checked }) {
    if (checked) {
      this.setState({
        lastChecked: node.label
      })
    } else {
      this.setState({
        lastUnchecked: node.label
      })
    }

    const updateNode = ({ node, checked }) => {
      // we put the checked information on the node itself
      return Object.assign({}, node, { checked })
    }

    const dataSource = getUpdatedDataSource(updateNode)

    this.setState({
      dataSource
    })
  }

  render() {
    return <div>
      <p>{this.state.lastUnchecked ? 'Last unchecked node: ' + this.state.lastUnchecked: 'No node has been unchecked yet'}.</p>
      <p>{this.state.lastChecked ? 'Last checked node: ' + this.state.lastChecked: 'No node has been checked yet'}.</p>
      <TreeView
        enableChecked
        checkNodesRecursive={false}
        defaultChecked={{
          '0/2/0': true,
          '0/2/1': true
        }}
        isNodeChecked={this.isNodeChecked}
        onCheckedChange={this.onCheckedChange}
        dataSource={this.state.dataSource}
      />
      <p>
        DataSource: <code>{JSON.stringify(this.state.dataSource, null, 2)}</code>.
      </p>

    </div>
  }
}

export default () => <App />
Fn({ collapsedMap, getUpdatedDataSource, node, collapsed, ...nodeProps })
default: undefined
Called when a node changes the collapsed state - usually this is triggered by user interaction.
This function is called with the following params:
  • collapsedMap: Object - represents new collapsed state. When using the controlled collapsed prop, this is the value that should be passed back into the collapsed prop.
  • getUpdatedDataSource: Fn()|Object - a function that returns a version of dataSource that has its keys anotated with a collapsed key, that represents the collapsed state of the node.
  • node: Object - data asociated with the node that changed collapsed state.
  • nodeProps: Object - props of the node that changed its collapsed state, see the Node Props page for more information.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

import components from './components';

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      collapsed: {
        '0/0/1': true,
        '0/1': true,
        '0/2': true,
        '0/3': true
      }
    }
  }
  render() {
    return <div>
      <p>Currently collapsed: <code>{JSON.stringify(this.state.collapsed, null, 2)}</code>.</p>
      <TreeView
        collapsed={this.state.collapsed}
        onCollapsedChange={({ collapsedMap: collapsed }) => {
          this.setState({ collapsed })
        }}
        dataSource={components}
      />
    </div>
  }
}

export default () => <App />
Fn(null): void
default: undefined
Called when collapsedDepth changes.
When collapsedDepth is specified, if the user expands/collapses any nodes, onCollapsedDepthChange is called, which should set collapsedDepth to null in order to reflect the new collapsed/expanded state.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'
import components from './components'

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = { collapsedDepth: 1  }
  }
  render() {
    return <TreeView
      collapsedDepth={this.state.collapsedDepth}
      onCollapsedDepthChange={() => this.setState({ collapsedDepth: null })}
      dataSource={components}
    />
  }
}

export default () => <App />
Fn(dataSource)
default: undefined
Called when the dataSource promise resolves. It's called when the dataSource is a Promise or a function returning a Promise. The first param is the Promise resolution value.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

import components from './components'

const dataSource = () => new Promise((resolve) => {
  setTimeout(() => {
    resolve(components)
  }, 1500)
})

export default () => <TreeView
  onDataSourceLoad={(nodes) => console.log(nodes)}
  dataSource={dataSource}
/>
Fn(): node[]
default: undefined
Called when a promise resolves an async node as a result of a call to loadNode or loadNodeOnce.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

const dataSource = [
  {
    label: 'Components',
    nodes: [
      { label: 'DataGrid', nodes: null },
      { label: 'ComboBox', nodes: null },
      { label: 'TreeView', nodes: null },
      { label: 'Button' },
    ]
  },
]

function loadNodeOnce({ node, path }) {
  const nodes = node.label.indexOf('API') != -1 ?
    [
      { label: 'General props' },
      { label: 'Callback props' },
      { label: 'Methods' }
    ]
    :
    [
      { label: 'Using the ' + node.label },
      { label: node.label + ' API', nodes: null }
    ]

  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(nodes)
    }, 500)
  })
}

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      lastLoaded: null
    }

    this.onNodeLoad = this.onNodeLoad.bind(this)
  }

  onNodeLoad(newNodes, { node }) {
    this.setState({
      lastLoaded: node.label
    })
  }

  render() {
    return <div>
      <p>{this.state.lastLoaded ? 'Last async-loaded node: ' + this.state.lastLoaded: 'No async node loaded yet'}</p>
      <TreeView
        onNodeLoad={this.onNodeLoad}
        loadNodeOnce={loadNodeOnce}
        dataSource={dataSource}
      />
    </div>
  }
}

export default () => <App />
Fn(searchText: String)
default: undefined
Called when searchText changes.
Only applies to <SearchTreeView />.
import React from 'react'
import SearchTreeView from '@zippytech/react-toolkit/TreeView/SearchTreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

import components from './components'

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      searchText: 'at'
    }
  }
  render() {
    return <div>
      <p>
        Current search text: {this.state.searchText || "none"}.
      </p>

      <SearchTreeView
        searchText={this.state.searchText}
        onSearchTextChange={(searchText) => {
          this.setState({
            searchText
          })
        }}
        dataSource={components}
      />
    </div>
  }
}

export default () => <App />
Fn({ selectedMap, getUpdatedDataSource, node, collapsed, ...nodeProps })
default: undefined
Called when the <TreeView /> selection changes.
This function is called with the following params:
  • selectedMap: Object - an object with the selected nodes. When using controlled selection, this is the object that should be passed back into the selected prop.
  • getUpdatedDataSource: Fn()|Object - a function that returns a version of dataSource that has its keys anotated with a selected key, that represents the selected state of the node.
  • node: Object - data asociated with the node that triggered the selected state change.
  • nodeProps: Object - props of the node that triggered the selected state change (see the Node Props page for more information).
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'
import components from './components'

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      selected: {
        "0/0/0/1":true,
        "0/0/0/2":true,
        "0/0/1/1":true,
        "0/0/1/2":true,
        "0/0/1/0":true,
        "1/0":true
      }
    }
  }
  render() {
    return <div>
      <p>Current selection: <code>{JSON.stringify(this.state.selected)}</code>.</p>
      <TreeView
        enableSelection
        selected={this.state.selected}
        onSelectionChange={({ selectedMap }) => {
          this.setState({ selected: selectedMap })
        }}
        dataSource={components}
      />
    </div>
  }
}

export default () => <App />
String
default: undefined
A className to be added on the <TreeView /> component node.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

import components from './components'

export default () => <TreeView
  className="tree-view-color-blue"
  dataSource={components}
/>
String|Fn(nodeProps)
default: undefined
Specifies a className to be added on the node content wrapper.
It can also be a function that is called with the nodeProps object, so it can return the className dynamically based on the node checked/selected/collapsed state. For more details on nodeProps see Node Props page.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

import components from './components'

export default () => <TreeView
  defaultCollapsedDepth={1}
  contentClassName={'tree-view-background-light-blue'}
  dataSource={components}
/>
Object|Fn(nodeProps)
default: undefined
Style applied to the wrapper that contains the children of the node. Overwritten by node.contentStyle.
It can also be a function that is called with the nodeProps object, so it can return the style dynamically based on the node checked/selected/collapsed state. For more details on nodeProps see Node Props page.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

import components from './components'

export default () => <TreeView
  defaultCollapsedDepth={1}
  contentStyle={{ background: '#ffece2' }}
  dataSource={components}
/>
String|Fn(nodeProps)
default: undefined
Specifies a className to be added on the DOM element rendering the label.
It can also be a function that is called with the nodeProps object, so it can return the label className dynamically based on the node checked/selected/collapsed state. For more details on nodeProps see Node Props page.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

import components from './components'

export default () => <TreeView
  defaultCollapsedDepth={1}
  labelClassName={({ hasChildren }) => hasChildren ? "tree-view-background-light-blue": ''}
  dataSource={components}
/>
Object|Fn(nodeProps)
default: undefined
A style object applied to the node label/text. NOT applied to the wrapper that contains the children of the node. This is overwritten by node.labelStyle.
For more details on nodeProps see Node Props page.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

import components from './components'

function labelStyle(nodeProps) {
  if (nodeProps.collapsed) {
    return { background: '#ffece2' }
  }
  return { background: '#e2f3ff' }
}

export default () => <TreeView
  defaultCollapsedDepth={1}
  labelStyle={labelStyle}
  dataSource={components}
/>
String|Fn(nodeProps)
default: undefined
Specifies a className to be added on DOM element for the specific node.
It can also be a function that is called with the nodeProps object, so it can return the className dynamically based on the node checked/selected/collapsed state. For more details on nodeProps see Node Props page.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

const components = [
  {
    label: <strong>components:</strong>,
    nodes: [
      {
        label: <i>DataGrid</i>,
        className: ({ collapsed }) => !collapsed ? 'tree-view-background-light-blue': '',
        nodes: [
          { label: <i>Getting started</i> },
          {
            label: <i>Configuring columns</i>,
            nodes: [
              { label: <i>Normal columns</i> },
              { label: <i>Locked start columns</i> },
              { label: <i>Locked end columns</i> }
            ]
          },
          { label: <i>Using a data source</i> },
          { label: <i>Sorting</i> },
          { label: <i>Keyboard navigation</i> },
          { label: <i>Filtering</i> },
        ]
      },
      {
        label: <i>ComboBox</i>,
        nodes: [
          { label: <i>Getting started</i> },
          { label: <i>Multiselect</i> },
          { label: <i>Dropdown</i> },
          { label: <i>Autocomplete</i> },
          { label: <i>Styling</i> }
        ]
      },
      {
        label: <i>TreeView</i>,
        nodes: [
          { label: <i>Getting started</i> },
          { label: <i>Async nodes</i> },
          { label: <i>Navigation</i> },
          { label: <i>Search TreeView</i> },
          { label: <i>API</i> }
        ]
      },
      {
        label: <i>Button</i>,
        nodes: [
          {
            label: <i>DropdownButton</i>,
            nodes: [
              { label: <i>Getting started</i> },
              { label: <i>Callback props</i> },
              { label: <i>API</i> }
            ]
          },
          { label: <i>SplitButton</i> },
          { label: <i>GroupButton</i> }
        ]
      }
    ]
  },
  {
    label: <strong>guides:</strong>,
    nodes: [
      { label: <i>Getting started with React</i> },
      { label: <i>Understanding React state</i> },
      { label: <i>Using Redux for state management</i> }
    ]
  }
];

export default () => <TreeView
  defaultCollapsedDepth={2}
  dataSource={components}
/>
String
default: undefined
Specifies a className to be added on the node content wrapper for the specific node on which it is defined.
Overwrites contentClassName.
It can also be a function that is called with the nodeProps object, so it can return the content className dynamically based on the node checked/selected/collapsed state. For more details on nodeProps see Node Props page.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

const components = [
  {
    label: <strong>components:</strong>,
    nodes: [
      {
        label: <i>DataGrid</i>,
        contentClassName: (nodeProps) => 'tree-view-background-light-blue',
        nodes: [
          { label: <i>Getting started</i> },
          {
            label: <i>Configuring columns</i>,
            nodes: [
              { label: <i>Normal columns</i> },
              { label: <i>Locked start columns</i> },
              { label: <i>Locked end columns</i> }
            ]
          },
          { label: <i>Using a data source</i> },
          { label: <i>Sorting</i> },
          { label: <i>Keyboard navigation</i> },
          { label: <i>Filtering</i> },
        ]
      },
      {
        label: <i>ComboBox</i>,
        nodes: [
          { label: <i>Getting started</i> },
          { label: <i>Multiselect</i> },
          { label: <i>Dropdown</i> },
          { label: <i>Autocomplete</i> },
          { label: <i>Styling</i> }
        ]
      },
      {
        label: <i>TreeView</i>,
        nodes: [
          { label: <i>Getting started</i> },
          { label: <i>Async nodes</i> },
          { label: <i>Navigation</i> },
          { label: <i>Search TreeView</i> },
          { label: <i>API</i> }
        ]
      },
      {
        label: <i>Button</i>,
        nodes: [
          {
            label: <i>DropdownButton</i>,
            nodes: [
              { label: <i>Getting started</i> },
              { label: <i>Callback props</i> },
              { label: <i>API</i> }
            ]
          },
          { label: <i>SplitButton</i> },
          { label: <i>GroupButton</i> }
        ]
      }
    ]
  },
  {
    label: <strong>guides:</strong>,
    contentClassName: 'tree-view-background-light-blue',
    nodes: [
      { label: <i>Getting started with React</i> },
      { label: <i>Understanding React state</i> },
      { label: <i>Using Redux for state management</i> }
    ]
  }
];

export default () => <TreeView
  enableHoverStyle={false}
  defaultCollapsedDepth={2}
  dataSource={components}
/>
ClassName added the div that wraps it's nodes.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

const colors = [
  {
    label: <strong>colors:</strong>,
    contentClassName: 'tree-view-background-light-blue',
    nodes: [
      { label: 'red' },
      { label: 'blue' },
      { label: 'orange' },
      { label: 'violet' }
    ]
  }
];

export default () => <div>
  <TreeView
    dataSource={colors}
  />
</div>
Object|Fn(nodeProps): Object
default: undefined
Specifies a style object to be added on the DOM element that wraps the node content.
Overwrites contentStyle.
It can also be a function that is called with the nodeProps object, so it can return the node content style dynamically based on the node checked/selected/collapsed state. For more details on nodeProps see Node Props page.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

const components = [
  {
    label: <strong>components:</strong>,
    nodes: [
      {
        label: <i>DataGrid</i>,
        contentStyle: ({ collapsed }) => !collapsed ? { color: 'magenta' }: null,
        nodes: [
          { label: <i>Getting started</i> },
          {
            label: <i>Configuring columns</i>,
            nodes: [
              { label: <i>Normal columns</i> },
              { label: <i>Locked start columns</i> },
              { label: <i>Locked end columns</i> }
            ]
          },
          { label: <i>Using a data source</i> },
          { label: <i>Sorting</i> },
          { label: <i>Keyboard navigation</i> },
          { label: <i>Filtering</i> },
        ]
      },
      {
        label: <i>ComboBox</i>,
        nodes: [
          { label: <i>Getting started</i> },
          { label: <i>Multiselect</i> },
          { label: <i>Dropdown</i> },
          { label: <i>Autocomplete</i> },
          { label: <i>Styling</i> }
        ]
      },
      {
        label: <i>TreeView</i>,
        nodes: [
          { label: <i>Getting started</i> },
          { label: <i>Async nodes</i> },
          { label: <i>Navigation</i> },
          { label: <i>Search TreeView</i> },
          { label: <i>API</i> }
        ]
      },
      {
        label: <i>Button</i>,
        nodes: [
          {
            label: <i>DropdownButton</i>,
            nodes: [
              { label: <i>Getting started</i> },
              { label: <i>Callback props</i> },
              { label: <i>API</i> }
            ]
          },
          { label: <i>SplitButton</i> },
          { label: <i>GroupButton</i> }
        ]
      }
    ]
  },
  {
    label: <strong>guides:</strong>,
    contentStyle: { color: 'magenta' },
    nodes: [
      { label: <i>Getting started with React</i> },
      { label: <i>Understanding React state</i> },
      { label: <i>Using Redux for state management</i> }
    ]
  }
];

export default () => <TreeView
  enableHoverStyle={false}
  defaultCollapsedDepth={2}
  dataSource={components}
/>
String|Fn(nodeProps)
default: undefined
Specifies a className to be added on the DOM element rendering the label.
Overwrites labelClassName.
It can also be a function that is called with the nodeProps object, so it can return the label className dynamically based on the node checked/selected/collapsed state. For more details on nodeProps see Node Props page.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

const components = [
  {
    label: <strong>components:</strong>,
    nodes: [
      {
        label: <i>DataGrid</i>,
        labelClassName: ({ collapsed }) => !collapsed ? 'tree-view-background-light-blue': '',
        nodes: [
          { label: <i>Getting started</i> },
          {
            label: <i>Configuring columns</i>,
            nodes: [
              { label: <i>Normal columns</i> },
              { label: <i>Locked start columns</i> },
              { label: <i>Locked end columns</i> }
            ]
          },
          { label: <i>Using a data source</i> },
          { label: <i>Sorting</i> },
          { label: <i>Keyboard navigation</i> },
          { label: <i>Filtering</i> },
        ]
      },
      {
        label: <i>ComboBox</i>,
        nodes: [
          { label: <i>Getting started</i> },
          { label: <i>Multiselect</i> },
          { label: <i>Dropdown</i> },
          { label: <i>Autocomplete</i> },
          { label: <i>Styling</i> }
        ]
      },
      {
        label: <i>TreeView</i>,
        nodes: [
          { label: <i>Getting started</i> },
          { label: <i>Async nodes</i> },
          { label: <i>Navigation</i> },
          { label: <i>Search TreeView</i> },
          { label: <i>API</i> }
        ]
      },
      {
        label: <i>Button</i>,
        nodes: [
          {
            label: <i>DropdownButton</i>,
            nodes: [
              { label: <i>Getting started</i> },
              { label: <i>Callback props</i> },
              { label: <i>API</i> }
            ]
          },
          { label: <i>SplitButton</i> },
          { label: <i>GroupButton</i> }
        ]
      }
    ]
  },
  {
    label: <strong>guides:</strong>,
    labelClassName: 'tree-view-background-light-blue',
    nodes: [
      { label: <i>Getting started with React</i> },
      { label: <i>Understanding React state</i> },
      { label: <i>Using Redux for state management</i> }
    ]
  }
];

export default () => <TreeView
  enableHoverStyle={false}
  defaultCollapsedDepth={2}
  dataSource={components}
/>
Object|Fn(nodeProps): Object
default: undefined
Specifies a style object to be added on the DOM element that wraps the node.label.
Overwrites labelStyle.
It can also be a function that is called with the nodeProps object, so it can return the label style dynamically based on the node checked/selected/collapsed state. For more details on nodeProps see Node Props page.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

const components = [
  {
    label: <strong>components:</strong>,
    nodes: [
      {
        label: <i>DataGrid</i>,
        labelStyle: ({ collapsed }) => !collapsed ? { color: 'magenta' }: null,
        nodes: [
          { label: <i>Getting started</i> },
          {
            label: <i>Configuring columns</i>,
            nodes: [
              { label: <i>Normal columns</i> },
              { label: <i>Locked start columns</i> },
              { label: <i>Locked end columns</i> }
            ]
          },
          { label: <i>Using a data source</i> },
          { label: <i>Sorting</i> },
          { label: <i>Keyboard navigation</i> },
          { label: <i>Filtering</i> },
        ]
      },
      {
        label: <i>ComboBox</i>,
        nodes: [
          { label: <i>Getting started</i> },
          { label: <i>Multiselect</i> },
          { label: <i>Dropdown</i> },
          { label: <i>Autocomplete</i> },
          { label: <i>Styling</i> }
        ]
      },
      {
        label: <i>TreeView</i>,
        nodes: [
          { label: <i>Getting started</i> },
          { label: <i>Async nodes</i> },
          { label: <i>Navigation</i> },
          { label: <i>Search TreeView</i> },
          { label: <i>API</i> }
        ]
      },
      {
        label: <i>Button</i>,
        nodes: [
          {
            label: <i>DropdownButton</i>,
            nodes: [
              { label: <i>Getting started</i> },
              { label: <i>Callback props</i> },
              { label: <i>API</i> }
            ]
          },
          { label: <i>SplitButton</i> },
          { label: <i>GroupButton</i> }
        ]
      }
    ]
  },
  {
    label: <strong>guides:</strong>,
    labelStyle: { color: 'magenta' },
    nodes: [
      { label: <i>Getting started with React</i> },
      { label: <i>Understanding React state</i> },
      { label: <i>Using Redux for state management</i> }
    ]
  }
];

export default () => <TreeView
  enableHoverStyle={false}
  defaultCollapsedDepth={2}
  dataSource={components}
/>
String|Fn(nodeProps)
default: undefined
Specifies a className to be added on <TreeView /> nodes.
It can also be a function that is called with the nodeProps object, so it can return the node className dynamically based on the node checked/selected/collapsed state. For more details on nodeProps see Node Props page.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

import components from './components'

export default () => <TreeView
  defaultCollapsedDepth={1}
  nodeClassName={({ path }) => path == '1' ? "tree-view-background-light-blue": ''}
  dataSource={components}
/>
Object|Fn(nodeProps)
default: undefined
Specifies an inline style to be added on <TreeView/> nodes.
It can also be a function that is called with the nodeProps object, so it can return the node style dynamically based on the node checked/selected/collapsed state. For more details on nodeProps see Node Props page.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

import components from './components'

const nodeStyle=(nodeProps) => ({ color: nodeProps.collapsed ? 'blue' : 'magenta' })

export default () => <TreeView
  nodeStyle={nodeStyle}
  defaultCollapsedDepth={1}
  dataSource={components}
/>
Object
default: undefined
Specifies a style object to be added on the <TreeView /> body.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

import components from './components'

export default () => <TreeView
  style={{
    border: '1px dashed #e9580a',
    padding: 10
  }}
  dataSource={components}
/>
Most methods use path to identify a node on which the action to take place. For more information see Using the path property page.
Fn()
Object
Checks all nodes. Returns the new checked state, or null if enableChecked=false.
When this is called, onCheckedChange will be called, if defined.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

import Button from '@zippytech/react-toolkit/Button'
import '@zippytech/react-toolkit/Button/index.css'

import components from './components'

class App extends React.Component {
  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <Button onClick={() => {
          const newCheckedState = this.tree.checkAll()
          console.log(newCheckedState)
        }}>
          Check all nodes
        </Button>
      </div>
      <div style={{marginBottom: 20}}>
        <Button onClick={() => {
          const newCheckedState = this.tree.uncheckAll()
          console.log(newCheckedState)
        }}>
          Uncheck all nodes
        </Button>
      </div>
      <TreeView
        enableChecked
        ref={ref => this.tree = ref}
        dataSource={components}
      />
    </div>
  }
}

export default () => <App />
Fn(path: path|id)
Object
Checks the node at the specified path. It returns the new checked state.
When this is called, onCheckedChange will be called, if specified.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

import Button from '@zippytech/react-toolkit/Button'
import '@zippytech/react-toolkit/Button/index.css'

import components from './components'

class App extends React.Component {
  render() {
    return <div>
    <div style={{ marginBottom: 20 }}>
        <Button onClick={() => {
          const newCheckedState = this.tree.checkNode('0/0')
          console.log(newCheckedState)
        }}>
          Check DataGrid node
        </Button>
      </div>
      <div style={{ marginBottom: 20 }}>
        <Button onClick={() => {
          const newCheckedState = this.tree.uncheckNode('0/0')
          console.log(newCheckedState)
        }}>
          Uncheck DataGrid node
        </Button>
      </div>
      <TreeView
        defaultCollapsedDepth={1}
        enableChecked
        ref={ref => this.tree = ref}
        dataSource={components}
      />
    </div>
  }
}

export default () => <App />
Fn()
Object
Collapses all nodes. Returns new collapsed state.
When this is called, onCollapsedChange will be triggered, if specified.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'
import Button from '@zippytech/react-toolkit/Button'
import '@zippytech/react-toolkit/Button/index.css'
import components from './components'

class App extends React.Component {
  render() {
    return <div>
      <div style={{ marginBottom: 20}} >
        <Button onClick={() => {
          const newCollapsedState = this.tree.collapseAll()
          console.log(newCollapsedState)
        }}>
          Collapse all nodes
        </Button>
      </div>
      <div style={{ marginBottom: 20}} >
        <Button onClick={() => {
          const newCollapsedState = this.tree.expandAll()
          console.log(newCollapsedState)
        }}>
          Expand all nodes
        </Button>
      </div>
      <TreeView
        ref={ref => this.tree = ref}
        dataSource={components}
      />
    </div>
  }
}

export default () => <App />
Fn(path: path|id)
Object
Collapses node at specified path. It returns new collapsed state.
When this is called, onCollapsedChange will be triggered, if specified.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'
import Button from '@zippytech/react-toolkit/Button'
import '@zippytech/react-toolkit/Button/index.css'
import components from './components'

class App extends React.Component {
  render() {
    return <div>
      <div style={{ marginBottom: 20}} >
        <Button onClick={() => {
          const newCollapsedState = this.tree.collapseNode('0')
          console.log(newCollapsedState)
        }}>
          Collapse components node
        </Button>
      </div>
      <div style={{ marginBottom: 20}} >
        <Button onClick={() => {
          const newCollapsedState = this.tree.expandNode('0')
          console.log(newCollapsedState)
        }}>
          Expand components node
        </Button>
      </div>
      <TreeView ref={ref => this.tree = ref}
        dataSource={components} />
    </div>
  }
}

export default () => <App />
Fn()
Object
Deselects all nodes. Returns the new selected state or null if enableSelection=false.
When this is called, onSelectionChange will be triggered, if specified.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

import Button from '@zippytech/react-toolkit/Button'
import '@zippytech/react-toolkit/Button/index.css'

import components from './components'

class App extends React.Component {
  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <Button onClick={() => {
          const newSelectedState = this.tree.selectAll()
          console.log(newSelectedState)
        }}>
          Select all
        </Button>
      </div>
      <div style={{ marginBottom: 20 }}>
        <Button onClick={() => {
          const newSelectedState = this.tree.deselectAll()
          console.log(newSelectedState)
        }}>
          Deselect all
        </Button>
      </div>
      <TreeView
        enableSelection
        ref={ref => this.tree = ref}
        dataSource={components}
      />
    </div>
  }
}

export default () => <App />
Fn(path: path|id)
Object
Deselects the node at specified path. Returns the new selected state.
When this is called, onSelectionChange will be triggered, if specified.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'
import Button from '@zippytech/react-toolkit/Button'
import '@zippytech/react-toolkit/Button/index.css'
import components from './components'

class App extends React.Component {
  render() {
    return <div>
      <Button style={{ marginBottom: 20 }}
        onClick={() => this.tree.deselectNode('0/0')}
      >
        Deselect DataGrid node
      </Button>
      <TreeView
        enableSelection
        defaultSelected={{ '0/0': true }}
        ref={ref => this.tree = ref}
        dataSource={components}
      />
    </div>
  }
}

export default () => <App />
Fn()
Object
Expands all nodes. Returns new collapsed state.
When this is called, onCollapsedChange will be triggered, if specified.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'
import Button from '@zippytech/react-toolkit/Button'
import '@zippytech/react-toolkit/Button/index.css'
import components from './components'

class App extends React.Component {
  render() {
    return <div>
      <div style={{ marginBottom: 20}}>
        <Button onClick={() => this.tree.collapseAll()}>
          Collapse all nodes
        </Button>
      </div>
      <div style={{ marginBottom: 20}}>
        <Button onClick={() => this.tree.expandAll()}>
          Expand all nodes
        </Button>
      </div>
      <TreeView
        defaultCollapsedDepth={0}
        ref={ref => this.tree = ref}
        dataSource={components}
      />
    </div>
  }
}

export default () => <App />
Fn(path: path|id)
Object
Expands node at specified path. It returns new collapsed state.
When this is called, onCollapsedChange will be triggered, if specified.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'
import Button from '@zippytech/react-toolkit/Button'
import '@zippytech/react-toolkit/Button/index.css'
import components from './components'

class App extends React.Component {
  render() {
    return <div>
      <div style={{ marginBottom: 20}} >
        <Button onClick={() => this.tree.expandNode('0')}>
          Expand components node
        </Button>
      </div>
      <div style={{ marginBottom: 20}} >
        <Button onClick={() => this.tree.collapseNode('0')}>
          Collapse components node
        </Button>
      </div>
      <TreeView ref={ref => this.tree = ref}
        defaultCollapsedDepth={0}
        dataSource={components} />
    </div>
  }
}

export default () => <App />
Fn()
React.Component
Returns the TreeView component that the <SearchTreeView /> renders.
Applies only for <SearchTreeView />.
import React from 'react'
import SearchTreeView from '@zippytech/react-toolkit/TreeView/SearchTreeView'
import '@zippytech/react-toolkit/TreeView/index.css'
import Button from '@zippytech/react-toolkit/Button'
import '@zippytech/react-toolkit/Button/index.css'
import components from './components'

class App extends React.Component {

  render() {
    return <div>
      <div>
        <Button style={{ marginBottom: 20 }} onClick={() => console.log(
          this.tree.getTreeViewInstance()
        )}>
          console.log(TreeView instance)
        </Button>
      </div>
      <div>
        <Button style={{ marginBottom: 20 }} onClick={() =>
          this.tree.getTreeViewInstance().collapseAll()
        }>
          Collapse the SearchTreeView via getTreeViewInstance
        </Button>
      </div>
      <div>
        <Button style={{ marginBottom: 20 }} onClick={() =>
          this.tree.getTreeViewInstance().expandAll()
        }>
          Expand the SearchTreeView via getTreeViewInstance
        </Button>
      </div>
     <SearchTreeView
       ref={ref => this.tree = ref}
       dataSource={components}
     />
   </div>
  }
}

export default () => <App />
Fn()
Object
Selects all nodes. Returns the new selected state or null if enableSelection=false.
When this is called, onSelectionChange will be triggered, if specified.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

import Button from '@zippytech/react-toolkit/Button'
import '@zippytech/react-toolkit/Button/index.css'

import components from './components'

class App extends React.Component {
  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <Button onClick={() => {
          const newSelectedState = this.tree.selectAll()
          console.log(newSelectedState)
        }}>
          Select all
        </Button>
      </div>
      <div style={{ marginBottom: 20 }}>
        <Button onClick={() => {
          const newSelectedState = this.tree.deselectAll()
          console.log(newSelectedState)
        }}>
          Deselect all
        </Button>
      </div>
      <TreeView
        enableSelection
        ref={ref => this.tree = ref}
        dataSource={components}
      />
    </div>
  }
}

export default () => <App />
Fn(path: path|id)
Object
Selects the node at specified path. Returns new selectedstate.
When this is called, onSelectionChange will be triggered, if specified.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

import Button from '@zippytech/react-toolkit/Button'
import '@zippytech/react-toolkit/Button/index.css'

import components from './components'

class App extends React.Component {
  render() {
    return <div>
      <Button style={{ marginBottom: 20 }} onClick={() => {
        const selectedState = this.tree.selectNode('0/0')
        console.log(selectedState)
      }}>
        Select DataGrid node
      </Button>
      <TreeView
        enableSelection
        defaultCollapsedDepth={1}
        ref={ref => this.tree = ref}
        dataSource={components}
      />
    </div>
  }
}

export default () => <App />
Fn(path: path|id)
activeNode
Changes the activeNode to be the node at the specified path. Returns new activeNode.
When this is called, onActiveNodeChange will be triggered, if specified.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

import Button from '@zippytech/react-toolkit/Button'
import '@zippytech/react-toolkit/Button/index.css'

import components from './components'

class App extends React.Component {
  render() {
    return <div>
      <Button style={{ marginBottom: 20 }} onClick={() => {
        const activeNode = this.tree.setActiveNode('0/0')
        console.log(activeNode)
      }}>
        Set DataGrid to be the active node
      </Button>
      <TreeView
        defaultCollapsedDepth={1}
        ref={ref => this.tree = ref}
        dataSource={components}
      />
    </div>
  }
}

export default () => <App />
Fn(collapsed)
Object
Changes the checked state.
When this is called, onCheckedChange will be called, if specified.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

import Button from '@zippytech/react-toolkit/Button'
import '@zippytech/react-toolkit/Button/index.css'

import components from './components'

class App extends React.Component {
  render() {
    return <div>
      <Button style={{ marginBottom: 20 }} onClick={() => {
        const newCollapsedState = this.tree.setChecked({ '0/0/0': true })
        console.log(newCollapsedState)
      }}>
        Check "DataGrid/Getting started" node
      </Button>
      <TreeView
        enableChecked
        ref={ref => this.tree = ref}
        dataSource={components}
      />
    </div>
  }
}

export default () => <App />
Fn(collapsed)
Object
Changes the collapsed state.
When this is called, onCollapsedChange will be triggered, if specified.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

import Button from '@zippytech/react-toolkit/Button'
import '@zippytech/react-toolkit/Button/index.css'

import components from './components'

class App extends React.Component {
  render() {
    return <div>
      <Button style={{ marginBottom: 20 }} onClick={() => {
        const newCollapsedState = this.tree.setCollapsed({'0/0': true })
        console.log(newCollapsedState)
      }}>
        Collapse the DataGrid node
      </Button>
      <TreeView
        ref={ref => this.tree = ref}
        dataSource={components}
      />
    </div>
  }
}

export default () => <App />
Fn(selected)
Object
Changes the selected state. Returns the new selected state or null if enableSelection=false.
When this is called, onSelectedChange will be triggered, if specified.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

import Button from '@zippytech/react-toolkit/Button'
import '@zippytech/react-toolkit/Button/index.css'

import components from './components'

class App extends React.Component {
  render() {
    return <div>
      <Button style={{ marginBottom: 20 }} onClick={() => {
        const newSelectedState = this.tree.setSelected({'0/0': true, '0/1': true})
        console.log(newSelectedState)
      }}>
        Select DataGrid & ComboBox
      </Button>
      <TreeView
        enableSelection
        defaultCollapsedDepth={1}
        ref={ref => this.tree = ref}
        dataSource={components}
      />
    </div>
  }
}

export default () => <App />
Fn()
Object
Unchecks all nodes. Returns the new checked state, or null if enableChecked=false.
When this is called, onCheckedChange will be called, if specified.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'

import Button from '@zippytech/react-toolkit/Button'
import '@zippytech/react-toolkit/Button/index.css'

import components from './components'

class App extends React.Component {
  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <Button onClick={() => {
          const newCheckedState = this.tree.checkAll()
          console.log(newCheckedState)
        }}>
          Check all nodes
        </Button>
      </div>
      <div style={{marginBottom: 20}}>
        <Button onClick={() => {
          const newCheckedState = this.tree.uncheckAll()
          console.log(newCheckedState)
        }}>
          Uncheck all nodes
        </Button>
      </div>
      <TreeView
        enableChecked
        ref={ref => this.tree = ref}
        dataSource={components}
      />
    </div>
  }
}

export default () => <App />
Fn(path: path|id)
Object
Unchecks the node at the specified path. It returns the new checked state.
When this is called, onCheckedChange will be called, if specified.
import React from 'react'
import TreeView from '@zippytech/react-toolkit/TreeView'
import '@zippytech/react-toolkit/TreeView/index.css'
import Button from '@zippytech/react-toolkit/Button'
import '@zippytech/react-toolkit/Button/index.css'
import components from './components'

class App extends React.Component {
  render() {
    return <div>
      <div style={{ marginBottom: 20 }}>
        <Button onClick={() => {
          const newCheckedState = this.tree.checkNode('0/0')
          console.log(newCheckedState)
        }}>
          Check DataGrid node
        </Button>
      </div>
      <div style={{ marginBottom: 20 }}>
        <Button onClick={() => {
          const newCheckedState = this.tree.uncheckNode('0/0')
          console.log(newCheckedState)
        }}>
          Uncheck DataGrid node
        </Button>
      </div>
      <TreeView
        enableChecked
        ref={ref => this.tree = ref}
        dataSource={components}
      />
    </div>
  }
}

export default () => <App />