Skip to content

Commit 4cca0e9

Browse files
authored
ActionList: Add new prop disableFocusZone (#6116)
1 parent 737c672 commit 4cca0e9

File tree

4 files changed

+45
-2
lines changed

4 files changed

+45
-2
lines changed

.changeset/clever-pans-tap.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@primer/react': minor
3+
---
4+
5+
ActionList: Add new prop `disableFocusZone` to disable the default focus zone provided

packages/react/src/ActionList/ActionList.test.tsx

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,4 +149,29 @@ describe('ActionList', () => {
149149
expect(container.querySelector('.leading')).toBeInTheDocument()
150150
expect(container.querySelector('.description')).toBeInTheDocument()
151151
})
152+
153+
it('should not be navigatable with arrow keys if `disableFocusZone` is true', async () => {
154+
const {container} = HTMLRender(
155+
<ActionList role="listbox" aria-label="Select a project" disableFocusZone={true}>
156+
<ActionList.Item role="option">Option 1</ActionList.Item>
157+
<ActionList.Item role="option">Option 2</ActionList.Item>
158+
<ActionList.Item role="option" disabled>
159+
Option 3
160+
</ActionList.Item>
161+
<ActionList.Item role="option">Option 4</ActionList.Item>
162+
<ActionList.Item role="option" inactiveText="Unavailable due to an outage">
163+
Option 5
164+
</ActionList.Item>
165+
</ActionList>,
166+
)
167+
168+
await userEvent.tab() // tab into the story, this should focus on the first button
169+
expect(document.activeElement).toHaveTextContent('Option 1')
170+
171+
await userEvent.keyboard('{ArrowDown}')
172+
expect(document.activeElement).toHaveTextContent('Option 1')
173+
174+
expect(container.querySelector('li[aria-disabled="true"]')?.nextElementSibling).toHaveTextContent('Option 4')
175+
expect(container.querySelector('li[aria-disabled="true"]')?.nextElementSibling).toHaveAttribute('tabindex', '0')
176+
})
152177
})

packages/react/src/ActionList/List.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,16 @@ import {BoxWithFallback} from '../internal/components/BoxWithFallback'
1414

1515
export const List = React.forwardRef<HTMLUListElement, ActionListProps>(
1616
(
17-
{variant = 'inset', selectionVariant, showDividers = false, role, sx: sxProp = defaultSxProp, className, ...props},
17+
{
18+
variant = 'inset',
19+
selectionVariant,
20+
showDividers = false,
21+
role,
22+
sx: sxProp = defaultSxProp,
23+
disableFocusZone = false,
24+
className,
25+
...props
26+
},
1827
forwardedRef,
1928
): JSX.Element => {
2029
const [slots, childrenWithoutSlots] = useSlots(props.children, {
@@ -37,7 +46,7 @@ export const List = React.forwardRef<HTMLUListElement, ActionListProps>(
3746

3847
let enableFocusZone = false
3948
if (enableFocusZoneFromContainer !== undefined) enableFocusZone = enableFocusZoneFromContainer
40-
else if (listRole) enableFocusZone = ['menu', 'menubar', 'listbox'].includes(listRole)
49+
else if (listRole && !disableFocusZone) enableFocusZone = ['menu', 'menubar', 'listbox'].includes(listRole)
4150

4251
useFocusZone({
4352
disabled: !enableFocusZone,

packages/react/src/ActionList/shared.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,10 @@ export type ActionListProps = React.PropsWithChildren<{
136136
* The ARIA role describing the function of `List` component. `listbox` or `menu` are a common values.
137137
*/
138138
role?: AriaRole
139+
/**
140+
* Disables the focus zone for the list if applicable. Focus zone is enabled by default for `menu` and `listbox` roles, or components such as `ActionMenu` and `SelectPanel`.
141+
*/
142+
disableFocusZone?: boolean
139143
className?: string
140144
}> &
141145
SxProp

0 commit comments

Comments
 (0)