Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
5 changes: 5 additions & 0 deletions .changeset/few-deers-work.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@primer/react": patch
---

TreeView: When moving focus to TreeView, the current item will be focused by default.
14 changes: 14 additions & 0 deletions src/TreeView/TreeView.features.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -773,6 +773,20 @@ export const ContainIntrinsicSize: Story = () => {
)
}

export const InitialFocus: Story = () => (
<div>
<Button>Focusable element before TreeView</Button>
<TreeView aria-label="Test tree">
<TreeView.Item id="item-1">Item 1</TreeView.Item>
<TreeView.Item id="item-2" current>
Item 2
</TreeView.Item>
<TreeView.Item id="item-3">Item 3</TreeView.Item>
</TreeView>
<Button>Focusable element after TreeView</Button>
</div>
)

ContainIntrinsicSize.parameters = {
chromatic: {disableSnapshot: true},
}
Expand Down
3 changes: 0 additions & 3 deletions src/TreeView/TreeView.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1224,9 +1224,6 @@ describe('Asyncronous loading', () => {
// Parent item should be expanded
expect(parentItem).toHaveAttribute('aria-expanded', 'true')

// Focus first item
parentItem.focus()

// Press ←
fireEvent.keyDown(document.activeElement || document.body, {key: 'ArrowLeft'})

Expand Down
17 changes: 17 additions & 0 deletions src/TreeView/useRovingTabIndex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,23 @@ export function useRovingTabIndex({containerRef}: {containerRef: React.RefObject

return getNextFocusableElement(from, event) ?? from
},
focusInStrategy: () => {
const currentItem = containerRef.current?.querySelector('[aria-current]')
const firstItem = containerRef.current?.querySelector('[role="treeitem"]')

// Focus the aria-current item if it exists
if (currentItem instanceof HTMLElement) {
return currentItem
}

// Otherwise, focus the activeElement if it's a treeitem
if (document.activeElement instanceof HTMLElement && containerRef.current?.contains(document.activeElement)) {
return document.activeElement
}

// Otherwise, focus the first treeitem
return firstItem instanceof HTMLElement ? firstItem : undefined
},
})
}

Expand Down