([]);
return (
<>
setSelectedItems(itemIds)}
>
Selected: {selectedItems.join(', ')}
>
);
}
```
### RichTreeView Multiselect
```tsx
import { useState } from 'react';
import { RichTreeView } from '@mui/x-tree-view/RichTreeView';
import type { TreeViewBaseItem } from '@mui/x-tree-view/models';
const FEATURES: TreeViewBaseItem[] = [
{
id: 'frontend',
label: 'Frontend',
children: [
{ id: 'react', label: 'React' },
{ id: 'vue', label: 'Vue' },
{ id: 'angular', label: 'Angular' },
],
},
{
id: 'backend',
label: 'Backend',
children: [
{ id: 'node', label: 'Node.js' },
{ id: 'python', label: 'Python' },
],
},
];
function FeatureSelector() {
const [selected, setSelected] = useState([]);
return (
setSelected(ids)}
/>
);
}
```
---
## 6. Item Customization — Custom TreeItem Content
Use `TreeItem2` (or `TreeItem` with `ContentComponent`) for full control over each item's rendered content.
### Custom Label with Metadata
```tsx
import { SimpleTreeView } from '@mui/x-tree-view/SimpleTreeView';
import { TreeItem, TreeItemProps } from '@mui/x-tree-view/TreeItem';
import Box from '@mui/material/Box';
import Typography from '@mui/material/Typography';
import Chip from '@mui/material/Chip';
import IconButton from '@mui/material/IconButton';
import DeleteIcon from '@mui/icons-material/Delete';
interface CustomLabelProps {
label: string;
count?: number;
onDelete?: () => void;
}
function CustomLabel({ label, count, onDelete }: CustomLabelProps) {
return (
{label}
{count !== undefined && (
)}
{onDelete && (
{
e.stopPropagation(); // Prevent tree expansion toggle
onDelete();
}}
aria-label={`Delete ${label}`}
>
)}
);
}
function CustomContentTree() {
return (
}
>
console.log('delete msg1')}
/>
}
/>
}
/>
);
}
```
### Custom TreeItem with useTreeItem Hook
```tsx
import React from 'react';
import { unstable_useTreeItem as useTreeItem } from '@mui/x-tree-view/useTreeItem';
import {
TreeItemContent,
TreeItemRoot,
TreeItemGroupTransition,
TreeItemIconContainer,
TreeItemLabel,
} from '@mui/x-tree-view/TreeItem';
import { TreeItemProvider } from '@mui/x-tree-view/TreeItemProvider';
import type { TreeItemProps } from '@mui/x-tree-view/TreeItem';
import { SimpleTreeView } from '@mui/x-tree-view/SimpleTreeView';
import Avatar from '@mui/material/Avatar';
import Box from '@mui/material/Box';
interface UserTreeItemProps extends TreeItemProps {
avatar?: string;
subtitle?: string;
}
const UserTreeItem = React.forwardRef(
({ avatar, subtitle, ...props }, ref) => {
const {
getRootProps,
getContentProps,
getLabelProps,
getIconContainerProps,
getGroupTransitionProps,
status,
} = useTreeItem({ id: props.itemId, children: props.children, label: props.label, rootRef: ref });
return (
{avatar && }
{subtitle && (
{subtitle}
)}
{props.children && }
);
}
);
function UserTree() {
return (
);
}
```
---
## 7. Drag and Drop (Premium)
Drag-and-drop reordering requires `RichTreeViewPro` from `@mui/x-tree-view-pro` (Premium license).
```tsx
import { RichTreeViewPro } from '@mui/x-tree-view-pro/RichTreeViewPro';
import type { TreeViewBaseItem } from '@mui/x-tree-view/models';
import type { TreeViewItemReorderPosition } from '@mui/x-tree-view/models';
const ITEMS: TreeViewBaseItem[] = [
{
id: 'chapter1',
label: 'Chapter 1: Introduction',
children: [
{ id: 'section1-1', label: '1.1 Overview' },
{ id: 'section1-2', label: '1.2 Getting Started' },
],
},
{
id: 'chapter2',
label: 'Chapter 2: Core Concepts',
children: [
{ id: 'section2-1', label: '2.1 Architecture' },
{ id: 'section2-2', label: '2.2 Data Flow' },
],
},
{ id: 'chapter3', label: 'Chapter 3: Advanced Topics' },
];
function DragDropTree() {
const handleItemPositionChange = (params: {
itemId: string;
oldPosition: TreeViewItemReorderPosition;
newPosition: TreeViewItemReorderPosition;
}) => {
console.log(
`Moved "${params.itemId}" from ${params.oldPosition.parentId ?? 'root'} ` +
`(index ${params.oldPosition.index}) to ${params.newPosition.parentId ?? 'root'} ` +
`(index ${params.newPosition.index})`
);
// Persist the new order to your backend
};
return (
);
}
```
### Restricting Drop Targets
```tsx
import { RichTreeViewPro } from '@mui/x-tree-view-pro/RichTreeViewPro';
import type { TreeViewBaseItem } from '@mui/x-tree-view/models';
interface CategoryItem {
id: string;
label: string;
isCategory?: boolean;
children?: CategoryItem[];
}
const items: TreeViewBaseItem[] = [
{
id: 'cat1',
label: 'Fruits',
isCategory: true,
children: [
{ id: 'apple', label: 'Apple' },
{ id: 'banana', label: 'Banana' },
],
},
{
id: 'cat2',
label: 'Vegetables',
isCategory: true,
children: [
{ id: 'carrot', label: 'Carrot' },
],
},
];
function RestrictedDnDTree() {
return (
items={items}
itemsReordering
isItemReorderable={(item) => !item.isCategory} // Only leaf items can be dragged
canMoveItemToNewPosition={({ newPosition }) => {
// Only allow dropping into category containers
return newPosition.parentId !== null;
}}
/>
);
}
```
---
## 8. Virtualization (Premium)
Built-in virtualization for large trees via `RichTreeViewPro`. Renders only visible items for performance.
```tsx
import { RichTreeViewPro } from '@mui/x-tree-view-pro/RichTreeViewPro';
import type { TreeViewBaseItem } from '@mui/x-tree-view/models';
// Generate a large tree for demo
function generateLargeTree(depth: number, breadth: number, prefix = ''): TreeViewBaseItem[] {
if (depth === 0) return [];
return Array.from({ length: breadth }, (_, i) => ({
id: `${prefix}${i}`,
label: `Item ${prefix}${i}`,
children: generateLargeTree(depth - 1, breadth, `${prefix}${i}-`),
}));
}
const LARGE_ITEMS = generateLargeTree(4, 20); // 20^4 = 160,000 potential nodes
function VirtualizedTree() {
return (
);
}
```
---
## 9. API Ref — Programmatic Control
Use `useTreeViewApiRef()` for imperative actions: expand, collapse, select, focus.
```tsx
import { useRef } from 'react';
import { RichTreeView } from '@mui/x-tree-view/RichTreeView';
import { useTreeViewApiRef } from '@mui/x-tree-view/hooks';
import type { TreeViewBaseItem } from '@mui/x-tree-view/models';
import Button from '@mui/material/Button';
import Stack from '@mui/material/Stack';
const ITEMS: TreeViewBaseItem[] = [
{
id: 'settings',
label: 'Settings',
children: [
{
id: 'profile',
label: 'Profile',
children: [
{ id: 'avatar', label: 'Avatar' },
{ id: 'bio', label: 'Bio' },
],
},
{ id: 'security', label: 'Security' },
],
},
{
id: 'dashboard',
label: 'Dashboard',
children: [
{ id: 'analytics', label: 'Analytics' },
{ id: 'reports', label: 'Reports' },
],
},
];
function ApiRefTree() {
const apiRef = useTreeViewApiRef();
const expandAll = () => {
// Expand all items by ID
const allIds = ['settings', 'profile', 'dashboard'];
allIds.forEach((id) => {
apiRef.current?.setItemExpansion(null, id, true);
});
};
const collapseAll = () => {
const allIds = ['settings', 'profile', 'dashboard'];
allIds.forEach((id) => {
apiRef.current?.setItemExpansion(null, id, false);
});
};
const focusItem = (itemId: string) => {
apiRef.current?.focusItem(null, itemId);
};
const selectItem = (itemId: string) => {
apiRef.current?.selectItem({ event: {} as React.SyntheticEvent, itemId });
};
return (
);
}
```
### API Reference Methods
| Method | Signature | Description |
|--------|-----------|-------------|
| `setItemExpansion` | `(event, itemId, isExpanded) => void` | Expand or collapse a specific item |
| `focusItem` | `(event, itemId) => void` | Set focus to a specific item |
| `selectItem` | `({ event, itemId, keepExistingSelection?, shouldBeSelected? }) => void` | Select/deselect an item |
| `getItem` | `(itemId) => TreeViewBaseItem` | Get the item model by ID |
| `getItemDOMElement` | `(itemId) => HTMLElement \| null` | Get the DOM element for an item |
| `getItemTree` | `() => TreeViewBaseItem[]` | Get the full item tree |
| `getItemOrderedChildrenIds` | `(itemId) => string[]` | Get ordered children IDs |
---
## 10. Disabled Items
Disable individual items. By default, disabled items are not focusable and not selectable.
```tsx
import { SimpleTreeView } from '@mui/x-tree-view/SimpleTreeView';
import { TreeItem } from '@mui/x-tree-view/TreeItem';
function DisabledItemsTree() {
return (
);
}
```
### Disabled with RichTreeView
```tsx
import { RichTreeView } from '@mui/x-tree-view/RichTreeView';
import type { TreeViewBaseItem } from '@mui/x-tree-view/models';
const ITEMS: TreeViewBaseItem[] = [
{
id: 'active',
label: 'Active Modules',
children: [
{ id: 'auth', label: 'Authentication' },
{ id: 'billing', label: 'Billing' },
],
},
{
id: 'deprecated',
label: 'Deprecated Modules',
children: [
{ id: 'legacy-auth', label: 'Legacy Auth (v1)' },
],
},
];
function DisabledRichTree() {
return (
item.id === 'deprecated' || item.id === 'legacy-auth'}
disabledItemsFocusable={false} // default
/>
);
}
```
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `disabledItemsFocusable` | `boolean` | `false` | If `true`, disabled items can receive keyboard focus |
| `disabled` (TreeItem) | `boolean` | `false` | Disables the item and all its descendants |
| `isItemDisabled` (RichTreeView) | `(item) => boolean` | — | Callback to determine if an item is disabled |
---
## 11. TypeScript Patterns
### TreeViewBaseItem Interface
```tsx
import type { TreeViewBaseItem } from '@mui/x-tree-view/models';
// Base interface — every item must have id, label, optional children
// interface TreeViewBaseItem = Record> {
// id: string;
// label: string;
// children?: TreeViewBaseItem[];
// } & R
// Extend with custom properties
interface ProjectItem {
id: string;
label: string;
status: 'active' | 'archived' | 'draft';
owner: string;
children?: ProjectItem[];
}
// Use as generic parameter
const items: TreeViewBaseItem[] = [
{
id: 'proj1',
label: 'Website Redesign',
status: 'active',
owner: 'alice',
children: [
{ id: 'task1', label: 'Wireframes', status: 'active', owner: 'bob' },
{ id: 'task2', label: 'Visual Design', status: 'draft', owner: 'carol' },
],
},
];
```
### Typed Event Handlers
```tsx
import type { TreeViewBaseItem } from '@mui/x-tree-view/models';
import { RichTreeView } from '@mui/x-tree-view/RichTreeView';
interface NavItem {
id: string;
label: string;
path: string;
children?: NavItem[];
}
function TypedHandlers() {
const handleSelect = (
_event: React.SyntheticEvent,
itemId: string | null
) => {
if (itemId) {
console.log('Selected:', itemId);
}
};
const handleExpansion = (
_event: React.SyntheticEvent,
itemIds: string[]
) => {
console.log('Expanded items:', itemIds);
};
const handleItemClick = (
_event: React.MouseEvent,
itemId: string
) => {
console.log('Clicked:', itemId);
};
const items: TreeViewBaseItem[] = [
{
id: 'home',
label: 'Home',
path: '/',
children: [
{ id: 'about', label: 'About', path: '/about' },
{ id: 'contact', label: 'Contact', path: '/contact' },
],
},
];
return (
items={items}
onSelectedItemsChange={handleSelect}
onExpandedItemsChange={handleExpansion}
onItemClick={handleItemClick}
/>
);
}
```
### Utility Types
```tsx
// Item ID type alias
type TreeItemId = string;
// Selection model types
type SingleSelectValue = string | null;
type MultiSelectValue = string[];
// Expansion model
type ExpandedItems = string[];
// Slot prop overrides
import type { TreeItemSlots, TreeItemSlotProps } from '@mui/x-tree-view/TreeItem';
```
---
## 12. Tier Availability Summary
| Feature | Community (free) | Pro | Premium |
|---------|:---:|:---:|:---:|
| `SimpleTreeView` | Yes | Yes | Yes |
| `RichTreeView` | Yes | Yes | Yes |
| Expansion/Selection | Yes | Yes | Yes |
| Checkbox selection | Yes | Yes | Yes |
| Custom icons | Yes | Yes | Yes |
| Disabled items | Yes | Yes | Yes |
| `useTreeViewApiRef` | Yes | Yes | Yes |
| Keyboard navigation | Yes | Yes | Yes |
| `RichTreeViewPro` | -- | Yes | Yes |
| Drag-and-drop reorder | -- | -- | Yes |
| Virtualization | -- | -- | Yes |
| Lazy loading (data source) | Yes | Yes | Yes |
### Installation
```bash
# Community (free)
npm install @mui/x-tree-view
# Pro (commercial license)
npm install @mui/x-tree-view-pro
# Always needed as peer dependencies
npm install @mui/material @emotion/react @emotion/styled
```
### License Key Setup (Pro/Premium)
```tsx
import { LicenseInfo } from '@mui/x-license';
LicenseInfo.setLicenseKey('YOUR_LICENSE_KEY');
```
---
## Quick Reference — Common Props
### SimpleTreeView
| Prop | Type | Description |
|------|------|-------------|
| `expandedItems` | `string[]` | Controlled expanded item IDs |
| `defaultExpandedItems` | `string[]` | Uncontrolled default expanded |
| `selectedItems` | `string \| string[] \| null` | Controlled selection |
| `defaultSelectedItems` | `string \| string[] \| null` | Uncontrolled default selection |
| `multiSelect` | `boolean` | Enable multi-selection |
| `checkboxSelection` | `boolean` | Show checkboxes for selection |
| `disabledItemsFocusable` | `boolean` | Allow focus on disabled items |
| `onExpandedItemsChange` | `(event, itemIds) => void` | Expansion change handler |
| `onSelectedItemsChange` | `(event, itemIds) => void` | Selection change handler |
| `onItemClick` | `(event, itemId) => void` | Item click handler |
| `onItemFocus` | `(event, itemId, value) => void` | Item focus handler |
| `onItemExpansionToggle` | `(event, itemId, isExpanded) => void` | Per-item expansion toggle |
| `slots` | `object` | Custom slot components |
| `slotProps` | `object` | Props for slot components |
| `apiRef` | `React.MutableRefObject` | Imperative API reference |
### RichTreeView (extends SimpleTreeView)
| Prop | Type | Description |
|------|------|-------------|
| `items` | `TreeViewBaseItem[]` | Data-driven item array (required) |
| `getItemId` | `(item) => string` | Custom ID accessor (default: `item.id`) |
| `getItemLabel` | `(item) => string` | Custom label accessor (default: `item.label`) |
| `isItemDisabled` | `(item) => boolean` | Per-item disabled callback |
| `experimentalFeatures` | `{ lazyLoading?, virtualization? }` | Enable experimental features |
| `dataSource` | `{ getChildren, getChildrenCount }` | Async data source for lazy loading |
### TreeItem
| Prop | Type | Description |
|------|------|-------------|
| `itemId` | `string` | Unique identifier (required) |
| `label` | `ReactNode` | Content displayed for the item |
| `disabled` | `boolean` | Disable this item and descendants |
| `slots` | `{ icon?, expandIcon?, collapseIcon?, endIcon?, groupTransition? }` | Custom slot components |
| `slotProps` | `object` | Props for slot components |