;
+
+ const { getRootProps, contextValue } = useTreeView({
+ disabledItemsFocusable,
+ expanded,
+ defaultExpanded,
+ onNodeToggle,
+ onNodeFocus,
+ disableSelection,
+ defaultSelected,
+ selected,
+ multiSelect,
+ onNodeSelect,
+ id,
+ defaultCollapseIcon,
+ defaultEndIcon,
+ defaultExpandIcon,
+ defaultParentIcon,
+ log,
+ plugins,
+ });
+
+ const rootProps = useSlotProps({
+ elementType: TreeViewRoot,
+ externalSlotProps: {},
+ externalForwardedProps: other,
+ getSlotProps: getRootProps,
+ ownerState,
+ });
+
+ return (
+
+ {children}
+
+ );
+}
+
+export default function HeadlessTreeView() {
+ return (
+ }
+ defaultExpandIcon={}
+ sx={{ height: 240, flexGrow: 1, maxWidth: 400, overflowY: 'auto' }}
+ >
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/docs/data/tree-view/headless/headless.md b/docs/data/tree-view/headless/headless.md
new file mode 100644
index 0000000000000..61a08edb5b334
--- /dev/null
+++ b/docs/data/tree-view/headless/headless.md
@@ -0,0 +1,14 @@
+---
+productId: material-ui
+title: Tree View Headless usage
+githubLabel: 'component: tree view'
+packageName: '@mui/x-tree-view'
+---
+
+# Tree View - Headless
+
+Experiment with headless tree view
+
+Open the console and interact with the tree view to see the expanded items being logged:
+
+{{"demo": "HeadlessTreeView.js"}}
diff --git a/docs/pages/x/react-tree-view/experiments/headless.js b/docs/pages/x/react-tree-view/experiments/headless.js
new file mode 100644
index 0000000000000..6d0bad999762a
--- /dev/null
+++ b/docs/pages/x/react-tree-view/experiments/headless.js
@@ -0,0 +1,7 @@
+import * as React from 'react';
+import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs';
+import * as pageProps from 'docsx/data/tree-view/headless/headless.md?@mui/markdown';
+
+export default function Page() {
+ return ;
+}
diff --git a/packages/x-tree-view/src/internals/models/plugin.ts b/packages/x-tree-view/src/internals/models/plugin.ts
index 4bbc15b61603c..e11c7d54122f4 100644
--- a/packages/x-tree-view/src/internals/models/plugin.ts
+++ b/packages/x-tree-view/src/internals/models/plugin.ts
@@ -4,10 +4,9 @@ import { TreeViewModel } from './treeView';
import type { TreeViewContextValue } from '../TreeViewProvider';
import type { MergePluginsProperty } from './helpers';
-export interface TreeViewPluginParams {
+export interface TreeViewPluginOptions {
instance: TreeViewUsedInstance;
- // TODO: Rename 'params'
- props: TreeViewUsedDefaultizedParams;
+ params: TreeViewUsedDefaultizedParams;
state: TreeViewUsedState;
models: TreeViewUsedModels;
setState: React.Dispatch>>;
@@ -36,16 +35,16 @@ export type TreeViewPluginSignature<
TModelNames extends keyof TDefaultizedParams,
TDependantPlugins extends readonly TreeViewAnyPluginSignature[],
> = {
- state: TState;
- instance: TInstance;
params: TParams;
defaultizedParams: TDefaultizedParams;
- dependantPlugins: TDependantPlugins;
+ instance: TInstance;
+ state: TState;
models: {
[TControlled in TModelNames]-?: TreeViewModel<
Exclude
>;
};
+ dependantPlugins: TDependantPlugins;
};
export type TreeViewAnyPluginSignature = {
@@ -74,7 +73,7 @@ export type TreeViewUsedModels =
TSignature['models'] & MergePluginsProperty;
export type TreeViewPlugin = {
- (options: TreeViewPluginParams): void | TreeViewResponse;
+ (options: TreeViewPluginOptions): void | TreeViewResponse;
getDefaultizedParams?: (
params: TreeViewUsedParams,
) => TSignature['defaultizedParams'];
diff --git a/packages/x-tree-view/src/internals/plugins/useTreeViewContextValueBuilder/useTreeViewContextValueBuilder.ts b/packages/x-tree-view/src/internals/plugins/useTreeViewContextValueBuilder/useTreeViewContextValueBuilder.ts
index e45e2aacf9326..a0e27dfa8c356 100644
--- a/packages/x-tree-view/src/internals/plugins/useTreeViewContextValueBuilder/useTreeViewContextValueBuilder.ts
+++ b/packages/x-tree-view/src/internals/plugins/useTreeViewContextValueBuilder/useTreeViewContextValueBuilder.ts
@@ -4,8 +4,8 @@ import { UseTreeViewContextValueBuilderSignature } from './useTreeViewContextVal
export const useTreeViewContextValueBuilder: TreeViewPlugin<
UseTreeViewContextValueBuilderSignature
-> = ({ instance, props }) => {
- const treeId = useId(props.id);
+> = ({ instance, params }) => {
+ const treeId = useId(params.id);
return {
getRootProps: () => ({
@@ -14,13 +14,13 @@ export const useTreeViewContextValueBuilder: TreeViewPlugin<
contextValue: {
treeId,
instance: instance as TreeViewInstance,
- multiSelect: props.multiSelect,
- disabledItemsFocusable: props.disabledItemsFocusable,
+ multiSelect: params.multiSelect,
+ disabledItemsFocusable: params.disabledItemsFocusable,
icons: {
- defaultCollapseIcon: props.defaultCollapseIcon,
- defaultEndIcon: props.defaultEndIcon,
- defaultExpandIcon: props.defaultExpandIcon,
- defaultParentIcon: props.defaultParentIcon,
+ defaultCollapseIcon: params.defaultCollapseIcon,
+ defaultEndIcon: params.defaultEndIcon,
+ defaultExpandIcon: params.defaultExpandIcon,
+ defaultParentIcon: params.defaultParentIcon,
},
},
};
diff --git a/packages/x-tree-view/src/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.ts b/packages/x-tree-view/src/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.ts
index ece8cc6e68717..2d94779186fd7 100644
--- a/packages/x-tree-view/src/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.ts
+++ b/packages/x-tree-view/src/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.ts
@@ -6,7 +6,7 @@ import { UseTreeViewExpansionSignature } from './useTreeViewExpansion.types';
export const useTreeViewExpansion: TreeViewPlugin = ({
instance,
- props,
+ params,
models,
}) => {
const isNodeExpanded = React.useCallback(
@@ -37,8 +37,8 @@ export const useTreeViewExpansion: TreeViewPlugin
newExpanded = [nodeId].concat(models.expanded.value);
}
- if (props.onNodeToggle) {
- props.onNodeToggle(event, newExpanded);
+ if (params.onNodeToggle) {
+ params.onNodeToggle(event, newExpanded);
}
models.expanded.setValue(newExpanded);
@@ -58,8 +58,8 @@ export const useTreeViewExpansion: TreeViewPlugin
if (diff.length > 0) {
models.expanded.setValue(newExpanded);
- if (props.onNodeToggle) {
- props.onNodeToggle(event, newExpanded);
+ if (params.onNodeToggle) {
+ params.onNodeToggle(event, newExpanded);
}
}
};
diff --git a/packages/x-tree-view/src/internals/plugins/useTreeViewFocus/useTreeViewFocus.ts b/packages/x-tree-view/src/internals/plugins/useTreeViewFocus/useTreeViewFocus.ts
index 98a6cc7baac93..b6ac0bd2c7070 100644
--- a/packages/x-tree-view/src/internals/plugins/useTreeViewFocus/useTreeViewFocus.ts
+++ b/packages/x-tree-view/src/internals/plugins/useTreeViewFocus/useTreeViewFocus.ts
@@ -7,7 +7,7 @@ import { UseTreeViewFocusSignature } from './useTreeViewFocus.types';
export const useTreeViewFocus: TreeViewPlugin = ({
instance,
- props,
+ params,
state,
setState,
models,
@@ -26,8 +26,8 @@ export const useTreeViewFocus: TreeViewPlugin = ({
if (nodeId) {
setFocusedNodeId(nodeId);
- if (props.onNodeFocus) {
- props.onNodeFocus(event, nodeId);
+ if (params.onNodeFocus) {
+ params.onNodeFocus(event, nodeId);
}
}
});
diff --git a/packages/x-tree-view/src/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.ts b/packages/x-tree-view/src/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.ts
index 3187c639b1e5c..71baf770a370e 100644
--- a/packages/x-tree-view/src/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.ts
+++ b/packages/x-tree-view/src/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.ts
@@ -27,7 +27,7 @@ function findNextFirstChar(firstChars: string[], startIndex: number, char: strin
export const useTreeViewKeyboardNavigation: TreeViewPlugin<
UseTreeViewKeyboardNavigationSignature
-> = ({ instance, props, state }) => {
+> = ({ instance, params, state }) => {
const theme = useTheme();
const isRtl = theme.direction === 'rtl';
const firstCharMap = React.useRef<{ [nodeId: string]: string }>({});
@@ -93,7 +93,7 @@ export const useTreeViewKeyboardNavigation: TreeViewPlugin<
Object.keys(firstCharMap.current).forEach((mapNodeId) => {
const map = instance.getNode(mapNodeId);
const visible = map.parentId ? instance.isNodeExpanded(map.parentId) : true;
- const shouldBeSkipped = props.disabledItemsFocusable
+ const shouldBeSkipped = params.disabledItemsFocusable
? false
: instance.isNodeDisabled(mapNodeId);
@@ -164,11 +164,11 @@ export const useTreeViewKeyboardNavigation: TreeViewPlugin<
const ctrlPressed = event.ctrlKey || event.metaKey;
switch (key) {
case ' ':
- if (!props.disableSelection && !instance.isNodeDisabled(state.focusedNodeId)) {
+ if (!params.disableSelection && !instance.isNodeDisabled(state.focusedNodeId)) {
flag = true;
- if (props.multiSelect && event.shiftKey) {
+ if (params.multiSelect && event.shiftKey) {
instance.selectRange(event, { end: state.focusedNodeId });
- } else if (props.multiSelect) {
+ } else if (params.multiSelect) {
instance.selectNode(event, state.focusedNodeId, true);
} else {
instance.selectNode(event, state.focusedNodeId);
@@ -181,9 +181,9 @@ export const useTreeViewKeyboardNavigation: TreeViewPlugin<
if (instance.isNodeExpandable(state.focusedNodeId)) {
instance.toggleNodeExpansion(event, state.focusedNodeId);
flag = true;
- } else if (!props.disableSelection) {
+ } else if (!params.disableSelection) {
flag = true;
- if (props.multiSelect) {
+ if (params.multiSelect) {
instance.selectNode(event, state.focusedNodeId, true);
} else {
instance.selectNode(event, state.focusedNodeId);
@@ -193,14 +193,14 @@ export const useTreeViewKeyboardNavigation: TreeViewPlugin<
event.stopPropagation();
break;
case 'ArrowDown':
- if (props.multiSelect && event.shiftKey && !props.disableSelection) {
+ if (params.multiSelect && event.shiftKey && !params.disableSelection) {
selectNextNode(event, state.focusedNodeId);
}
instance.focusNode(event, getNextNode(instance, state.focusedNodeId));
flag = true;
break;
case 'ArrowUp':
- if (props.multiSelect && event.shiftKey && !props.disableSelection) {
+ if (params.multiSelect && event.shiftKey && !params.disableSelection) {
selectPreviousNode(event, state.focusedNodeId);
}
instance.focusNode(event, getPreviousNode(instance, state.focusedNodeId));
@@ -222,10 +222,10 @@ export const useTreeViewKeyboardNavigation: TreeViewPlugin<
break;
case 'Home':
if (
- props.multiSelect &&
+ params.multiSelect &&
ctrlPressed &&
event.shiftKey &&
- !props.disableSelection &&
+ !params.disableSelection &&
!instance.isNodeDisabled(state.focusedNodeId)
) {
instance.rangeSelectToFirst(event, state.focusedNodeId);
@@ -235,10 +235,10 @@ export const useTreeViewKeyboardNavigation: TreeViewPlugin<
break;
case 'End':
if (
- props.multiSelect &&
+ params.multiSelect &&
ctrlPressed &&
event.shiftKey &&
- !props.disableSelection &&
+ !params.disableSelection &&
!instance.isNodeDisabled(state.focusedNodeId)
) {
instance.rangeSelectToLast(event, state.focusedNodeId);
@@ -251,10 +251,10 @@ export const useTreeViewKeyboardNavigation: TreeViewPlugin<
instance.expandAllSiblings(event, state.focusedNodeId);
flag = true;
} else if (
- props.multiSelect &&
+ params.multiSelect &&
ctrlPressed &&
key.toLowerCase() === 'a' &&
- !props.disableSelection
+ !params.disableSelection
) {
instance.selectRange(event, {
start: getFirstNode(instance),
diff --git a/packages/x-tree-view/src/internals/plugins/useTreeViewNodes/useTreeViewNodes.ts b/packages/x-tree-view/src/internals/plugins/useTreeViewNodes/useTreeViewNodes.ts
index b993aaeae030f..e356bc5fa7a2b 100644
--- a/packages/x-tree-view/src/internals/plugins/useTreeViewNodes/useTreeViewNodes.ts
+++ b/packages/x-tree-view/src/internals/plugins/useTreeViewNodes/useTreeViewNodes.ts
@@ -7,7 +7,7 @@ import { UseTreeViewNodesSignature } from './useTreeViewNodes.types';
export const useTreeViewNodes: TreeViewPlugin = ({
instance,
- props,
+ params,
rootRef,
}) => {
const nodeMap = React.useRef<{ [nodeId: string]: TreeViewNode }>({});
@@ -51,7 +51,7 @@ export const useTreeViewNodes: TreeViewPlugin = ({
const getNavigableChildrenIds = (nodeId: string | null) => {
let childrenIds = instance.getChildrenIds(nodeId);
- if (!props.disabledItemsFocusable) {
+ if (!params.disabledItemsFocusable) {
childrenIds = childrenIds.filter((node) => !instance.isNodeDisabled(node));
}
return childrenIds;
diff --git a/packages/x-tree-view/src/internals/plugins/useTreeViewSelection/useTreeViewSelection.ts b/packages/x-tree-view/src/internals/plugins/useTreeViewSelection/useTreeViewSelection.ts
index 11b3670c40b69..ce634bbecc694 100644
--- a/packages/x-tree-view/src/internals/plugins/useTreeViewSelection/useTreeViewSelection.ts
+++ b/packages/x-tree-view/src/internals/plugins/useTreeViewSelection/useTreeViewSelection.ts
@@ -14,7 +14,7 @@ import { findOrderInTremauxTree } from './useTreeViewSelection.utils';
export const useTreeViewSelection: TreeViewPlugin> = ({
instance,
- props,
+ params,
models,
}) => {
const lastSelectedNode = React.useRef(null);
@@ -27,7 +27,7 @@ export const useTreeViewSelection: TreeViewPlugin {
- if (props.disableSelection) {
+ if (params.disableSelection) {
return;
}
@@ -40,8 +40,8 @@ export const useTreeViewSelection: TreeViewPlugin['onNodeSelect'])!(
+ if (params.onNodeSelect) {
+ (params.onNodeSelect as UseTreeViewSelectionDefaultizedParameters['onNodeSelect'])!(
event,
newSelected,
);
@@ -50,10 +50,10 @@ export const useTreeViewSelection: TreeViewPlugin['onNodeSelect'])!(
+ if (params.onNodeSelect) {
+ (params.onNodeSelect as UseTreeViewSelectionDefaultizedParameters['onNodeSelect'])!(
event,
base,
);
@@ -131,8 +131,8 @@ export const useTreeViewSelection: TreeViewPlugin newSelected.indexOf(id) === i);
- if (props.onNodeSelect) {
- (props.onNodeSelect as UseTreeViewSelectionDefaultizedParameters['onNodeSelect'])!(
+ if (params.onNodeSelect) {
+ (params.onNodeSelect as UseTreeViewSelectionDefaultizedParameters['onNodeSelect'])!(
event,
newSelected,
);
@@ -142,7 +142,7 @@ export const useTreeViewSelection: TreeViewPlugin {
- if (props.disableSelection) {
+ if (params.disableSelection) {
return;
}
@@ -191,7 +191,7 @@ export const useTreeViewSelection: TreeViewPlugin ({
- 'aria-multiselectable': props.multiSelect,
+ 'aria-multiselectable': params.multiSelect,
}),
};
};
diff --git a/packages/x-tree-view/src/internals/useTreeView/useTreeView.ts b/packages/x-tree-view/src/internals/useTreeView/useTreeView.ts
index d191d0e9121a7..4921e9dce76f5 100644
--- a/packages/x-tree-view/src/internals/useTreeView/useTreeView.ts
+++ b/packages/x-tree-view/src/internals/useTreeView/useTreeView.ts
@@ -63,7 +63,7 @@ export const useTreeView = ) => {
const pluginResponse =
- plugin({ instance, props: params, state, setState, rootRef: innerRootRef, models }) || {};
+ plugin({ instance, params: params, state, setState, rootRef: innerRootRef, models }) || {};
if (pluginResponse.getRootProps) {
rootPropsGetters.push(pluginResponse.getRootProps);