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/
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,
);
}