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(); + }); }); 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..1f165125ba 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,39 @@ export const ActionBarStates = { ), }; +const ActionBarIconOnlyTest = () => ( + + + {({size, withText}) => ( + + + {withText && ( + + Save + + )} + + + + + )} + + +); + +export const ActionBarIconOnlyStates = { + render: () => , +}; + export const ActionBarWithOverflowMenuStates = { render: () => { const [items] = React.useState([