[] = [
+ {
+ id: 'grid',
+ label: 'Data Grid',
+ children: [
+ {
+ id: 'grid-community',
+ label: '@mui/x-data-grid',
+ secondaryLabel: 'Community package',
+ },
+ {
+ id: 'grid-pro',
+ label: '@mui/x-data-grid-pro',
+ secondaryLabel: 'Pro package',
+ },
+ {
+ id: 'grid-premium',
+ label: '@mui/x-data-grid-premium',
+ secondaryLabel: 'Premium package',
+ },
+ ],
+ },
+ {
+ id: 'pickers',
+ label: 'Date and Time pickers',
+
+ children: [
+ {
+ id: 'pickers-community',
+ label: '@mui/x-date-pickers',
+ secondaryLabel: 'Community package',
+ },
+ {
+ id: 'pickers-pro',
+ label: '@mui/x-date-pickers-pro',
+ secondaryLabel: 'Pro package',
+ },
+ ],
+ },
+ {
+ id: 'charts',
+ label: 'Charts',
+
+ children: [{ id: 'charts-community', label: '@mui/x-charts' }],
+ },
+ {
+ id: 'tree-view',
+ label: 'Tree View',
+ children: [{ id: 'tree-view-community', label: '@mui/x-tree-view' }],
+ },
+];
+
+interface CustomLabelProps {
+ children: string;
+ className: string;
+ secondaryLabel: string;
+}
+
+function CustomLabel({ children, className, secondaryLabel }: CustomLabelProps) {
+ return (
+
+ {children}
+ {secondaryLabel && (
+
+ {secondaryLabel}
+
+ )}
+
+ );
+}
+
+const CustomTreeItem = React.forwardRef(function CustomTreeItem(
+ props: TreeItem2Props,
+ ref: React.Ref,
+) {
+ const { publicAPI } = useTreeItem2Utils({
+ itemId: props.itemId,
+ children: props.children,
+ });
+
+ const item = publicAPI.getItem(props.itemId);
+
+ return (
+
+ );
+});
+
+export default function LabelSlot() {
+ return (
+
+
+
+ );
+}
diff --git a/docs/data/tree-view/tree-item-customization/LabelSlot.tsx.preview b/docs/data/tree-view/tree-item-customization/LabelSlot.tsx.preview
new file mode 100644
index 0000000000000..1333b932705fa
--- /dev/null
+++ b/docs/data/tree-view/tree-item-customization/LabelSlot.tsx.preview
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/docs/data/tree-view/tree-item-customization/LabelSlotProps.js b/docs/data/tree-view/tree-item-customization/LabelSlotProps.js
new file mode 100644
index 0000000000000..5de096ebed230
--- /dev/null
+++ b/docs/data/tree-view/tree-item-customization/LabelSlotProps.js
@@ -0,0 +1,31 @@
+import * as React from 'react';
+import Box from '@mui/material/Box';
+import { RichTreeView } from '@mui/x-tree-view/RichTreeView';
+import { TreeItem2 } from '@mui/x-tree-view/TreeItem2';
+import { MUI_X_PRODUCTS } from './products';
+
+const CustomTreeItem = React.forwardRef(function CustomTreeItem(props, ref) {
+ return (
+
+ );
+});
+
+export default function LabelSlotProps() {
+ return (
+
+
+
+ );
+}
diff --git a/docs/data/tree-view/tree-item-customization/LabelSlotProps.tsx b/docs/data/tree-view/tree-item-customization/LabelSlotProps.tsx
new file mode 100644
index 0000000000000..4713d99686863
--- /dev/null
+++ b/docs/data/tree-view/tree-item-customization/LabelSlotProps.tsx
@@ -0,0 +1,34 @@
+import * as React from 'react';
+import Box from '@mui/material/Box';
+import { RichTreeView } from '@mui/x-tree-view/RichTreeView';
+import { TreeItem2, TreeItem2Props } from '@mui/x-tree-view/TreeItem2';
+import { MUI_X_PRODUCTS } from './products';
+
+const CustomTreeItem = React.forwardRef(function CustomTreeItem(
+ props: TreeItem2Props,
+ ref: React.Ref,
+) {
+ return (
+
+ );
+});
+
+export default function LabelSlotProps() {
+ return (
+
+
+
+ );
+}
diff --git a/docs/data/tree-view/tree-item-customization/LabelSlotProps.tsx.preview b/docs/data/tree-view/tree-item-customization/LabelSlotProps.tsx.preview
new file mode 100644
index 0000000000000..ebee34cfcc6f4
--- /dev/null
+++ b/docs/data/tree-view/tree-item-customization/LabelSlotProps.tsx.preview
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/docs/data/tree-view/tree-item-customization/products.ts b/docs/data/tree-view/tree-item-customization/products.ts
new file mode 100644
index 0000000000000..4eff454801bbc
--- /dev/null
+++ b/docs/data/tree-view/tree-item-customization/products.ts
@@ -0,0 +1,44 @@
+import { TreeViewBaseItem } from '@mui/x-tree-view/models';
+
+type TreeItemType = {
+ id: string;
+ label: string;
+ disabled?: boolean;
+ editable?: boolean;
+};
+
+export const MUI_X_PRODUCTS: TreeViewBaseItem[] = [
+ {
+ id: 'grid',
+ label: 'Data Grid',
+ editable: true,
+ children: [
+ { id: 'grid-community', label: '@mui/x-data-grid', editable: true },
+ { id: 'grid-pro', label: '@mui/x-data-grid-pro', editable: true },
+ { id: 'grid-premium', label: '@mui/x-data-grid-premium', editable: true },
+ ],
+ },
+ {
+ id: 'pickers',
+ label: 'Date and Time pickers',
+ children: [
+ {
+ id: 'pickers-community',
+ label: '@mui/x-date-pickers',
+ disabled: true,
+ },
+ { id: 'pickers-pro', label: '@mui/x-date-pickers-pro', editable: true },
+ ],
+ },
+ {
+ id: 'charts',
+ label: 'Charts',
+
+ children: [{ id: 'charts-community', label: '@mui/x-charts' }],
+ },
+ {
+ id: 'tree-view',
+ label: 'Tree View',
+ children: [{ id: 'tree-view-community', label: '@mui/x-tree-view' }],
+ },
+];
diff --git a/docs/data/tree-view/tree-item-customization/tree-item-customization.md b/docs/data/tree-view/tree-item-customization/tree-item-customization.md
index ffc3be81307aa..93c39d69cd276 100644
--- a/docs/data/tree-view/tree-item-customization/tree-item-customization.md
+++ b/docs/data/tree-view/tree-item-customization/tree-item-customization.md
@@ -11,6 +11,66 @@ waiAria: https://www.w3.org/WAI/ARIA/apg/patterns/treeview/
Learn how to customize the Tree Item component.
+## Anatomy
+
+Each Tree Item component is shaped by a series of composable slots.
+Hover over them in the demo below to see each slot.
+
+
+
+
+{{"component": "modules/components/TreeItem2Anatomy.js"}}
+
+### Content
+
+Use the content slot to customize the content of the Tree Item or replace it with a custom component.
+
+#### Slot props
+
+The `slotProps` prop lets you pass props to the content component.
+The demo below shows how to pass an `sx` handler to the content of the Tree Item:
+
+{{"demo": "ContentSlotProps.js"}}
+
+#### Slot
+
+The demo below shows how to replace the content slot with a custom component.
+
+{{"demo": "ContentSlot.js"}}
+
+### Label
+
+Use the label slot to customize the Tree Item label or replace it with a custom component.
+
+#### Slot props
+
+The `slotProps` prop lets you pass props to the label component.
+The demo below shows how to pass an `id` attribute to the Tree Item label:
+
+{{"demo": "LabelSlotProps.js"}}
+
+#### Slot
+
+The demo below shows how to replace the label slot with a custom component.
+
+{{"demo": "LabelSlot.js"}}
+
+### Checkbox
+
+The checkbox is present on the items when `checkboxSelection` is enabled on the Tree View.
+
+#### Slot props
+
+You can pass props to the checkbox slot using the `slotProps` on the Tree Item 2 component.
+
+{{"demo": "CheckboxSlotProps.js"}}
+
+#### Slot
+
+The demo below shows how to replace the checkbox slot with a custom component.
+
+{{"demo": "CheckboxSlot.js"}}
+
## Basics
### Change nested item's indentation
@@ -69,3 +129,115 @@ const CustomTreeItem2Content = styled(TreeItem2Content)(({ theme }) => ({
```
:::
+
+## Hooks
+
+### useTreeItem2
+
+The `useTreeItem2` hook lets you manage and customize individual Tree Items.
+You can use it to get the properties needed for all slots, the status of any given Item, or to tap into the interactive API of the Tree View.
+
+#### Slot properties
+
+The `useTreeItem2` hook gives you granular control over an Item's layout by providing resolvers to get the appropriate props for each slot.
+This makes it possible to build a fully custom layout for your Tree Items.
+
+The demo below shows how to get the props needed for each slot, and how to pass them correctly.
+
+{{"demo": "useTreeItem2HookProperties.js"}}
+
+You can pass additional props to a slot—or override existing slots—by passing an object argument to the slot's props resolver, as shown below:
+
+```jsx
+
+```
+
+#### Item status
+
+The `useTreeItem2` hook also returns a `status` object that holds boolean values for each possible state of a Tree Item.
+
+```jsx
+const {
+ status: { expanded, expandable, focused, selected, disabled, editable, editing },
+} = useTreeItem2(props);
+```
+
+You can use these statuses to apply custom styling to the item or conditionally render subcomponents.
+
+{{"demo": "useTreeItem2HookStatus.js"}}
+
+#### Imperative API
+
+The `publicAPI` object provides a number of methods to programmatically interact with the Tree View.
+You can use the `useTreeItem2` hook to access the `publicAPI` object from within a Tree Item.
+
+{{"demo": "useTreeItem2HookPublicAPI.js"}}
+
+See the **Imperative API** section on each feature page to learn more about the public API methods available on the Tree View.
+
+### `useTreeItem2Utils`
+
+The `useTreeItem2Utils` hook provides a set of interaction methods for implementing custom behaviors for the Tree View.
+It also returns the status of the Item.
+
+```jsx
+const { interactions, status } = useTreeItem2Utils({
+ itemId: props.itemId,
+ children: props.children,
+});
+```
+
+To override the Tree Item's default interactions, set `event.defaultMuiPrevented` to `true` in the event handlers and then implement your own behavior.
+
+#### Selection
+
+You can select an Item in a Tree View by clicking its content slot.
+The demo below shows how to handle selection when the user clicks on an icon.
+
+{{"demo": "HandleSelectionDemo.js"}}
+
+#### Checkbox selection
+
+By default, checkbox selection is skipped if an Item is disabled or if `disableSelection` is `true` on the Tree View.
+You can create a custom handler for the `onChange` event on the checkbox slot to bypass these conditions.
+The demo below shows how to implement custom checkbox selection behavior.
+
+{{"demo": "HandleCheckboxSelectionDemo.js"}}
+
+Visit the [Rich Tree View](/x/react-tree-view/rich-tree-view/selection/) or [Simple Tree View](/x/react-tree-view/simple-tree-view/selection/) docs, respectively, for more details on the selection API.
+
+#### Expansion
+
+By default, a Tree Item is expanded when the user clicks on its contents.
+You can change the expansion trigger using the `expansionTrigger` prop on the `iconContainer`.
+For more details, see [Expansion—Limit expansion to icon container](/x/react-tree-view/rich-tree-view/expansion/#limit-expansion-to-icon-container).
+
+Use the `handleExpansion` interaction method for deeper customization of the Item's expansion behavior.
+
+The demo below shows how to introduce a new element that expands and collapses the Item.
+
+{{"demo": "HandleExpansionDemo.js"}}
+
+#### Label editing
+
+The `useTreeItem2Utils` hook provides the following interaction methods relevant to label editing behavior:
+
+```jsx
+const {
+ interactions: {
+ toggleItemEditing,
+ handleCancelItemLabelEditing,
+ handleSaveItemLabel,
+ },
+} = useTreeItem2Utils({
+ itemId: props.itemId,
+ children: props.children,
+});
+```
+
+See [Editing—enable editing using only icons](/x/react-tree-view/rich-tree-view/editing/#enable-editing-using-only-icons) for more details on customizing this behavior.
diff --git a/docs/data/tree-view/tree-item-customization/useTreeItem2HookProperties.js b/docs/data/tree-view/tree-item-customization/useTreeItem2HookProperties.js
new file mode 100644
index 0000000000000..b93e60f39e001
--- /dev/null
+++ b/docs/data/tree-view/tree-item-customization/useTreeItem2HookProperties.js
@@ -0,0 +1,72 @@
+import * as React from 'react';
+import Box from '@mui/material/Box';
+import { RichTreeView } from '@mui/x-tree-view/RichTreeView';
+import { useTreeItem2 } from '@mui/x-tree-view/useTreeItem2';
+import {
+ TreeItem2Checkbox,
+ TreeItem2Content,
+ TreeItem2IconContainer,
+ TreeItem2Label,
+ TreeItem2Root,
+ TreeItem2GroupTransition,
+} from '@mui/x-tree-view/TreeItem2';
+import { TreeItem2Icon } from '@mui/x-tree-view/TreeItem2Icon';
+import { TreeItem2Provider } from '@mui/x-tree-view/TreeItem2Provider';
+import { TreeItem2DragAndDropOverlay } from '@mui/x-tree-view/TreeItem2DragAndDropOverlay';
+import { TreeItem2LabelInput } from '@mui/x-tree-view/TreeItem2LabelInput';
+import { MUI_X_PRODUCTS } from './products';
+
+const CustomTreeItem = React.forwardRef(function CustomTreeItem(
+ { id, itemId, label, disabled, children },
+ ref,
+) {
+ const {
+ getRootProps,
+ getContentProps,
+ getIconContainerProps,
+ getCheckboxProps,
+ getLabelProps,
+ getLabelInputProps,
+ getGroupTransitionProps,
+ getDragAndDropOverlayProps,
+ status,
+ } = useTreeItem2({ id, itemId, children, label, disabled, rootRef: ref });
+
+ return (
+
+
+
+
+
+
+
+ {status.editing ? (
+
+ ) : (
+
+ )}
+
+
+
+ {children && }
+
+
+ );
+});
+
+export default function useTreeItem2HookProperties() {
+ return (
+
+
+
+ );
+}
diff --git a/docs/data/tree-view/tree-item-customization/useTreeItem2HookProperties.tsx b/docs/data/tree-view/tree-item-customization/useTreeItem2HookProperties.tsx
new file mode 100644
index 0000000000000..e2ec284be456a
--- /dev/null
+++ b/docs/data/tree-view/tree-item-customization/useTreeItem2HookProperties.tsx
@@ -0,0 +1,73 @@
+import * as React from 'react';
+import Box from '@mui/material/Box';
+import { RichTreeView } from '@mui/x-tree-view/RichTreeView';
+import { useTreeItem2 } from '@mui/x-tree-view/useTreeItem2';
+import {
+ TreeItem2Checkbox,
+ TreeItem2Content,
+ TreeItem2IconContainer,
+ TreeItem2Label,
+ TreeItem2Root,
+ TreeItem2Props,
+ TreeItem2GroupTransition,
+} from '@mui/x-tree-view/TreeItem2';
+import { TreeItem2Icon } from '@mui/x-tree-view/TreeItem2Icon';
+import { TreeItem2Provider } from '@mui/x-tree-view/TreeItem2Provider';
+import { TreeItem2DragAndDropOverlay } from '@mui/x-tree-view/TreeItem2DragAndDropOverlay';
+import { TreeItem2LabelInput } from '@mui/x-tree-view/TreeItem2LabelInput';
+import { MUI_X_PRODUCTS } from './products';
+
+const CustomTreeItem = React.forwardRef(function CustomTreeItem(
+ { id, itemId, label, disabled, children }: TreeItem2Props,
+ ref: React.Ref,
+) {
+ const {
+ getRootProps,
+ getContentProps,
+ getIconContainerProps,
+ getCheckboxProps,
+ getLabelProps,
+ getLabelInputProps,
+ getGroupTransitionProps,
+ getDragAndDropOverlayProps,
+ status,
+ } = useTreeItem2({ id, itemId, children, label, disabled, rootRef: ref });
+
+ return (
+
+
+
+
+
+
+
+ {status.editing ? (
+
+ ) : (
+
+ )}
+
+
+
+ {children && }
+
+
+ );
+});
+
+export default function useTreeItem2HookProperties() {
+ return (
+
+
+
+ );
+}
diff --git a/docs/data/tree-view/tree-item-customization/useTreeItem2HookProperties.tsx.preview b/docs/data/tree-view/tree-item-customization/useTreeItem2HookProperties.tsx.preview
new file mode 100644
index 0000000000000..5c65f878fe8fb
--- /dev/null
+++ b/docs/data/tree-view/tree-item-customization/useTreeItem2HookProperties.tsx.preview
@@ -0,0 +1,10 @@
+
\ No newline at end of file
diff --git a/docs/data/tree-view/tree-item-customization/useTreeItem2HookPublicAPI.js b/docs/data/tree-view/tree-item-customization/useTreeItem2HookPublicAPI.js
new file mode 100644
index 0000000000000..086d8d6ff0867
--- /dev/null
+++ b/docs/data/tree-view/tree-item-customization/useTreeItem2HookPublicAPI.js
@@ -0,0 +1,56 @@
+import * as React from 'react';
+import Box from '@mui/material/Box';
+import Typography from '@mui/material/Typography';
+import Chip from '@mui/material/Chip';
+import Stack from '@mui/material/Stack';
+import { RichTreeView } from '@mui/x-tree-view/RichTreeView';
+import { TreeItem2 } from '@mui/x-tree-view/TreeItem2';
+import { useTreeItem2 } from '@mui/x-tree-view/useTreeItem2';
+import { MUI_X_PRODUCTS } from './products';
+
+function CustomLabel({ children, className, numberOfChildren }) {
+ return (
+
+ {children}
+
+
+
+ );
+}
+
+const CustomTreeItem = React.forwardRef(function CustomTreeItem(props, ref) {
+ const { publicAPI } = useTreeItem2(props);
+
+ const childrenNumber = publicAPI.getItemOrderedChildrenIds(props.itemId).length;
+
+ return (
+
+ );
+});
+
+export default function useTreeItem2HookPublicAPI() {
+ return (
+
+
+
+ );
+}
diff --git a/docs/data/tree-view/tree-item-customization/useTreeItem2HookPublicAPI.tsx b/docs/data/tree-view/tree-item-customization/useTreeItem2HookPublicAPI.tsx
new file mode 100644
index 0000000000000..271d94879967a
--- /dev/null
+++ b/docs/data/tree-view/tree-item-customization/useTreeItem2HookPublicAPI.tsx
@@ -0,0 +1,65 @@
+import * as React from 'react';
+import Box from '@mui/material/Box';
+import Typography from '@mui/material/Typography';
+import Chip from '@mui/material/Chip';
+import Stack from '@mui/material/Stack';
+import { RichTreeView } from '@mui/x-tree-view/RichTreeView';
+import { TreeItem2, TreeItem2Props } from '@mui/x-tree-view/TreeItem2';
+import { useTreeItem2 } from '@mui/x-tree-view/useTreeItem2';
+import { MUI_X_PRODUCTS } from './products';
+
+interface CustomLabelProps {
+ children: string;
+ className: string;
+ numberOfChildren: number;
+}
+
+function CustomLabel({ children, className, numberOfChildren }: CustomLabelProps) {
+ return (
+
+ {children}
+
+
+
+ );
+}
+
+const CustomTreeItem = React.forwardRef(function CustomTreeItem(
+ props: TreeItem2Props,
+ ref: React.Ref,
+) {
+ const { publicAPI } = useTreeItem2(props);
+
+ const childrenNumber = publicAPI.getItemOrderedChildrenIds(props.itemId).length;
+
+ return (
+
+ );
+});
+
+export default function useTreeItem2HookPublicAPI() {
+ return (
+
+
+
+ );
+}
diff --git a/docs/data/tree-view/tree-item-customization/useTreeItem2HookPublicAPI.tsx.preview b/docs/data/tree-view/tree-item-customization/useTreeItem2HookPublicAPI.tsx.preview
new file mode 100644
index 0000000000000..1333b932705fa
--- /dev/null
+++ b/docs/data/tree-view/tree-item-customization/useTreeItem2HookPublicAPI.tsx.preview
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/docs/data/tree-view/tree-item-customization/useTreeItem2HookStatus.js b/docs/data/tree-view/tree-item-customization/useTreeItem2HookStatus.js
new file mode 100644
index 0000000000000..6385bcb3f5ae3
--- /dev/null
+++ b/docs/data/tree-view/tree-item-customization/useTreeItem2HookStatus.js
@@ -0,0 +1,152 @@
+import * as React from 'react';
+import Box from '@mui/material/Box';
+import Stack from '@mui/material/Stack';
+import Paper from '@mui/material/Paper';
+import Typography from '@mui/material/Typography';
+import AdjustIcon from '@mui/icons-material/Adjust';
+import CheckCircleOutlinedIcon from '@mui/icons-material/CheckCircleOutlined';
+import ExpandCircleDownOutlinedIcon from '@mui/icons-material/ExpandCircleDownOutlined';
+import ExpandCircleDownRoundedIcon from '@mui/icons-material/ExpandCircleDownRounded';
+import CancelOutlinedIcon from '@mui/icons-material/CancelOutlined';
+import EditOutlinedIcon from '@mui/icons-material/EditOutlined';
+import DrawOutlinedIcon from '@mui/icons-material/DrawOutlined';
+import { RichTreeView } from '@mui/x-tree-view/RichTreeView';
+import { useTreeItem2 } from '@mui/x-tree-view/useTreeItem2';
+import {
+ TreeItem2Content,
+ TreeItem2Root,
+ TreeItem2GroupTransition,
+ TreeItem2IconContainer,
+ TreeItem2Label,
+} from '@mui/x-tree-view/TreeItem2';
+import { TreeItem2Icon } from '@mui/x-tree-view/TreeItem2Icon';
+import { TreeItem2Provider } from '@mui/x-tree-view/TreeItem2Provider';
+import { TreeItem2LabelInput } from '@mui/x-tree-view/TreeItem2LabelInput';
+import { MUI_X_PRODUCTS } from './products';
+
+function StatusLegend() {
+ return (
+ ({
+ padding: 2,
+ background: theme.palette.grey[50],
+ ...theme.applyStyles('dark', {
+ background: theme.palette.grey[900],
+ }),
+ })}
+ >
+
+ Legend
+
+
+ {STATUS_ICONS.focused}
+ focused
+
+
+ {STATUS_ICONS.selected}
+ selected
+
+
+ {STATUS_ICONS.expandable}
+ expandable
+
+
+ {STATUS_ICONS.expanded}
+ expanded
+
+
+ {STATUS_ICONS.disabled}
+ disabled
+
+
+ {STATUS_ICONS.editable}
+ editable
+
+
+ {STATUS_ICONS.editing}
+ editing
+
+
+
+ );
+}
+
+const STATUS_ICONS = {
+ focused: ,
+ selected: ,
+ expandable: ,
+ expanded: ,
+ disabled: ,
+ editable: ,
+ editing: ,
+};
+
+const CustomTreeItem = React.forwardRef(function CustomTreeItem(
+ { id, itemId, label, disabled, children },
+ ref,
+) {
+ const {
+ getRootProps,
+ getContentProps,
+ getLabelProps,
+ getGroupTransitionProps,
+ getIconContainerProps,
+ getLabelInputProps,
+ status,
+ } = useTreeItem2({ id, itemId, label, disabled, children, rootRef: ref });
+
+ return (
+
+
+
+
+
+
+
+ {status.editing ? (
+
+ ) : (
+
+ )}
+
+
+ {Object.keys(STATUS_ICONS).map((iconKey, index) => {
+ if (status[iconKey]) {
+ return (
+
+ {STATUS_ICONS[iconKey]}
+
+ );
+ }
+ return null;
+ })}
+
+
+ {children && }
+
+
+ );
+});
+
+export default function useTreeItem2HookStatus() {
+ return (
+
+
+ Boolean(item?.disabled)}
+ isItemEditable={(item) => Boolean(item?.editable)}
+ experimentalFeatures={{
+ labelEditing: true,
+ }}
+ />
+
+
+
+ );
+}
diff --git a/docs/data/tree-view/tree-item-customization/useTreeItem2HookStatus.tsx b/docs/data/tree-view/tree-item-customization/useTreeItem2HookStatus.tsx
new file mode 100644
index 0000000000000..2ea3153a42cef
--- /dev/null
+++ b/docs/data/tree-view/tree-item-customization/useTreeItem2HookStatus.tsx
@@ -0,0 +1,157 @@
+import * as React from 'react';
+import Box from '@mui/material/Box';
+import Stack from '@mui/material/Stack';
+import Paper from '@mui/material/Paper';
+import Typography from '@mui/material/Typography';
+import AdjustIcon from '@mui/icons-material/Adjust';
+import CheckCircleOutlinedIcon from '@mui/icons-material/CheckCircleOutlined';
+import ExpandCircleDownOutlinedIcon from '@mui/icons-material/ExpandCircleDownOutlined';
+import ExpandCircleDownRoundedIcon from '@mui/icons-material/ExpandCircleDownRounded';
+import CancelOutlinedIcon from '@mui/icons-material/CancelOutlined';
+import EditOutlinedIcon from '@mui/icons-material/EditOutlined';
+import DrawOutlinedIcon from '@mui/icons-material/DrawOutlined';
+import { RichTreeView } from '@mui/x-tree-view/RichTreeView';
+import { useTreeItem2, UseTreeItem2Status } from '@mui/x-tree-view/useTreeItem2';
+import {
+ TreeItem2Content,
+ TreeItem2Root,
+ TreeItem2Props,
+ TreeItem2GroupTransition,
+ TreeItem2IconContainer,
+ TreeItem2Label,
+} from '@mui/x-tree-view/TreeItem2';
+import { TreeItem2Icon } from '@mui/x-tree-view/TreeItem2Icon';
+import { TreeItem2Provider } from '@mui/x-tree-view/TreeItem2Provider';
+import { TreeItem2LabelInput } from '@mui/x-tree-view/TreeItem2LabelInput';
+import { MUI_X_PRODUCTS } from './products';
+
+function StatusLegend() {
+ return (
+ ({
+ padding: 2,
+ background: theme.palette.grey[50],
+ ...theme.applyStyles('dark', {
+ background: theme.palette.grey[900],
+ }),
+ })}
+ >
+
+ Legend
+
+
+ {STATUS_ICONS.focused}
+ focused
+
+
+ {STATUS_ICONS.selected}
+ selected
+
+
+ {STATUS_ICONS.expandable}
+ expandable
+
+
+ {STATUS_ICONS.expanded}
+ expanded
+
+
+ {STATUS_ICONS.disabled}
+ disabled
+
+
+ {STATUS_ICONS.editable}
+ editable
+
+
+ {STATUS_ICONS.editing}
+ editing
+
+
+
+ );
+}
+
+const STATUS_ICONS: {
+ [K in keyof UseTreeItem2Status]: React.ReactNode;
+} = {
+ focused: ,
+ selected: ,
+ expandable: ,
+ expanded: ,
+ disabled: ,
+ editable: ,
+ editing: ,
+};
+
+const CustomTreeItem = React.forwardRef(function CustomTreeItem(
+ { id, itemId, label, disabled, children }: TreeItem2Props,
+ ref: React.Ref,
+) {
+ const {
+ getRootProps,
+ getContentProps,
+ getLabelProps,
+ getGroupTransitionProps,
+ getIconContainerProps,
+ getLabelInputProps,
+ status,
+ } = useTreeItem2({ id, itemId, label, disabled, children, rootRef: ref });
+
+ return (
+
+
+
+
+
+
+
+ {status.editing ? (
+
+ ) : (
+
+ )}
+
+
+ {(Object.keys(STATUS_ICONS) as [keyof UseTreeItem2Status]).map(
+ (iconKey, index) => {
+ if (status[iconKey]) {
+ return (
+
+ {STATUS_ICONS[iconKey]}
+
+ );
+ }
+ return null;
+ },
+ )}
+
+
+ {children && }
+
+
+ );
+});
+
+export default function useTreeItem2HookStatus() {
+ return (
+
+
+ Boolean(item?.disabled)}
+ isItemEditable={(item) => Boolean(item?.editable)}
+ experimentalFeatures={{
+ labelEditing: true,
+ }}
+ />
+
+
+
+ );
+}
diff --git a/docs/data/tree-view/tree-item-customization/useTreeItem2HookStatus.tsx.preview b/docs/data/tree-view/tree-item-customization/useTreeItem2HookStatus.tsx.preview
new file mode 100644
index 0000000000000..bdd7c89341d10
--- /dev/null
+++ b/docs/data/tree-view/tree-item-customization/useTreeItem2HookStatus.tsx.preview
@@ -0,0 +1,14 @@
+
+ Boolean(item?.disabled)}
+ isItemEditable={(item) => Boolean(item?.editable)}
+ experimentalFeatures={{
+ labelEditing: true,
+ }}
+ />
+
+
\ No newline at end of file
diff --git a/docs/next-env.d.ts b/docs/next-env.d.ts
index a4a7b3f5cfa2f..4f11a03dc6cc3 100644
--- a/docs/next-env.d.ts
+++ b/docs/next-env.d.ts
@@ -2,4 +2,4 @@
///
// NOTE: This file should not be edited
-// see https://nextjs.org/docs/pages/building-your-application/configuring/typescript for more information.
+// see https://nextjs.org/docs/basic-features/typescript for more information.
diff --git a/docs/public/static/x/tree-view-illustrations/tree-item-dark.png b/docs/public/static/x/tree-view-illustrations/tree-item-dark.png
new file mode 100644
index 0000000000000..9cd285c3d2797
Binary files /dev/null and b/docs/public/static/x/tree-view-illustrations/tree-item-dark.png differ
diff --git a/docs/public/static/x/tree-view-illustrations/tree-item-light.png b/docs/public/static/x/tree-view-illustrations/tree-item-light.png
new file mode 100644
index 0000000000000..052d8359525c4
Binary files /dev/null and b/docs/public/static/x/tree-view-illustrations/tree-item-light.png differ
diff --git a/docs/src/modules/components/TreeItem2Anatomy.js b/docs/src/modules/components/TreeItem2Anatomy.js
new file mode 100644
index 0000000000000..2f46bb4dce947
--- /dev/null
+++ b/docs/src/modules/components/TreeItem2Anatomy.js
@@ -0,0 +1,22 @@
+import * as React from 'react';
+import { useTheme } from '@mui/material/styles';
+import Card from '@mui/material/Card';
+import CardMedia from '@mui/material/CardMedia';
+
+export default function TreeItem2Anatomy() {
+ const { palette } = useTheme();
+
+ const src =
+ palette.mode === 'light'
+ ? '/static/x/tree-view-illustrations/tree-item-light.png'
+ : '/static/x/tree-view-illustrations/tree-item-dark.png';
+ return (
+
+
+
+ );
+}
diff --git a/packages/x-tree-view/src/useTreeItem2/index.ts b/packages/x-tree-view/src/useTreeItem2/index.ts
index 94545e26b83b6..58154d6640e85 100644
--- a/packages/x-tree-view/src/useTreeItem2/index.ts
+++ b/packages/x-tree-view/src/useTreeItem2/index.ts
@@ -12,6 +12,7 @@ export type {
UseTreeItem2ContentSlotOwnProps,
UseTreeItem2LabelInputSlotOwnProps,
UseTreeItem2LabelSlotOwnProps,
+ UseTreeItem2CheckboxSlotOwnProps,
UseTreeItem2IconContainerSlotOwnProps,
UseTreeItem2GroupTransitionSlotOwnProps,
UseTreeItem2DragAndDropOverlaySlotOwnProps,
diff --git a/packages/x-tree-view/src/useTreeItem2/useTreeItem2.types.ts b/packages/x-tree-view/src/useTreeItem2/useTreeItem2.types.ts
index 9457cc1572509..68080b4f4f735 100644
--- a/packages/x-tree-view/src/useTreeItem2/useTreeItem2.types.ts
+++ b/packages/x-tree-view/src/useTreeItem2/useTreeItem2.types.ts
@@ -100,7 +100,7 @@ export type UseTreeItem2LabelInputSlotProps = ExternalProps
export interface UseTreeItem2CheckboxSlotOwnProps {
visible: boolean;
checked: boolean;
- onChange: React.ChangeEventHandler;
+ onChange: MuiCancellableEventHandler>;
disabled: boolean;
ref: React.RefObject;
tabIndex: -1;
diff --git a/scripts/x-tree-view-pro.exports.json b/scripts/x-tree-view-pro.exports.json
index ea69aaa8f832b..aa48d50761f16 100644
--- a/scripts/x-tree-view-pro.exports.json
+++ b/scripts/x-tree-view-pro.exports.json
@@ -64,6 +64,7 @@
{ "name": "unstable_resetCleanupTracking", "kind": "Variable" },
{ "name": "unstable_useTreeItem2", "kind": "Variable" },
{ "name": "useTreeItem2", "kind": "Variable" },
+ { "name": "UseTreeItem2CheckboxSlotOwnProps", "kind": "Interface" },
{ "name": "UseTreeItem2ContentSlotOwnProps", "kind": "Interface" },
{ "name": "UseTreeItem2DragAndDropOverlaySlotOwnProps", "kind": "Interface" },
{ "name": "UseTreeItem2GroupTransitionSlotOwnProps", "kind": "Interface" },
diff --git a/scripts/x-tree-view.exports.json b/scripts/x-tree-view.exports.json
index 676aa7f67abea..ad00319179cf5 100644
--- a/scripts/x-tree-view.exports.json
+++ b/scripts/x-tree-view.exports.json
@@ -68,6 +68,7 @@
{ "name": "unstable_resetCleanupTracking", "kind": "Variable" },
{ "name": "unstable_useTreeItem2", "kind": "Variable" },
{ "name": "useTreeItem2", "kind": "Variable" },
+ { "name": "UseTreeItem2CheckboxSlotOwnProps", "kind": "Interface" },
{ "name": "UseTreeItem2ContentSlotOwnProps", "kind": "Interface" },
{ "name": "UseTreeItem2DragAndDropOverlaySlotOwnProps", "kind": "Interface" },
{ "name": "UseTreeItem2GroupTransitionSlotOwnProps", "kind": "Interface" },