Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions change/@fluentui-react-tree-tree-deep-level-fix.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
Copy link
Copy Markdown

@github-actions github-actions Bot Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🕵🏾‍♀️ visual changes to review in the Visual Change Report

vr-tests-react-components/Charts-DonutChart 1 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/Charts-DonutChart.Dynamic - Dark Mode.default.chromium.png 7530 Changed
vr-tests-react-components/Menu Converged - submenuIndicator slotted content 2 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/Menu Converged - submenuIndicator slotted content.default - RTL.submenus open.chromium.png 599 Changed
vr-tests-react-components/Menu Converged - submenuIndicator slotted content.default.submenus open.chromium.png 605 Changed
vr-tests-react-components/Positioning 2 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/Positioning.Positioning end.updated 2 times.chromium.png 962 Changed
vr-tests-react-components/Positioning.Positioning end.chromium.png 620 Changed
vr-tests-react-components/ProgressBar converged 2 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/ProgressBar converged.Indeterminate + thickness - Dark Mode.default.chromium.png 58 Changed
vr-tests-react-components/ProgressBar converged.Indeterminate + thickness.default.chromium.png 159 Changed

"type": "patch",
"comment": "fix(react-tree): support indentation for TreeItem levels greater than 10 via inline CSS variable fallback",
"packageName": "@fluentui/react-tree",
"email": "198982749+Copilot@users.noreply.github.com",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { isConformant } from '../../testing/isConformant';
import type { TreeItemProps } from './TreeItem.types';
import { treeItemClassNames } from './useTreeItemStyles.styles';
import { Tree } from '../../Tree';
import { treeItemLevelToken } from '../../utils/tokens';

describe('TreeItem', () => {
isConformant<TreeItemProps>({
Expand Down Expand Up @@ -51,4 +52,38 @@ describe('TreeItem', () => {
fireEvent.click(result.getByText('Default TreeItem'));
expect(handleOpenChange).not.toHaveBeenCalled();
});

it('should set the level CSS variable via inline style for levels greater than 10', () => {
const depth = 12;
const openItems: string[] = [];
const renderNestedTree = (current: number): React.ReactElement => {
if (current > 1) {
openItems.push(`item-${current}`);
}
return (
<TreeItem value={`item-${current}`} itemType={current === 1 ? 'leaf' : 'branch'}>
<span>{`level ${current}`}</span>
{current > 1 ? <Tree>{renderNestedTree(current - 1)}</Tree> : null}
</TreeItem>
);
};
const treeContent = renderNestedTree(depth);

const result = render(<Tree defaultOpenItems={openItems}>{treeContent}</Tree>);

const treeItems = result.container.querySelectorAll<HTMLElement>(`.${treeItemClassNames.root}`);
expect(treeItems).toHaveLength(depth);

// Levels 1..10 are handled by static classes and should not set the inline CSS variable
// Levels > 10 fall back to an inline CSS variable for the indentation
treeItems.forEach(item => {
const ariaLevel = Number(item.getAttribute('aria-level'));
const inlineLevel = item.style.getPropertyValue(treeItemLevelToken);
if (ariaLevel > 10) {
expect(inlineLevel).toBe(String(ariaLevel));
} else {
expect(inlineLevel).toBe('');
}
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,17 @@ export const useTreeItemStyles_unstable = (state: TreeItemState): TreeItemState
state.root.className,
);

// For levels beyond the statically generated classes (> 10), fall back to an
// inline style that sets the indentation CSS variable dynamically. This avoids
// generating an unbounded number of atomic classes while still supporting
// arbitrarily deep trees. User-provided inline styles take precedence.
if (!isStaticallyDefinedLevel(level)) {
state.root.style = {
[treeItemLevelToken]: level,
...state.root.style,
};
}

return state;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ InlineStylingTreeItemLevel.parameters = {
docs: {
description: {
story: `
The tree component supports nested styling up to 10 levels, limited by performance considerations. For more than 10 levels of nesting, use dynamic styling instead. Below is an example of how to apply custom inline styles to create dynamic tree item levels, overriding the default static styles.
The tree component generates static styles for the first 10 nesting levels (for performance reasons) and automatically falls back to an inline CSS variable for deeper levels, so arbitrarily deep trees indent correctly out of the box. Below is an example of how to apply custom inline styles to create dynamic tree item levels, overriding the default static styles.
`,
},
},
Expand Down
Loading