Skip to content

Commit

Permalink
Merge pull request #313 from sparksuite/chang-focus-behavior-on-click
Browse files Browse the repository at this point in the history
Change focus behavior on click
  • Loading branch information
WesCossick authored Feb 22, 2023
2 parents dc08298 + ddf6861 commit af74c87
Show file tree
Hide file tree
Showing 5 changed files with 17 additions and 15 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-accessible-dropdown-menu-hook",
"version": "3.2.0",
"version": "4.0.0",
"description": "A simple Hook for creating fully accessible dropdown menus in React",
"main": "dist/use-dropdown-menu.js",
"types": "dist/use-dropdown-menu.d.ts",
Expand Down
14 changes: 8 additions & 6 deletions src/use-dropdown-menu.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,16 +95,16 @@ it('Moves the focus to the first menu item after pressing space while focused on
expect(screen.getByText('1 Item')).toHaveFocus();
});

it('Moves the focus to the first menu item after clicking the menu to open it', async () => {
const { user } = setup(<TestComponent />);
it('Moves the focus to the first menu item after clicking the menu to open it, if `focusFirstItemOnClick` is specified', async () => {
const { user } = setup(<TestComponent options={{ focusFirstItemOnClick: true }} />);

await user.click(screen.getByText('Primary'));

expect(screen.getByText('1 Item')).toHaveFocus();
});

it('Moves the focus to the first menu item after clicking the menu to open it, then pressing tab while focused on the menu button, if `disableFocusFirstItemOnClick` is specified', async () => {
const { user } = setup(<TestComponent options={{ disableFocusFirstItemOnClick: true }} />);
it('Moves the focus to the first menu item after clicking the menu to open it, then pressing tab while focused on the menu button', async () => {
const { user } = setup(<TestComponent />);

await user.click(screen.getByText('Primary'));

Expand All @@ -115,8 +115,8 @@ it('Moves the focus to the first menu item after clicking the menu to open it, t
expect(screen.getByText('1 Item')).toHaveFocus();
});

it('Moves the focus to the first menu item after clicking the menu to open it, then pressing arrow down while focused on the menu button, if `disableFocusFirstItemOnClick` is specified', async () => {
const { user } = setup(<TestComponent options={{ disableFocusFirstItemOnClick: true }} />);
it('Moves the focus to the first menu item after clicking the menu to open it, then pressing arrow down while focused on the menu button', async () => {
const { user } = setup(<TestComponent />);

await user.click(screen.getByText('Primary'));

Expand Down Expand Up @@ -308,6 +308,8 @@ it('Can navigate to a dynamically-added item', async () => {

await user.click(screen.getByText('Primary'));

await user.keyboard('{ArrowDown}');

for (let i = 0; i < 4; i += 1) {
await user.keyboard('{ArrowDown}');
}
Expand Down
6 changes: 3 additions & 3 deletions src/use-dropdown-menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ interface ButtonProps<ButtonElement extends HTMLElement>

// A custom Hook that abstracts away the listeners/controls for dropdown menus
export interface DropdownMenuOptions {
disableFocusFirstItemOnClick?: boolean;
focusFirstItemOnClick?: boolean;
}

interface DropdownMenuResponse<ButtonElement extends HTMLElement> {
Expand Down Expand Up @@ -64,7 +64,7 @@ export default function useDropdownMenu<ButtonElement extends HTMLElement = HTML
}

// If the menu is currently open focus on the first item in the menu
if (isOpen && !options?.disableFocusFirstItemOnClick) {
if (isOpen && (!clickedOpen.current || options?.focusFirstItemOnClick)) {
moveFocus(0);
} else if (!isOpen) {
clickedOpen.current = false;
Expand Down Expand Up @@ -159,7 +159,7 @@ export default function useDropdownMenu<ButtonElement extends HTMLElement = HTML
setIsOpen(false);
}
} else {
if (options?.disableFocusFirstItemOnClick) {
if (!options?.focusFirstItemOnClick) {
clickedOpen.current = !isOpen;
}

Expand Down
4 changes: 2 additions & 2 deletions test-projects/browser/src/app.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ it('Has the correct page title', async () => {
await expect(page.title()).resolves.toMatch('Browser');
});

it('Focuses the first menu item when menu button is clicked', async () => {
it('Maintains focus when menu button is clicked', async () => {
await page.click('#menu-button');
await menuOpen();

expect(await currentFocusID()).toBe('menu-item-1');
expect(await currentFocusID()).toBe('menu-button');
});

it('Focuses on the menu button after pressing escape', async () => {
Expand Down
6 changes: 3 additions & 3 deletions website/docs/design/options.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ You can customize the behavior with options, passed as the second argument.

Option | Default | Possible values
:--- | :--- | :---
`disableFocusFirstItemOnClick` | `false` | `boolean`
`focusFirstItemOnClick` | `false` | `boolean`

Option | Explanation
:--- | :---
`disableFocusFirstItemOnClick` | If specified as `true` the default behavior of focusing the first menu item on click will be disabled. The menu button will instead retain focus.
`focusFirstItemOnClick` | If specified as `true`, the first menu item will be focused when the menu is opened via a click (in addition to via a keyboard interaction).

```js
useDropdownMenu(numberOfItems, {
disableFocusFirstItemOnClick: true,
focusFirstItemOnClick: true,
});
```

0 comments on commit af74c87

Please sign in to comment.