diff --git a/.changeset/itchy-monkeys-repeat.md b/.changeset/itchy-monkeys-repeat.md new file mode 100644 index 000000000..53ccd6479 --- /dev/null +++ b/.changeset/itchy-monkeys-repeat.md @@ -0,0 +1,7 @@ +--- +"@frameless/ui": patch +--- + +Verbeterde toegankelijkheid: skiplinks naar het hoofdmenu focussen nu direct op de eerste menulink, waardoor toetsenbordnavigatie soepeler verloopt. + +([GitHub Issue Frameless/strapi#761](https://github.com/frameless/strapi/issues/761)) diff --git a/packages/ui/src/components/Navigation/NavigationList/index.test.tsx b/packages/ui/src/components/Navigation/NavigationList/index.test.tsx index af1937d36..e4ef6f635 100644 --- a/packages/ui/src/components/Navigation/NavigationList/index.test.tsx +++ b/packages/ui/src/components/Navigation/NavigationList/index.test.tsx @@ -1,4 +1,4 @@ -import { fireEvent, render, screen } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; import '@testing-library/jest-dom'; import { NavigationList } from './index'; import { NavigationListType } from '../index'; @@ -106,23 +106,17 @@ describe('NavigationList', () => { expect(navigationList).toBeInTheDocument(); expect(navigationList).toHaveClass('utrecht-navigation__list--sub-list'); }); - test('focuses on the first link when the list receives focus', () => { - render(); + test('applies targetId to first link when provided', () => { + const targetId = 'main-nav'; + render(); const firstLink = screen.getByText('Home'); - const navList = firstLink.closest('ul'); - expect(navList).toHaveAttribute('tabIndex', '-1'); - - fireEvent.focus(navList as HTMLUListElement); - expect(firstLink).toHaveFocus(); + expect(firstLink.getAttribute('id')).toEqual(targetId); }); - test('does not focus the first link on mobile focus', () => { - render(); - const firstLink = screen.getByText('Home'); - const navList = firstLink.closest('ul'); - expect(navList).toHaveAttribute('tabIndex', '-1'); - fireEvent.focus(navList as HTMLUListElement); - // Ensure the focus behavior is explicitly prevented in mobile mode - expect(firstLink).not.toHaveFocus(); + test('does not apply id to other links', () => { + const targetId = 'main-nav'; + render(); + const secondLink = screen.getByText('About'); + expect(secondLink).not.toHaveAttribute('id'); }); }); diff --git a/packages/ui/src/components/Navigation/NavigationList/index.tsx b/packages/ui/src/components/Navigation/NavigationList/index.tsx index ba2d8edd2..93f9a5131 100644 --- a/packages/ui/src/components/Navigation/NavigationList/index.tsx +++ b/packages/ui/src/components/Navigation/NavigationList/index.tsx @@ -1,6 +1,5 @@ import classnames from 'classnames/bind'; -import { DetailedHTMLProps, HTMLAttributes, PropsWithChildren, useRef } from 'react'; -import { FocusEvent } from 'react'; +import { DetailedHTMLProps, HTMLAttributes, PropsWithChildren } from 'react'; import styles from './index.module.scss'; import { NavigationItem } from '../NavigationItem'; import { NavigationLink } from '../NavigationLink'; @@ -11,6 +10,7 @@ export interface NavigationListProps extends DetailedHTMLProps) => { - const navListRef = useRef(null); - const navLinkRef = useRef(null); - - // focus on first link in list when list is focused - const onNavListLinkFocusHandler = (event: FocusEvent) => { - if (mobile) return; // prevent behavior on mobile - if (event.target !== navListRef.current) return; // ignore bubbling focus event in React - - if (navListRef.current && navLinkRef?.current) { - navLinkRef.current.focus(); - } - }; - return (
    {children} @@ -76,7 +61,7 @@ export const NavigationList = ({ mobile={mobile} href={item.href} isCurrent={item.isCurrent} - ref={isTheFirstElement ? navLinkRef : null} + id={isTheFirstElement ? targetId : undefined} marker={mobile && } > {item.textContent} diff --git a/packages/ui/src/components/Navigation/index.tsx b/packages/ui/src/components/Navigation/index.tsx index eff425dcd..6e606ca65 100644 --- a/packages/ui/src/components/Navigation/index.tsx +++ b/packages/ui/src/components/Navigation/index.tsx @@ -82,7 +82,7 @@ export const Navigation = forwardRef( {...restProps} > {!visible ? ( - + ) : (