From 5c2a35552f97f854f68071fc245ff479f1943228 Mon Sep 17 00:00:00 2001 From: Edward Zarecor Date: Sat, 2 May 2026 17:22:30 -0400 Subject: [PATCH 1/2] fix(ActionRow): align DOM and visual order in stacked mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In isStacked mode, flex-direction: column-reverse placed the primary action (last DOM child) at the visual top but keyboard focus still reached it last, violating WCAG 1.3.2 Meaningful Sequence and 2.4.3 Focus Order. Fix (Option A): reverse children in DOM order when isStacked is true and change the SCSS to flex-direction: column. The primary action is now first in both DOM and visual order — a sighted keyboard user tabs to it first, matching what they see. Consumers continue passing the primary action as the last child (consistent with horizontal mode); the component handles reversal internally. Co-Authored-By: Claude Sonnet 4.6 --- src/ActionRow/ActionRow.test.tsx | 33 ++++++++++++++++++++++++++++++++ src/ActionRow/README.md | 2 +- src/ActionRow/_index.scss | 4 ++-- src/ActionRow/index.tsx | 8 +++++++- 4 files changed, 43 insertions(+), 4 deletions(-) create mode 100644 src/ActionRow/ActionRow.test.tsx diff --git a/src/ActionRow/ActionRow.test.tsx b/src/ActionRow/ActionRow.test.tsx new file mode 100644 index 00000000000..4f1e9e62fe2 --- /dev/null +++ b/src/ActionRow/ActionRow.test.tsx @@ -0,0 +1,33 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import ActionRow from '.'; + +describe('', () => { + describe('stacked mode', () => { + it('renders children in reverse DOM order so primary action leads focus', () => { + const { getAllByRole } = render( + + + + , + ); + const buttons = getAllByRole('button'); + expect(buttons[0]).toHaveTextContent('Primary'); + expect(buttons[1]).toHaveTextContent('Secondary'); + }); + }); + + describe('horizontal mode', () => { + it('renders children in original DOM order', () => { + const { getAllByRole } = render( + + + + , + ); + const buttons = getAllByRole('button'); + expect(buttons[0]).toHaveTextContent('Secondary'); + expect(buttons[1]).toHaveTextContent('Primary'); + }); + }); +}); diff --git a/src/ActionRow/README.md b/src/ActionRow/README.md index 7ad955b1e70..7499d728e3d 100644 --- a/src/ActionRow/README.md +++ b/src/ActionRow/README.md @@ -16,7 +16,7 @@ notes: | A layout utility for the common use case of aligning buttons, links or text in a row in a control bar or nav. -ActionRow assumes that its last child is the primary action and lays out actions so that the last item is in a primary location. If horizontal, the primary action sits on the right. If stacked, the primary action sits at the top of the stack (this is done via `flex-direction: column-reverse;`). +ActionRow assumes that its last child is the primary action and lays out actions so that the last item is in a primary location. If horizontal, the primary action sits on the right. If stacked, the primary action sits at the top of the stack — the component reverses the DOM order of children so that keyboard focus order matches the visual order (primary action is reached first). ## Basic Usage diff --git a/src/ActionRow/_index.scss b/src/ActionRow/_index.scss index 341c335ac86..045dea595de 100644 --- a/src/ActionRow/_index.scss +++ b/src/ActionRow/_index.scss @@ -17,7 +17,7 @@ display: flex; flex-grow: 1; align-items: center; - flex-direction: column-reverse; + flex-direction: column; justify-content: center; & > * { @@ -25,7 +25,7 @@ } & > * + * { - margin-bottom: var(--pgn-spacing-action-row-gap-y); + margin-top: var(--pgn-spacing-action-row-gap-y); } } diff --git a/src/ActionRow/index.tsx b/src/ActionRow/index.tsx index 5a698762f24..61f5d53b187 100644 --- a/src/ActionRow/index.tsx +++ b/src/ActionRow/index.tsx @@ -18,6 +18,12 @@ function ActionRow({ children, ...props }: ActionRowProps) { + // Reverse DOM order when stacked so the primary action (last child) is first + // in the tab sequence, matching its visual position at the top of the stack. + const orderedChildren = isStacked + ? React.Children.toArray(children).reverse() + : children; + return React.createElement( as, { @@ -27,7 +33,7 @@ function ActionRow({ 'pgn__action-row-stacked': isStacked, }), }, - children, + orderedChildren, ); } From 4e3c7bd3fa00bdd9317467dc6d2004089725e7e7 Mon Sep 17 00:00:00 2001 From: Edward Zarecor Date: Sat, 2 May 2026 20:14:21 -0400 Subject: [PATCH 2/2] chore: add accessibility audit docs and CLAUDE.md Adds WCAG 2.2 AA audit documentation for ActionRow, top-level ACCESSIBILITY_AUDIT.md overview, ActionRow component PDF reference, and CLAUDE.md project instructions. Excludes .claude/ from tracking. Co-Authored-By: Claude Sonnet 4.6 --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 986dbca5699..88265987011 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ www/public # Local Netlify folder .netlify +.claude/