diff --git a/.changeset/ten-mirrors-refuse.md b/.changeset/ten-mirrors-refuse.md new file mode 100644 index 00000000000..afb2da1853a --- /dev/null +++ b/.changeset/ten-mirrors-refuse.md @@ -0,0 +1,5 @@ +--- +'@primer/react': minor +--- + +TreeView: Adds `aria-label` prop to `TreeView.Subtree` diff --git a/packages/react/src/TreeView/TreeView.docs.json b/packages/react/src/TreeView/TreeView.docs.json index 2cb75ac6eb5..91404fc2375 100644 --- a/packages/react/src/TreeView/TreeView.docs.json +++ b/packages/react/src/TreeView/TreeView.docs.json @@ -190,6 +190,11 @@ "name": "count", "type": "number", "description": "The number of items expected to be in the subtree. When in the loading state, the subtree will render a skeleton loading placeholder with the specified count of items" + }, + { + "name": "aria-label", + "type": "string", + "description": "An accessible name for the subtree. It is recommended that you provide a short version of the parent list item's name as the name of the subtree." } ] }, diff --git a/packages/react/src/TreeView/TreeView.test.tsx b/packages/react/src/TreeView/TreeView.test.tsx index 34dc96e5df9..727df4806c3 100644 --- a/packages/react/src/TreeView/TreeView.test.tsx +++ b/packages/react/src/TreeView/TreeView.test.tsx @@ -238,7 +238,7 @@ describe('Markup', () => { }) it('should render with containIntrinsicSize', () => { - const {getByLabelText} = renderWithTheme( + const {getByText} = renderWithTheme( Parent @@ -253,9 +253,9 @@ describe('Markup', () => { // The test runner removes the contain-intrinsic-size and content-visibility // properties, so we can only test that the elements are still rendering. - const childItem = getByLabelText(/Child/) + const childItem = getByText(/Child/) expect(childItem).toBeInTheDocument() - const parentItem = getByLabelText(/Parent/) + const parentItem = getByText(/Parent/) expect(parentItem).toBeInTheDocument() }) diff --git a/packages/react/src/TreeView/TreeView.tsx b/packages/react/src/TreeView/TreeView.tsx index 4c0fd101249..18c753fdbd1 100644 --- a/packages/react/src/TreeView/TreeView.tsx +++ b/packages/react/src/TreeView/TreeView.tsx @@ -647,14 +647,16 @@ export type TreeViewSubTreeProps = { * Display a skeleton loading state with the specified count of items */ count?: number + 'aria-label'?: string } -const SubTree: React.FC = ({count, state, children}) => { +const SubTree: React.FC = ({count, state, children, 'aria-label': ariaLabel}) => { const {announceUpdate} = React.useContext(RootContext) const {itemId, isExpanded, isSubTreeEmpty, setIsSubTreeEmpty} = React.useContext(ItemContext) const loadingItemRef = React.useRef(null) const ref = React.useRef(null) const [loadingFocused, setLoadingFocused] = React.useState(false) + const [subTreeLabel, setSubTreeLabel] = React.useState('') const previousState = usePreviousValue(state) const {safeSetTimeout} = useSafeTimeout() @@ -676,6 +678,8 @@ const SubTree: React.FC = ({count, state, children}) => { React.useEffect(() => { const parentElement = document.getElementById(itemId) if (!parentElement) return + + setSubTreeLabel(getAccessibleName(parentElement)) if (previousState === 'loading' && state === 'done') { // Announce update to screen readers const parentName = getAccessibleName(parentElement) @@ -753,6 +757,7 @@ const SubTree: React.FC = ({count, state, children}) => { }} // @ts-ignore Box doesn't have type support for `ref` used in combination with `as` ref={ref} + aria-label={ariaLabel || subTreeLabel} > {state === 'loading' ? : children} {isSubTreeEmpty && state !== 'loading' ? : null}