Put the carousel's tab stop on its items, as M3 asks
Plan step 19, containment.md C-18. The row was the focusable `region` and the items were not focusable at all, which is the thing M3's accessibility page draws a Don't for: "use Tab to place initial focus on the first carousel item", "avoid focusing on the carousel container". Each item is now `tabindex="0"` with the focus ring drawn inside it, the row is out of the tab order, and from a focused item the arrows move one item (moving focus with them), Home and End go to the ends, and Space or Enter opens one that is not fully in view. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9
This commit is contained in:
co-authored by
Claude Opus 5
parent
ad37862a9f
commit
9875ba156e
@@ -60,7 +60,7 @@ function onCarousel(int $index, string $body, string $scope = '#carousel'): stri
|
||||
JS;
|
||||
}
|
||||
|
||||
const FIRST_SCROLLER = '#carousel [role="region"] >> nth=0';
|
||||
const FIRST_ITEM = '#carousel [data-material-carousel-item] >> nth=0';
|
||||
|
||||
function carouselShowcase(array $options = [])
|
||||
{
|
||||
@@ -110,19 +110,21 @@ it('moves one item with the next and previous buttons', function () {
|
||||
it('moves one item with the arrow keys, and to the ends with Home and End', function () {
|
||||
$page = carouselShowcase();
|
||||
|
||||
$page->keys(FIRST_SCROLLER, 'ArrowRight')
|
||||
->assertScript(onCarousel(0, 'return at(1)'));
|
||||
// M3 puts the tab stop on the item, so the keys are the focused item's and each one moves
|
||||
// focus to the item it scrolls to.
|
||||
$page->keys(FIRST_ITEM, 'ArrowRight')
|
||||
->assertScript(onCarousel(0, 'return at(1) && document.activeElement === items[1]'));
|
||||
|
||||
$page->keys(FIRST_SCROLLER, 'ArrowRight')
|
||||
$page->keys(':focus', 'ArrowRight')
|
||||
->assertScript(onCarousel(0, 'return at(2)'));
|
||||
|
||||
$page->keys(FIRST_SCROLLER, 'ArrowLeft')
|
||||
$page->keys(':focus', 'ArrowLeft')
|
||||
->assertScript(onCarousel(0, 'return at(1)'));
|
||||
|
||||
$page->keys(FIRST_SCROLLER, 'End')
|
||||
$page->keys(':focus', 'End')
|
||||
->assertScript(onCarousel(0, 'return Math.abs(scroller.scrollLeft - (scroller.scrollWidth - scroller.clientWidth)) < 1.5 && inset(items.length - 1) < 0.5 && root.querySelector(\'[aria-label="Next"]\').disabled'));
|
||||
|
||||
$page->keys(FIRST_SCROLLER, 'Home')
|
||||
$page->keys(':focus', 'Home')
|
||||
->assertScript(onCarousel(0, 'return at(0)'));
|
||||
});
|
||||
|
||||
@@ -183,7 +185,7 @@ it('mirrors in a right-to-left page', function () {
|
||||
->assertNoJavaScriptErrors()
|
||||
->assertScript(onCarousel(0, 'return size > 0 && at(0) && inset(0) < 0.5 && inset(items.length - 1) > 0.5', 'body'));
|
||||
|
||||
$page->keys('[role="region"]', 'ArrowLeft')
|
||||
$page->keys('[data-material-carousel-item] >> nth=0', 'ArrowLeft')
|
||||
->assertScript(onCarousel(0, <<<'JS'
|
||||
return scroller.scrollLeft < -1 && at(1) && inset(0) > 0.5 && inset(1) < 0.5
|
||||
&& parseFloat(surface(0).style.getPropertyValue('--material-carousel-shift')) < 0
|
||||
@@ -192,7 +194,7 @@ it('mirrors in a right-to-left page', function () {
|
||||
$page->click('button[aria-label="Next"]')
|
||||
->assertScript(onCarousel(0, 'return at(2)', 'body'));
|
||||
|
||||
$page->keys('[role="region"]', 'ArrowRight')
|
||||
$page->keys('[data-material-carousel-item] >> nth=2', 'ArrowRight')
|
||||
->assertScript(onCarousel(0, 'return at(1)', 'body'));
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user