# Tree API

Canonical page: https://infinite-table.com/docs/reference/tree-api/

When rendering the `TreeDataSource` component, you can get access to the Tree API by reading it from the [DataSource API](https://infinite-table.com/docs/reference/datasource-api/index.md) [`treeApi`](https://infinite-table.com/docs/reference/datasource-api/index.md#treeApi) property.

```tsx {3}
<DataSource<DATA_TYPE>
  onReady={(api: DataSourceApi<DATA_TYPE>) => {
    api.treeApi // <----
    // treeApi is accessible here
    // you may want to store a reference to it in a ref or somewhere in your app state
    
  }}
/>
```

For updating tree nodes, see the following methods:

- [`updateDataByNodePath`](https://infinite-table.com/docs/reference/datasource-api/index.md#updateDataByNodePath)
- [`removeDataByNodePath`](https://infinite-table.com/docs/reference/datasource-api/index.md#removeDataByNodePath)

### expandAll (`() => void`)

> Expands all the nodes in the tree. See related [`collapseAll`](https://infinite-table.com/docs/reference/tree-api/index.md#collapseAll) prop.

**Example: Expanding all nodes**

```tsx
import {
  DataSourceApi,
  InfiniteTableColumn,
  TreeDataSource,
  TreeGrid,
} from '@infinite-table/infinite-react';
import { useState } from 'react';

type FileSystemNode = {
  id: string;
  name: string;
  type: 'folder' | 'file';
  extension?: string;
  mimeType?: string;
  sizeInKB: number;
  children?: FileSystemNode[];
};

const columns: Record<string, InfiniteTableColumn<FileSystemNode>> = {
  name: { field: 'name', header: 'Name', renderTreeIcon: true },
  type: { field: 'type', header: 'Type' },
  extension: { field: 'extension', header: 'Extension' },
  mimeType: { field: 'mimeType', header: 'Mime Type' },
  size: { field: 'sizeInKB', type: 'number', header: 'Size (KB)' },
};

export default function App() {
  const [dataSourceApi, setDataSourceApi] =
    useState<DataSourceApi<FileSystemNode> | null>();

  return (
    <>
      <TreeDataSource
        onReady={setDataSourceApi}
        nodesKey="children"
        primaryKey="id"
        data={dataSource}
        defaultTreeExpandState={{
          defaultExpanded: true,
          collapsedPaths: [['1', '10'], ['3']],
        }}
      >
        <div
          style={{
            color: 'var(--infinite-cell-color)',
            padding: '10px',
          }}
        >
          <button
            onClick={() => {
              dataSourceApi!.treeApi.expandAll();
            }}
          >
            Expand all
          </button>
          <button
            onClick={() => {
              dataSourceApi!.treeApi.collapseAll();
            }}
          >
            Collapse all
          </button>
        </div>

        <TreeGrid columns={columns} />
      </TreeDataSource>
    </>
  );
}

const dataSource = () => {
  const nodes: FileSystemNode[] = [
    {
      id: '1',
      name: 'Documents',
      sizeInKB: 1200,
      type: 'folder',
      children: [
        {
          id: '10',
          name: 'Private',
          sizeInKB: 100,
          type: 'folder',
          children: [
            {
              id: '100',
              name: 'Report.docx',
              sizeInKB: 210,
              type: 'file',
              extension: 'docx',
              mimeType: 'application/msword',
            },
            {
              id: '101',
              name: 'Vacation.docx',
              sizeInKB: 120,
              type: 'file',
              extension: 'docx',
              mimeType: 'application/msword',
            },
            {
              id: '102',
              name: 'CV.pdf',
              sizeInKB: 108,
              type: 'file',
              extension: 'pdf',
              mimeType: 'application/pdf',
            },
          ],
        },
      ],
    },
    {
      id: '2',
      name: 'Desktop',
      sizeInKB: 1000,
      type: 'folder',
      children: [
        {
          id: '20',
          name: 'unknown.txt',
          extension: 'txt',
          mimeType: 'text/plain',
          sizeInKB: 100,
          type: 'file',
        },
      ],
    },
    {
      id: '3',
      name: 'Media',
      sizeInKB: 1000,
      type: 'folder',
      children: [
        {
          id: '30',
          name: 'Music - empty',
          sizeInKB: 0,
          type: 'folder',
          children: [],
        },
        {
          id: '31',
          name: 'Videos',
          sizeInKB: 5400,
          type: 'folder',
          children: [
            {
              id: '310',
              name: 'Vacation.mp4',
              sizeInKB: 108,
              type: 'file',
              extension: 'mp4',
              mimeType: 'video/mp4',
            },
          ],
        },
      ],
    },
  ];
  return Promise.resolve(nodes);
};
```

### selectAll (`() => void`)

> Selects all the nodes in the tree. See related [`deselectAll`](https://infinite-table.com/docs/reference/tree-api/index.md#deselectAll) prop.

This works if the tree has selection enabled. See [tree selection](https://infinite-table.com/docs/learn/tree-grid/tree-selection.md) for more details.

**Example: Selecting all nodes via Tree API**

```tsx
import {
  DataSourceApi,
  InfiniteTableColumn,
  TreeDataSource,
  TreeGrid,
} from '@infinite-table/infinite-react';
import { useState } from 'react';

type FileSystemNode = {
  id: string;
  name: string;
  type: 'folder' | 'file';
  extension?: string;
  mimeType?: string;
  sizeInKB: number;
  children?: FileSystemNode[];
};

const columns: Record<string, InfiniteTableColumn<FileSystemNode>> = {
  name: {
    field: 'name',
    header: 'Name',
    renderTreeIcon: true,
    renderSelectionCheckBox: true,
  },
  type: { field: 'type', header: 'Type' },
  extension: { field: 'extension', header: 'Extension' },
  mimeType: { field: 'mimeType', header: 'Mime Type' },
  size: { field: 'sizeInKB', type: 'number', header: 'Size (KB)' },
};

export default function App() {
  const [dataSourceApi, setDataSourceApi] =
    useState<DataSourceApi<FileSystemNode> | null>();

  return (
    <>
      <TreeDataSource
        onReady={setDataSourceApi}
        nodesKey="children"
        primaryKey="id"
        data={dataSource}
        defaultTreeSelection={{
          defaultSelection: true,
          deselectedPaths: [['2']],
        }}
      >
        <div
          style={{
            color: 'var(--infinite-cell-color)',
            padding: '10px',
          }}
        >
          <button
            onClick={() => {
              dataSourceApi!.treeApi.selectAll();
            }}
          >
            Select all
          </button>
          <button
            onClick={() => {
              dataSourceApi!.treeApi.deselectAll();
            }}
          >
            Deselect all
          </button>
        </div>

        <TreeGrid columns={columns} />
      </TreeDataSource>
    </>
  );
}

const dataSource = () => {
  const nodes: FileSystemNode[] = [
    {
      id: '1',
      name: 'Documents',
      sizeInKB: 1200,
      type: 'folder',
      children: [
        {
          id: '10',
          name: 'Private',
          sizeInKB: 100,
          type: 'folder',
          children: [
            {
              id: '100',
              name: 'Report.docx',
              sizeInKB: 210,
              type: 'file',
              extension: 'docx',
              mimeType: 'application/msword',
            },
            {
              id: '101',
              name: 'Vacation.docx',
              sizeInKB: 120,
              type: 'file',
              extension: 'docx',
              mimeType: 'application/msword',
            },
            {
              id: '102',
              name: 'CV.pdf',
              sizeInKB: 108,
              type: 'file',
              extension: 'pdf',
              mimeType: 'application/pdf',
            },
          ],
        },
      ],
    },
    {
      id: '2',
      name: 'Desktop',
      sizeInKB: 1000,
      type: 'folder',
      children: [
        {
          id: '20',
          name: 'unknown.txt',
          extension: 'txt',
          mimeType: 'text/plain',
          sizeInKB: 100,
          type: 'file',
        },
      ],
    },
    {
      id: '3',
      name: 'Media',
      sizeInKB: 1000,
      type: 'folder',
      children: [
        {
          id: '30',
          name: 'Music - empty',
          sizeInKB: 0,
          type: 'folder',
          children: [],
        },
        {
          id: '31',
          name: 'Videos',
          sizeInKB: 5400,
          type: 'folder',
          children: [
            {
              id: '310',
              name: 'Vacation.mp4',
              sizeInKB: 108,
              type: 'file',
              extension: 'mp4',
              mimeType: 'video/mp4',
            },
          ],
        },
      ],
    },
  ];
  return Promise.resolve(nodes);
};
```

### selectNode (`(nodePath: NodePath) => void`)

> Selects the node with the given node path. See related [`deselectNode`](https://infinite-table.com/docs/reference/tree-api/index.md#deselectNode) and [`toggleNodeSelection`](https://infinite-table.com/docs/reference/tree-api/index.md#toggleNodeSelection) methods.

**Example: Selecting a node via Tree API**

```tsx
import {
  DataSourceApi,
  InfiniteTableColumn,
  TreeDataSource,
  TreeGrid,
} from '@infinite-table/infinite-react';
import { useState } from 'react';

type FileSystemNode = {
  id: string;
  name: string;
  type: 'folder' | 'file';
  extension?: string;
  mimeType?: string;
  sizeInKB: number;
  children?: FileSystemNode[];
};

const columns: Record<string, InfiniteTableColumn<FileSystemNode>> = {
  name: {
    field: 'name',
    header: 'Name',
    renderTreeIcon: true,
    renderSelectionCheckBox: true,
  },
  type: { field: 'type', header: 'Type' },
  extension: { field: 'extension', header: 'Extension' },
  mimeType: { field: 'mimeType', header: 'Mime Type' },
  size: { field: 'sizeInKB', type: 'number', header: 'Size (KB)' },
};

export default function App() {
  const [dataSourceApi, setDataSourceApi] =
    useState<DataSourceApi<FileSystemNode> | null>();

  const [activeRowIndex, setActiveRowIndex] = useState<number>(0);

  return (
    <>
      <TreeDataSource
        onReady={setDataSourceApi}
        nodesKey="children"
        primaryKey="id"
        data={dataSource}
        defaultTreeSelection={{
          defaultSelection: true,
          deselectedPaths: [['2']],
        }}
      >
        <div
          style={{
            color: 'var(--infinite-cell-color)',
            padding: 5,
            gap: 5,
          }}
        >
          <button
            onClick={() => {
              const nodePath =
                dataSourceApi!.getNodePathByIndex(activeRowIndex);

              if (!nodePath) {
                return;
              }

              dataSourceApi!.treeApi.selectNode(nodePath);
            }}
          >
            Select current active row
          </button>
          <button
            onClick={() => {
              const nodePath =
                dataSourceApi!.getNodePathByIndex(activeRowIndex);

              if (!nodePath) {
                return;
              }

              dataSourceApi!.treeApi.deselectNode(nodePath);
            }}
          >
            Deselect current active row
          </button>
          <button
            onClick={() => {
              const nodePath =
                dataSourceApi!.getNodePathByIndex(activeRowIndex);

              if (!nodePath) {
                return;
              }

              dataSourceApi!.treeApi.toggleNodeSelection(nodePath);
            }}
          >
            Toggle active row selection
          </button>
        </div>

        <TreeGrid
          columns={columns}
          keyboardNavigation="row"
          activeRowIndex={activeRowIndex}
          onActiveRowIndexChange={setActiveRowIndex}
        />
      </TreeDataSource>
    </>
  );
}

const dataSource = () => {
  const nodes: FileSystemNode[] = [
    {
      id: '1',
      name: 'Documents',
      sizeInKB: 1200,
      type: 'folder',
      children: [
        {
          id: '10',
          name: 'Private',
          sizeInKB: 100,
          type: 'folder',
          children: [
            {
              id: '100',
              name: 'Report.docx',
              sizeInKB: 210,
              type: 'file',
              extension: 'docx',
              mimeType: 'application/msword',
            },
            {
              id: '101',
              name: 'Vacation.docx',
              sizeInKB: 120,
              type: 'file',
              extension: 'docx',
              mimeType: 'application/msword',
            },
            {
              id: '102',
              name: 'CV.pdf',
              sizeInKB: 108,
              type: 'file',
              extension: 'pdf',
              mimeType: 'application/pdf',
            },
          ],
        },
      ],
    },
    {
      id: '2',
      name: 'Desktop',
      sizeInKB: 1000,
      type: 'folder',
      children: [
        {
          id: '20',
          name: 'unknown.txt',
          extension: 'txt',
          mimeType: 'text/plain',
          sizeInKB: 100,
          type: 'file',
        },
      ],
    },
    {
      id: '3',
      name: 'Media',
      sizeInKB: 1000,
      type: 'folder',
      children: [
        {
          id: '30',
          name: 'Music - empty',
          sizeInKB: 0,
          type: 'folder',
          children: [],
        },
        {
          id: '31',
          name: 'Videos',
          sizeInKB: 5400,
          type: 'folder',
          children: [
            {
              id: '310',
              name: 'Vacation.mp4',
              sizeInKB: 108,
              type: 'file',
              extension: 'mp4',
              mimeType: 'video/mp4',
            },
          ],
        },
      ],
    },
  ];
  return Promise.resolve(nodes);
};
```

### deselectNode (`(nodePath: NodePath) => void`)

> Deselects the node with the given node path. See related [`selectNode`](https://infinite-table.com/docs/reference/tree-api/index.md#selectNode) and [`toggleNodeSelection`](https://infinite-table.com/docs/reference/tree-api/index.md#toggleNodeSelection) methods.

**Example: Deselecting a node via Tree API**

```tsx
import {
  DataSourceApi,
  InfiniteTableColumn,
  TreeDataSource,
  TreeGrid,
} from '@infinite-table/infinite-react';
import { useState } from 'react';

type FileSystemNode = {
  id: string;
  name: string;
  type: 'folder' | 'file';
  extension?: string;
  mimeType?: string;
  sizeInKB: number;
  children?: FileSystemNode[];
};

const columns: Record<string, InfiniteTableColumn<FileSystemNode>> = {
  name: {
    field: 'name',
    header: 'Name',
    renderTreeIcon: true,
    renderSelectionCheckBox: true,
  },
  type: { field: 'type', header: 'Type' },
  extension: { field: 'extension', header: 'Extension' },
  mimeType: { field: 'mimeType', header: 'Mime Type' },
  size: { field: 'sizeInKB', type: 'number', header: 'Size (KB)' },
};

export default function App() {
  const [dataSourceApi, setDataSourceApi] =
    useState<DataSourceApi<FileSystemNode> | null>();

  const [activeRowIndex, setActiveRowIndex] = useState<number>(0);

  return (
    <>
      <TreeDataSource
        onReady={setDataSourceApi}
        nodesKey="children"
        primaryKey="id"
        data={dataSource}
        defaultTreeSelection={{
          defaultSelection: true,
          deselectedPaths: [['2']],
        }}
      >
        <div
          style={{
            color: 'var(--infinite-cell-color)',
            padding: 5,
            gap: 5,
          }}
        >
          <button
            onClick={() => {
              const nodePath =
                dataSourceApi!.getNodePathByIndex(activeRowIndex);

              if (!nodePath) {
                return;
              }

              dataSourceApi!.treeApi.selectNode(nodePath);
            }}
          >
            Select current active row
          </button>
          <button
            onClick={() => {
              const nodePath =
                dataSourceApi!.getNodePathByIndex(activeRowIndex);

              if (!nodePath) {
                return;
              }

              dataSourceApi!.treeApi.deselectNode(nodePath);
            }}
          >
            Deselect current active row
          </button>
          <button
            onClick={() => {
              const nodePath =
                dataSourceApi!.getNodePathByIndex(activeRowIndex);

              if (!nodePath) {
                return;
              }

              dataSourceApi!.treeApi.toggleNodeSelection(nodePath);
            }}
          >
            Toggle active row selection
          </button>
        </div>

        <TreeGrid
          columns={columns}
          keyboardNavigation="row"
          activeRowIndex={activeRowIndex}
          onActiveRowIndexChange={setActiveRowIndex}
        />
      </TreeDataSource>
    </>
  );
}

const dataSource = () => {
  const nodes: FileSystemNode[] = [
    {
      id: '1',
      name: 'Documents',
      sizeInKB: 1200,
      type: 'folder',
      children: [
        {
          id: '10',
          name: 'Private',
          sizeInKB: 100,
          type: 'folder',
          children: [
            {
              id: '100',
              name: 'Report.docx',
              sizeInKB: 210,
              type: 'file',
              extension: 'docx',
              mimeType: 'application/msword',
            },
            {
              id: '101',
              name: 'Vacation.docx',
              sizeInKB: 120,
              type: 'file',
              extension: 'docx',
              mimeType: 'application/msword',
            },
            {
              id: '102',
              name: 'CV.pdf',
              sizeInKB: 108,
              type: 'file',
              extension: 'pdf',
              mimeType: 'application/pdf',
            },
          ],
        },
      ],
    },
    {
      id: '2',
      name: 'Desktop',
      sizeInKB: 1000,
      type: 'folder',
      children: [
        {
          id: '20',
          name: 'unknown.txt',
          extension: 'txt',
          mimeType: 'text/plain',
          sizeInKB: 100,
          type: 'file',
        },
      ],
    },
    {
      id: '3',
      name: 'Media',
      sizeInKB: 1000,
      type: 'folder',
      children: [
        {
          id: '30',
          name: 'Music - empty',
          sizeInKB: 0,
          type: 'folder',
          children: [],
        },
        {
          id: '31',
          name: 'Videos',
          sizeInKB: 5400,
          type: 'folder',
          children: [
            {
              id: '310',
              name: 'Vacation.mp4',
              sizeInKB: 108,
              type: 'file',
              extension: 'mp4',
              mimeType: 'video/mp4',
            },
          ],
        },
      ],
    },
  ];
  return Promise.resolve(nodes);
};
```

### toggleNodeSelection (`(nodePath: NodePath) => void`)

> Toggles the selection state of the node with the given node path. See related [`selectNode`](https://infinite-table.com/docs/reference/tree-api/index.md#selectNode) and [`deselectNode`](https://infinite-table.com/docs/reference/tree-api/index.md#deselectNode) methods.

**Example: Toggling a node's selection state via Tree API**

```tsx
import {
  DataSourceApi,
  InfiniteTableColumn,
  TreeDataSource,
  TreeGrid,
} from '@infinite-table/infinite-react';
import { useState } from 'react';

type FileSystemNode = {
  id: string;
  name: string;
  type: 'folder' | 'file';
  extension?: string;
  mimeType?: string;
  sizeInKB: number;
  children?: FileSystemNode[];
};

const columns: Record<string, InfiniteTableColumn<FileSystemNode>> = {
  name: {
    field: 'name',
    header: 'Name',
    renderTreeIcon: true,
    renderSelectionCheckBox: true,
  },
  type: { field: 'type', header: 'Type' },
  extension: { field: 'extension', header: 'Extension' },
  mimeType: { field: 'mimeType', header: 'Mime Type' },
  size: { field: 'sizeInKB', type: 'number', header: 'Size (KB)' },
};

export default function App() {
  const [dataSourceApi, setDataSourceApi] =
    useState<DataSourceApi<FileSystemNode> | null>();

  const [activeRowIndex, setActiveRowIndex] = useState<number>(0);

  return (
    <>
      <TreeDataSource
        onReady={setDataSourceApi}
        nodesKey="children"
        primaryKey="id"
        data={dataSource}
        defaultTreeSelection={{
          defaultSelection: true,
          deselectedPaths: [['2']],
        }}
      >
        <div
          style={{
            color: 'var(--infinite-cell-color)',
            padding: 5,
            gap: 5,
          }}
        >
          <button
            onClick={() => {
              const nodePath =
                dataSourceApi!.getNodePathByIndex(activeRowIndex);

              if (!nodePath) {
                return;
              }

              dataSourceApi!.treeApi.selectNode(nodePath);
            }}
          >
            Select current active row
          </button>
          <button
            onClick={() => {
              const nodePath =
                dataSourceApi!.getNodePathByIndex(activeRowIndex);

              if (!nodePath) {
                return;
              }

              dataSourceApi!.treeApi.deselectNode(nodePath);
            }}
          >
            Deselect current active row
          </button>
          <button
            onClick={() => {
              const nodePath =
                dataSourceApi!.getNodePathByIndex(activeRowIndex);

              if (!nodePath) {
                return;
              }

              dataSourceApi!.treeApi.toggleNodeSelection(nodePath);
            }}
          >
            Toggle active row selection
          </button>
        </div>

        <TreeGrid
          columns={columns}
          keyboardNavigation="row"
          activeRowIndex={activeRowIndex}
          onActiveRowIndexChange={setActiveRowIndex}
        />
      </TreeDataSource>
    </>
  );
}

const dataSource = () => {
  const nodes: FileSystemNode[] = [
    {
      id: '1',
      name: 'Documents',
      sizeInKB: 1200,
      type: 'folder',
      children: [
        {
          id: '10',
          name: 'Private',
          sizeInKB: 100,
          type: 'folder',
          children: [
            {
              id: '100',
              name: 'Report.docx',
              sizeInKB: 210,
              type: 'file',
              extension: 'docx',
              mimeType: 'application/msword',
            },
            {
              id: '101',
              name: 'Vacation.docx',
              sizeInKB: 120,
              type: 'file',
              extension: 'docx',
              mimeType: 'application/msword',
            },
            {
              id: '102',
              name: 'CV.pdf',
              sizeInKB: 108,
              type: 'file',
              extension: 'pdf',
              mimeType: 'application/pdf',
            },
          ],
        },
      ],
    },
    {
      id: '2',
      name: 'Desktop',
      sizeInKB: 1000,
      type: 'folder',
      children: [
        {
          id: '20',
          name: 'unknown.txt',
          extension: 'txt',
          mimeType: 'text/plain',
          sizeInKB: 100,
          type: 'file',
        },
      ],
    },
    {
      id: '3',
      name: 'Media',
      sizeInKB: 1000,
      type: 'folder',
      children: [
        {
          id: '30',
          name: 'Music - empty',
          sizeInKB: 0,
          type: 'folder',
          children: [],
        },
        {
          id: '31',
          name: 'Videos',
          sizeInKB: 5400,
          type: 'folder',
          children: [
            {
              id: '310',
              name: 'Vacation.mp4',
              sizeInKB: 108,
              type: 'file',
              extension: 'mp4',
              mimeType: 'video/mp4',
            },
          ],
        },
      ],
    },
  ];
  return Promise.resolve(nodes);
};
```

### deselectAll (`() => void`)

> Deselects all the nodes in the tree. See related [`selectAll`](https://infinite-table.com/docs/reference/tree-api/index.md#selectAll) prop.

This works if the tree has selection enabled. See [tree selection](https://infinite-table.com/docs/learn/tree-grid/tree-selection.md) for more details.

**Example: Deselecting all nodes via Tree API**

```tsx
import {
  DataSourceApi,
  InfiniteTableColumn,
  TreeDataSource,
  TreeGrid,
} from '@infinite-table/infinite-react';
import { useState } from 'react';

type FileSystemNode = {
  id: string;
  name: string;
  type: 'folder' | 'file';
  extension?: string;
  mimeType?: string;
  sizeInKB: number;
  children?: FileSystemNode[];
};

const columns: Record<string, InfiniteTableColumn<FileSystemNode>> = {
  name: {
    field: 'name',
    header: 'Name',
    renderTreeIcon: true,
    renderSelectionCheckBox: true,
  },
  type: { field: 'type', header: 'Type' },
  extension: { field: 'extension', header: 'Extension' },
  mimeType: { field: 'mimeType', header: 'Mime Type' },
  size: { field: 'sizeInKB', type: 'number', header: 'Size (KB)' },
};

export default function App() {
  const [dataSourceApi, setDataSourceApi] =
    useState<DataSourceApi<FileSystemNode> | null>();

  return (
    <>
      <TreeDataSource
        onReady={setDataSourceApi}
        nodesKey="children"
        primaryKey="id"
        data={dataSource}
        defaultTreeSelection={{
          defaultSelection: true,
          deselectedPaths: [['2']],
        }}
      >
        <div
          style={{
            color: 'var(--infinite-cell-color)',
            padding: '10px',
          }}
        >
          <button
            onClick={() => {
              dataSourceApi!.treeApi.selectAll();
            }}
          >
            Select all
          </button>
          <button
            onClick={() => {
              dataSourceApi!.treeApi.deselectAll();
            }}
          >
            Deselect all
          </button>
        </div>

        <TreeGrid columns={columns} />
      </TreeDataSource>
    </>
  );
}

const dataSource = () => {
  const nodes: FileSystemNode[] = [
    {
      id: '1',
      name: 'Documents',
      sizeInKB: 1200,
      type: 'folder',
      children: [
        {
          id: '10',
          name: 'Private',
          sizeInKB: 100,
          type: 'folder',
          children: [
            {
              id: '100',
              name: 'Report.docx',
              sizeInKB: 210,
              type: 'file',
              extension: 'docx',
              mimeType: 'application/msword',
            },
            {
              id: '101',
              name: 'Vacation.docx',
              sizeInKB: 120,
              type: 'file',
              extension: 'docx',
              mimeType: 'application/msword',
            },
            {
              id: '102',
              name: 'CV.pdf',
              sizeInKB: 108,
              type: 'file',
              extension: 'pdf',
              mimeType: 'application/pdf',
            },
          ],
        },
      ],
    },
    {
      id: '2',
      name: 'Desktop',
      sizeInKB: 1000,
      type: 'folder',
      children: [
        {
          id: '20',
          name: 'unknown.txt',
          extension: 'txt',
          mimeType: 'text/plain',
          sizeInKB: 100,
          type: 'file',
        },
      ],
    },
    {
      id: '3',
      name: 'Media',
      sizeInKB: 1000,
      type: 'folder',
      children: [
        {
          id: '30',
          name: 'Music - empty',
          sizeInKB: 0,
          type: 'folder',
          children: [],
        },
        {
          id: '31',
          name: 'Videos',
          sizeInKB: 5400,
          type: 'folder',
          children: [
            {
              id: '310',
              name: 'Vacation.mp4',
              sizeInKB: 108,
              type: 'file',
              extension: 'mp4',
              mimeType: 'video/mp4',
            },
          ],
        },
      ],
    },
  ];
  return Promise.resolve(nodes);
};
```

### collapseAll (`() => void`)

> Collapses all the nodes in the tree. See related [`expandAll`](https://infinite-table.com/docs/reference/tree-api/index.md#expandAll) prop.

**Example: Collapsing all nodes**

```tsx
import {
  DataSourceApi,
  InfiniteTableColumn,
  TreeDataSource,
  TreeGrid,
} from '@infinite-table/infinite-react';
import { useState } from 'react';

type FileSystemNode = {
  id: string;
  name: string;
  type: 'folder' | 'file';
  extension?: string;
  mimeType?: string;
  sizeInKB: number;
  children?: FileSystemNode[];
};

const columns: Record<string, InfiniteTableColumn<FileSystemNode>> = {
  name: { field: 'name', header: 'Name', renderTreeIcon: true },
  type: { field: 'type', header: 'Type' },
  extension: { field: 'extension', header: 'Extension' },
  mimeType: { field: 'mimeType', header: 'Mime Type' },
  size: { field: 'sizeInKB', type: 'number', header: 'Size (KB)' },
};

export default function App() {
  const [dataSourceApi, setDataSourceApi] =
    useState<DataSourceApi<FileSystemNode> | null>();

  return (
    <>
      <TreeDataSource
        onReady={setDataSourceApi}
        nodesKey="children"
        primaryKey="id"
        data={dataSource}
        defaultTreeExpandState={{
          defaultExpanded: true,
          collapsedPaths: [['1', '10'], ['3']],
        }}
      >
        <div
          style={{
            color: 'var(--infinite-cell-color)',
            padding: '10px',
          }}
        >
          <button
            onClick={() => {
              dataSourceApi!.treeApi.expandAll();
            }}
          >
            Expand all
          </button>
          <button
            onClick={() => {
              dataSourceApi!.treeApi.collapseAll();
            }}
          >
            Collapse all
          </button>
        </div>

        <TreeGrid columns={columns} />
      </TreeDataSource>
    </>
  );
}

const dataSource = () => {
  const nodes: FileSystemNode[] = [
    {
      id: '1',
      name: 'Documents',
      sizeInKB: 1200,
      type: 'folder',
      children: [
        {
          id: '10',
          name: 'Private',
          sizeInKB: 100,
          type: 'folder',
          children: [
            {
              id: '100',
              name: 'Report.docx',
              sizeInKB: 210,
              type: 'file',
              extension: 'docx',
              mimeType: 'application/msword',
            },
            {
              id: '101',
              name: 'Vacation.docx',
              sizeInKB: 120,
              type: 'file',
              extension: 'docx',
              mimeType: 'application/msword',
            },
            {
              id: '102',
              name: 'CV.pdf',
              sizeInKB: 108,
              type: 'file',
              extension: 'pdf',
              mimeType: 'application/pdf',
            },
          ],
        },
      ],
    },
    {
      id: '2',
      name: 'Desktop',
      sizeInKB: 1000,
      type: 'folder',
      children: [
        {
          id: '20',
          name: 'unknown.txt',
          extension: 'txt',
          mimeType: 'text/plain',
          sizeInKB: 100,
          type: 'file',
        },
      ],
    },
    {
      id: '3',
      name: 'Media',
      sizeInKB: 1000,
      type: 'folder',
      children: [
        {
          id: '30',
          name: 'Music - empty',
          sizeInKB: 0,
          type: 'folder',
          children: [],
        },
        {
          id: '31',
          name: 'Videos',
          sizeInKB: 5400,
          type: 'folder',
          children: [
            {
              id: '310',
              name: 'Vacation.mp4',
              sizeInKB: 108,
              type: 'file',
              extension: 'mp4',
              mimeType: 'video/mp4',
            },
          ],
        },
      ],
    },
  ];
  return Promise.resolve(nodes);
};
```

### isNodeExpanded (`(nodePath: NodePath) => boolean`)

> Returns `true` if the node is expanded, `false` otherwise.

**Example: Checking if a node is expanded**

```tsx
import {
  DataSourceApi,
  InfiniteTableColumn,
  TreeDataSource,
  TreeGrid,
} from '@infinite-table/infinite-react';
import { useState } from 'react';

type FileSystemNode = {
  id: string;
  name: string;
  type: 'folder' | 'file';
  extension?: string;
  mimeType?: string;
  sizeInKB: number;
  children?: FileSystemNode[];
};

const columns: Record<string, InfiniteTableColumn<FileSystemNode>> = {
  name: { field: 'name', header: 'Name', renderTreeIcon: true },
  type: { field: 'type', header: 'Type' },
  extension: { field: 'extension', header: 'Extension' },
  mimeType: { field: 'mimeType', header: 'Mime Type' },
  size: { field: 'sizeInKB', type: 'number', header: 'Size (KB)' },
};

export default function App() {
  const [dataSourceApi, setDataSourceApi] =
    useState<DataSourceApi<FileSystemNode> | null>();

  const [activeRowIndex, setActiveRowIndex] = useState<number>(0);

  return (
    <>
      <TreeDataSource
        onReady={setDataSourceApi}
        nodesKey="children"
        primaryKey="id"
        data={dataSource}
        defaultTreeExpandState={{
          defaultExpanded: true,
          collapsedPaths: [['1', '10'], ['3']],
        }}
      >
        <div
          style={{
            color: 'var(--infinite-cell-color)',
            padding: '10px',
          }}
        >
          <button
            onClick={() => {
              const rowInfo = dataSourceApi!.getRowInfoByIndex(activeRowIndex);
              if (!rowInfo || !rowInfo.isTreeNode || !rowInfo.isParentNode) {
                return;
              }
              if (dataSourceApi!.treeApi.isNodeExpanded(rowInfo.nodePath)) {
                dataSourceApi!.treeApi.collapseNode(rowInfo.nodePath);
              } else {
                dataSourceApi!.treeApi.expandNode(rowInfo.nodePath);
              }
            }}
          >
            Toggle current node
          </button>
          <button
            onClick={() => {
              dataSourceApi!.treeApi.expandAll();
            }}
          >
            Expand all
          </button>
          <button
            onClick={() => {
              dataSourceApi!.treeApi.collapseAll();
            }}
          >
            Collapse all
          </button>
        </div>

        <TreeGrid
          columns={columns}
          keyboardNavigation="row"
          activeRowIndex={activeRowIndex}
          onActiveRowIndexChange={setActiveRowIndex}
        />
      </TreeDataSource>
    </>
  );
}

const dataSource = () => {
  const nodes: FileSystemNode[] = [
    {
      id: '1',
      name: 'Documents',
      sizeInKB: 1200,
      type: 'folder',
      children: [
        {
          id: '10',
          name: 'Private',
          sizeInKB: 100,
          type: 'folder',
          children: [
            {
              id: '100',
              name: 'Report.docx',
              sizeInKB: 210,
              type: 'file',
              extension: 'docx',
              mimeType: 'application/msword',
            },
            {
              id: '101',
              name: 'Vacation.docx',
              sizeInKB: 120,
              type: 'file',
              extension: 'docx',
              mimeType: 'application/msword',
            },
            {
              id: '102',
              name: 'CV.pdf',
              sizeInKB: 108,
              type: 'file',
              extension: 'pdf',
              mimeType: 'application/pdf',
            },
          ],
        },
      ],
    },
    {
      id: '2',
      name: 'Desktop',
      sizeInKB: 1000,
      type: 'folder',
      children: [
        {
          id: '20',
          name: 'unknown.txt',
          extension: 'txt',
          mimeType: 'text/plain',
          sizeInKB: 100,
          type: 'file',
        },
      ],
    },
    {
      id: '3',
      name: 'Media',
      sizeInKB: 1000,
      type: 'folder',
      children: [
        {
          id: '30',
          name: 'Music - empty',
          sizeInKB: 0,
          type: 'folder',
          children: [],
        },
        {
          id: '31',
          name: 'Videos',
          sizeInKB: 5400,
          type: 'folder',
          children: [
            {
              id: '310',
              name: 'Vacation.mp4',
              sizeInKB: 108,
              type: 'file',
              extension: 'mp4',
              mimeType: 'video/mp4',
            },
          ],
        },
      ],
    },
  ];
  return Promise.resolve(nodes);
};
```

### toggleNode (`(nodePath: NodePath, options?: {force?: boolean}) => void`)

> Toggles the node with the give node path.

If the node at the given path is expanded, it will be collapsed and vice versa.

See related [`expandNode`](https://infinite-table.com/docs/reference/tree-api/index.md#expandNode) and [`collapseNode`](https://infinite-table.com/docs/reference/tree-api/index.md#collapseNode) methods.

### expandNode (`(nodePath: NodePath, options?: {force?: boolean}) => void`)

> Expands the node with the given node path. See related [`collapseNode`](https://infinite-table.com/docs/reference/tree-api/index.md#collapseNode) and [`toggleNode`](https://infinite-table.com/docs/reference/tree-api/index.md#toggleNode) methods.

Expands the node. Does not affect other child nodes.

**Example: Expanding a node**

```tsx
import {
  DataSourceApi,
  InfiniteTableColumn,
  TreeDataSource,
  TreeGrid,
} from '@infinite-table/infinite-react';
import { useState } from 'react';

type FileSystemNode = {
  id: string;
  name: string;
  type: 'folder' | 'file';
  extension?: string;
  mimeType?: string;
  sizeInKB: number;
  children?: FileSystemNode[];
};

const columns: Record<string, InfiniteTableColumn<FileSystemNode>> = {
  name: { field: 'name', header: 'Name', renderTreeIcon: true },
  type: { field: 'type', header: 'Type' },
  extension: { field: 'extension', header: 'Extension' },
  mimeType: { field: 'mimeType', header: 'Mime Type' },
  size: { field: 'sizeInKB', type: 'number', header: 'Size (KB)' },
};

export default function App() {
  const [dataSourceApi, setDataSourceApi] =
    useState<DataSourceApi<FileSystemNode> | null>();

  const [activeRowIndex, setActiveRowIndex] = useState<number>(0);

  return (
    <>
      <TreeDataSource
        onReady={setDataSourceApi}
        nodesKey="children"
        primaryKey="id"
        data={dataSource}
        defaultTreeExpandState={{
          defaultExpanded: true,
          collapsedPaths: [['1', '10'], ['3']],
        }}
      >
        <div
          style={{
            color: 'var(--infinite-cell-color)',
            padding: '10px',
          }}
        >
          <button
            onClick={() => {
              const rowInfo = dataSourceApi!.getRowInfoByIndex(activeRowIndex);
              if (!rowInfo || !rowInfo.isTreeNode || !rowInfo.isParentNode) {
                return;
              }
              if (dataSourceApi!.treeApi.isNodeExpanded(rowInfo.nodePath)) {
                dataSourceApi!.treeApi.collapseNode(rowInfo.nodePath);
              } else {
                dataSourceApi!.treeApi.expandNode(rowInfo.nodePath);
              }
            }}
          >
            Toggle current node
          </button>
          <button
            onClick={() => {
              dataSourceApi!.treeApi.expandAll();
            }}
          >
            Expand all
          </button>
          <button
            onClick={() => {
              dataSourceApi!.treeApi.collapseAll();
            }}
          >
            Collapse all
          </button>
        </div>

        <TreeGrid
          columns={columns}
          keyboardNavigation="row"
          activeRowIndex={activeRowIndex}
          onActiveRowIndexChange={setActiveRowIndex}
        />
      </TreeDataSource>
    </>
  );
}

const dataSource = () => {
  const nodes: FileSystemNode[] = [
    {
      id: '1',
      name: 'Documents',
      sizeInKB: 1200,
      type: 'folder',
      children: [
        {
          id: '10',
          name: 'Private',
          sizeInKB: 100,
          type: 'folder',
          children: [
            {
              id: '100',
              name: 'Report.docx',
              sizeInKB: 210,
              type: 'file',
              extension: 'docx',
              mimeType: 'application/msword',
            },
            {
              id: '101',
              name: 'Vacation.docx',
              sizeInKB: 120,
              type: 'file',
              extension: 'docx',
              mimeType: 'application/msword',
            },
            {
              id: '102',
              name: 'CV.pdf',
              sizeInKB: 108,
              type: 'file',
              extension: 'pdf',
              mimeType: 'application/pdf',
            },
          ],
        },
      ],
    },
    {
      id: '2',
      name: 'Desktop',
      sizeInKB: 1000,
      type: 'folder',
      children: [
        {
          id: '20',
          name: 'unknown.txt',
          extension: 'txt',
          mimeType: 'text/plain',
          sizeInKB: 100,
          type: 'file',
        },
      ],
    },
    {
      id: '3',
      name: 'Media',
      sizeInKB: 1000,
      type: 'folder',
      children: [
        {
          id: '30',
          name: 'Music - empty',
          sizeInKB: 0,
          type: 'folder',
          children: [],
        },
        {
          id: '31',
          name: 'Videos',
          sizeInKB: 5400,
          type: 'folder',
          children: [
            {
              id: '310',
              name: 'Vacation.mp4',
              sizeInKB: 108,
              type: 'file',
              extension: 'mp4',
              mimeType: 'video/mp4',
            },
          ],
        },
      ],
    },
  ];
  return Promise.resolve(nodes);
};
```

If `options.force` is `true`, the node will be expanded even if [`isNodeReadOnly`](https://infinite-table.com/docs/reference/datasource-props/index.md#isNodeReadOnly) is `true` for the given node.

### collapseNode (`(nodePath: NodePath, options?: {force?: boolean}) => void`)

> Collapses the node with the given node path. See related [`expandNode`](https://infinite-table.com/docs/reference/tree-api/index.md#expandNode) and [`toggleNode`](https://infinite-table.com/docs/reference/tree-api/index.md#toggleNode) methods.

Collapses the node. Does not affect other child nodes.

**Example: Collapsing a node**

```tsx
import {
  DataSourceApi,
  InfiniteTableColumn,
  TreeDataSource,
  TreeGrid,
} from '@infinite-table/infinite-react';
import { useState } from 'react';

type FileSystemNode = {
  id: string;
  name: string;
  type: 'folder' | 'file';
  extension?: string;
  mimeType?: string;
  sizeInKB: number;
  children?: FileSystemNode[];
};

const columns: Record<string, InfiniteTableColumn<FileSystemNode>> = {
  name: { field: 'name', header: 'Name', renderTreeIcon: true },
  type: { field: 'type', header: 'Type' },
  extension: { field: 'extension', header: 'Extension' },
  mimeType: { field: 'mimeType', header: 'Mime Type' },
  size: { field: 'sizeInKB', type: 'number', header: 'Size (KB)' },
};

export default function App() {
  const [dataSourceApi, setDataSourceApi] =
    useState<DataSourceApi<FileSystemNode> | null>();

  const [activeRowIndex, setActiveRowIndex] = useState<number>(0);

  return (
    <>
      <TreeDataSource
        onReady={setDataSourceApi}
        nodesKey="children"
        primaryKey="id"
        data={dataSource}
        defaultTreeExpandState={{
          defaultExpanded: true,
          collapsedPaths: [['1', '10'], ['3']],
        }}
      >
        <div
          style={{
            color: 'var(--infinite-cell-color)',
            padding: '10px',
          }}
        >
          <button
            onClick={() => {
              const rowInfo = dataSourceApi!.getRowInfoByIndex(activeRowIndex);
              if (!rowInfo || !rowInfo.isTreeNode || !rowInfo.isParentNode) {
                return;
              }
              if (dataSourceApi!.treeApi.isNodeExpanded(rowInfo.nodePath)) {
                dataSourceApi!.treeApi.collapseNode(rowInfo.nodePath);
              } else {
                dataSourceApi!.treeApi.expandNode(rowInfo.nodePath);
              }
            }}
          >
            Toggle current node
          </button>
          <button
            onClick={() => {
              dataSourceApi!.treeApi.expandAll();
            }}
          >
            Expand all
          </button>
          <button
            onClick={() => {
              dataSourceApi!.treeApi.collapseAll();
            }}
          >
            Collapse all
          </button>
        </div>

        <TreeGrid
          columns={columns}
          keyboardNavigation="row"
          activeRowIndex={activeRowIndex}
          onActiveRowIndexChange={setActiveRowIndex}
        />
      </TreeDataSource>
    </>
  );
}

const dataSource = () => {
  const nodes: FileSystemNode[] = [
    {
      id: '1',
      name: 'Documents',
      sizeInKB: 1200,
      type: 'folder',
      children: [
        {
          id: '10',
          name: 'Private',
          sizeInKB: 100,
          type: 'folder',
          children: [
            {
              id: '100',
              name: 'Report.docx',
              sizeInKB: 210,
              type: 'file',
              extension: 'docx',
              mimeType: 'application/msword',
            },
            {
              id: '101',
              name: 'Vacation.docx',
              sizeInKB: 120,
              type: 'file',
              extension: 'docx',
              mimeType: 'application/msword',
            },
            {
              id: '102',
              name: 'CV.pdf',
              sizeInKB: 108,
              type: 'file',
              extension: 'pdf',
              mimeType: 'application/pdf',
            },
          ],
        },
      ],
    },
    {
      id: '2',
      name: 'Desktop',
      sizeInKB: 1000,
      type: 'folder',
      children: [
        {
          id: '20',
          name: 'unknown.txt',
          extension: 'txt',
          mimeType: 'text/plain',
          sizeInKB: 100,
          type: 'file',
        },
      ],
    },
    {
      id: '3',
      name: 'Media',
      sizeInKB: 1000,
      type: 'folder',
      children: [
        {
          id: '30',
          name: 'Music - empty',
          sizeInKB: 0,
          type: 'folder',
          children: [],
        },
        {
          id: '31',
          name: 'Videos',
          sizeInKB: 5400,
          type: 'folder',
          children: [
            {
              id: '310',
              name: 'Vacation.mp4',
              sizeInKB: 108,
              type: 'file',
              extension: 'mp4',
              mimeType: 'video/mp4',
            },
          ],
        },
      ],
    },
  ];
  return Promise.resolve(nodes);
};
```

If `options.force` is `true`, the node will be collapsed even if [`isNodeReadOnly`](https://infinite-table.com/docs/reference/datasource-props/index.md#isNodeReadOnly) is `true` for the given node.
