From 8db2874857349bf084188747dca34d72fc009b1d Mon Sep 17 00:00:00 2001
From: Akshita <110122283+akshita317@users.noreply.github.com>
Date: Mon, 12 Oct 2026 21:10:28 +0530
Subject: [PATCH 1/3] fix(ActionBar): Allow icon-only items without children
ActionBar.Item declared children as required, so an icon-only item such as
failed to type-check,
even though the underlying SecondaryButton renders icon-only buttons.
Make children optional, document providing an aria-label for icon-only
items, and add a spec that renders one and finds it by its accessible name.
Fixes #3620
---
modules/react/action-bar/lib/ActionBarItem.tsx | 4 +++-
.../react/action-bar/spec/ActionBar.spec.tsx | 17 +++++++++++++++++
2 files changed, 20 insertions(+), 1 deletion(-)
diff --git a/modules/react/action-bar/lib/ActionBarItem.tsx b/modules/react/action-bar/lib/ActionBarItem.tsx
index bfc28986d7..5297c88980 100644
--- a/modules/react/action-bar/lib/ActionBarItem.tsx
+++ b/modules/react/action-bar/lib/ActionBarItem.tsx
@@ -12,12 +12,14 @@ import {useActionBarModel} from './useActionBarModel';
export interface ActionBarItemProps {
/**
* The contents of the action item. This will be the accessible name of the action for screen readers.
+ * Omit it to render an icon-only button, and provide an `aria-label` instead.
*
* ```tsx
* First Action
+ *
* ```
*/
- children: React.ReactNode;
+ children?: React.ReactNode;
/**
* The identifier of the action. This identifier will be used for correct overflow behavior.
* If this property is not provided, it will default to a string representation
diff --git a/modules/react/action-bar/spec/ActionBar.spec.tsx b/modules/react/action-bar/spec/ActionBar.spec.tsx
index 4f8dc6749e..88e44476fb 100644
--- a/modules/react/action-bar/spec/ActionBar.spec.tsx
+++ b/modules/react/action-bar/spec/ActionBar.spec.tsx
@@ -1,6 +1,23 @@
+import {render} from '@testing-library/react';
+import * as React from 'react';
+
+import {trashIcon} from '@workday/canvas-system-icons-web';
+
import {ActionBar} from '../lib/ActionBar';
import {useActionBarModel} from '../lib/useActionBarModel';
describe('ActionBar.Item', () => {
verifyComponent(ActionBar.Item, {modelFn: useActionBarModel});
+
+ it('should render an icon-only item named by its aria-label', () => {
+ const screen = render(
+
+
+
+
+
+ );
+
+ expect(screen.getByRole('button', {name: 'Delete'})).toBeInTheDocument();
+ });
});
From c1db351e42c3c33e6b05bba7700c5a2231bdc4d6 Mon Sep 17 00:00:00 2001
From: Akshita <110122283+akshita317@users.noreply.github.com>
Date: Tue, 13 Oct 2026 22:42:55 +0530
Subject: [PATCH 2/3] docs(ActionBar): Add icon-only example and visual test
Add an Icon-Only example to the ActionBar Storybook docs, showing icon-only
items with an aria-label next to a text action, and an
ActionBarIconOnlyStates visual test covering icon-only items with and
without a text action, in the default and small sizes.
---
.../react/action-bar/stories/ActionBar.mdx | 9 ++++++
.../action-bar/stories/ActionBar.stories.ts | 4 +++
.../action-bar/stories/examples/IconOnly.tsx | 15 +++++++++
.../action-bar/stories/examples/index.ts | 1 +
.../visual-testing/testing.stories.tsx | 32 +++++++++++++++++++
5 files changed, 61 insertions(+)
create mode 100644 modules/react/action-bar/stories/examples/IconOnly.tsx
diff --git a/modules/react/action-bar/stories/ActionBar.mdx b/modules/react/action-bar/stories/ActionBar.mdx
index 242c8a4a49..08326d6c70 100644
--- a/modules/react/action-bar/stories/ActionBar.mdx
+++ b/modules/react/action-bar/stories/ActionBar.mdx
@@ -2,6 +2,7 @@ import {Meta} from '@storybook/blocks';
import {ExampleCodeBlock, SymbolDoc} from '@workday/canvas-kit-docs';
import {Basic} from './examples/Basic';
import {Icons} from './examples/Icons';
+import {IconOnly} from './examples/IconOnly';
import {DeleteAction} from './examples/DeleteAction';
import {OverflowActionBar} from './examples/OverflowActionBar';
import {OverflowActionBarCustomButtonCount} from './examples/OverflowActionBarCustomButtonCount';
@@ -42,6 +43,14 @@ with `ActionBar.Item` such as `icon` or `size`.
+### Icon-Only Example
+
+An `ActionBar.Item` can render an icon-only button by passing an `icon` without `children`. Because
+there is no visible text, provide an `aria-label` so the action has an accessible name. Wrapping the
+item in a [Tooltip](/components/popups/tooltip/) also shows the label to sighted users.
+
+
+
### Delete Action Example
`ActionBar.Item` is a `SecondaryButton` by default but it's posible to change it to another element,
diff --git a/modules/react/action-bar/stories/ActionBar.stories.ts b/modules/react/action-bar/stories/ActionBar.stories.ts
index 25a3ee10b7..9da6f96d7d 100644
--- a/modules/react/action-bar/stories/ActionBar.stories.ts
+++ b/modules/react/action-bar/stories/ActionBar.stories.ts
@@ -5,6 +5,7 @@ import {ActionBar} from '@workday/canvas-kit-react/action-bar';
import mdxDoc from './ActionBar.mdx';
import {Basic as BasicExample} from './examples/Basic';
import {DeleteAction as DeleteActionExample} from './examples/DeleteAction';
+import {IconOnly as IconOnlyExample} from './examples/IconOnly';
import {Icons as IconsExample} from './examples/Icons';
import {OverflowActionBar as OverflowActionBarExample} from './examples/OverflowActionBar';
import {OverflowActionBarCustomButtonCount as OverflowActionBarCustomButtonCountExample} from './examples/OverflowActionBarCustomButtonCount';
@@ -28,6 +29,9 @@ export const Basic: Story = {
export const Icons: Story = {
render: IconsExample,
};
+export const IconOnly: Story = {
+ render: IconOnlyExample,
+};
export const DeleteAction: Story = {
render: DeleteActionExample,
};
diff --git a/modules/react/action-bar/stories/examples/IconOnly.tsx b/modules/react/action-bar/stories/examples/IconOnly.tsx
new file mode 100644
index 0000000000..84eddd2ba9
--- /dev/null
+++ b/modules/react/action-bar/stories/examples/IconOnly.tsx
@@ -0,0 +1,15 @@
+import {ActionBar} from '@workday/canvas-kit-react/action-bar';
+import {PrimaryButton} from '@workday/canvas-kit-react/button';
+import {editIcon, trashIcon} from '@workday/canvas-system-icons-web';
+
+export const IconOnly = () => {
+ return (
+
+
+ Save
+
+
+
+
+ );
+};
diff --git a/modules/react/action-bar/stories/examples/index.ts b/modules/react/action-bar/stories/examples/index.ts
index 4f37831963..12efa4dfbd 100644
--- a/modules/react/action-bar/stories/examples/index.ts
+++ b/modules/react/action-bar/stories/examples/index.ts
@@ -1,5 +1,6 @@
export {Basic} from './Basic';
export {DeleteAction} from './DeleteAction';
+export {IconOnly} from './IconOnly';
export {Icons} from './Icons';
export {OverflowActionBar} from './OverflowActionBar';
export {OverflowActionBarCustomButtonCount} from './OverflowActionBarCustomButtonCount';
diff --git a/modules/react/action-bar/stories/visual-testing/testing.stories.tsx b/modules/react/action-bar/stories/visual-testing/testing.stories.tsx
index e16ade025d..d33c4f1e35 100644
--- a/modules/react/action-bar/stories/visual-testing/testing.stories.tsx
+++ b/modules/react/action-bar/stories/visual-testing/testing.stories.tsx
@@ -4,6 +4,7 @@ import {ActionBar} from '@workday/canvas-kit-react/action-bar';
import {PrimaryButton, SecondaryButton} from '@workday/canvas-kit-react/button';
import {ComponentStatesTable, StaticStates} from '@workday/canvas-kit-react/testing';
import {cssVar, px2rem} from '@workday/canvas-kit-styling';
+import {editIcon, trashIcon} from '@workday/canvas-system-icons-web';
import {base} from '@workday/canvas-tokens-web';
export default {
@@ -55,6 +56,37 @@ export const ActionBarStates = {
),
};
+export const ActionBarIconOnlyStates = {
+ render: () => (
+
+
+ {({size, withText}) => (
+
+
+ {withText && (
+
+ Save
+
+ )}
+
+
+
+
+ )}
+
+
+ ),
+};
+
export const ActionBarWithOverflowMenuStates = {
render: () => {
const [items] = React.useState([
From 99d7df8dec90459590d8b2fa53d3d0424a61b812 Mon Sep 17 00:00:00 2001
From: Akshita <110122283+akshita317@users.noreply.github.com>
Date: Wed, 14 Oct 2026 20:59:34 +0530
Subject: [PATCH 3/3] test(ActionBar): Render icon-only visual states from a
component
Move the ActionBarIconOnlyStates table into an ActionBarIconOnlyTest
component and render it from the story, following the convention of
keeping JSX out of the CSF story object.
---
.../visual-testing/testing.stories.tsx | 58 ++++++++++---------
1 file changed, 30 insertions(+), 28 deletions(-)
diff --git a/modules/react/action-bar/stories/visual-testing/testing.stories.tsx b/modules/react/action-bar/stories/visual-testing/testing.stories.tsx
index d33c4f1e35..1f165125ba 100644
--- a/modules/react/action-bar/stories/visual-testing/testing.stories.tsx
+++ b/modules/react/action-bar/stories/visual-testing/testing.stories.tsx
@@ -56,35 +56,37 @@ export const ActionBarStates = {
),
};
+const ActionBarIconOnlyTest = () => (
+
+
+ {({size, withText}) => (
+
+
+ {withText && (
+
+ Save
+
+ )}
+
+
+
+
+ )}
+
+
+);
+
export const ActionBarIconOnlyStates = {
- render: () => (
-
-
- {({size, withText}) => (
-
-
- {withText && (
-
- Save
-
- )}
-
-
-
-
- )}
-
-
- ),
+ render: () => ,
};
export const ActionBarWithOverflowMenuStates = {