Skip to content

Commit

Permalink
fix(LEMS-2183): Add optional aria label to popover (#2265)
Browse files Browse the repository at this point in the history
* add conditional aria label

* add test and update formatting

* update test to include checks for all attributes

* add changeset

* add story for custom aria label

* lint fix

* Update afraid-buckets-dance.md

Change from minor to patch

* add aria label string and description in popover accessibility file

* updated to include aria described by

* revert addition of aria described by
  • Loading branch information
anakaren-rojas authored Jul 22, 2024
1 parent 3ca9900 commit 68dd605
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 3 deletions.
5 changes: 5 additions & 0 deletions .changeset/afraid-buckets-dance.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@khanacademy/wonder-blocks-popover": patch
---

adds optional aria label for popover
3 changes: 3 additions & 0 deletions __docs__/wonder-blocks-popover/popover.accessibility.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ the `PopoverContent` component to reference the `title` and `content`
elements/props. By doing this, the popover will be announced by screen readers
as a dialog with a title and content.

Alternatively, you can use `aria-label` to add screen reader accessible text to the popover dialog in case there is no
visible title and/or description inside the dialog.

## Keyboard Interaction

### Initial focus
Expand Down
18 changes: 18 additions & 0 deletions __docs__/wonder-blocks-popover/popover.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -724,3 +724,21 @@ export const PopoverAlignment: StoryComponentType = {
</View>
),
};

/**
* With custom aria-label - overrides the default aria-describedby and aria-labelledby
*/

export const CustomAriaLabel: StoryComponentType = {
args: {
children: <Button>Open popover</Button>,
content: ContentMappings.withTextOnly,
placement: "top",
dismissEnabled: true,
id: "",
initialFocusId: "",
testId: "",
onClose: () => {},
"aria-label": "Popover with custom aria label",
} as PopoverArgs,
};
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 +583,40 @@ describe("Popover", () => {
).toBeInTheDocument();
});

it("should announce a popover correctly by reading the aria label", async () => {
// Arrange
render(
<Popover
onClose={jest.fn()}
aria-label="Popover Aria Label"
content={
<PopoverContentCore>
<button data-close-button onClick={close}>
Close Popover
</button>
</PopoverContentCore>
}
>
<Button>Open default popover</Button>
</Popover>,
);

// Act
// Open the popover
const openButton = await screen.findByRole("button", {
name: "Open default popover",
});

await userEvent.click(openButton);
const popover = await screen.findByRole("dialog");

// Assert

expect(popover).toHaveAttribute("aria-label", "Popover Aria Label");
expect(popover).not.toHaveAttribute("aria-labelledby");
expect(popover).not.toHaveAttribute("aria-describedby");
});

it("should correctly describe the popover content core's aria label", async () => {
// Arrange
render(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ export default class PopoverDialog extends React.Component<Props> {
showTail,
"aria-describedby": ariaDescribedby,
"aria-labelledby": ariaLabelledBy,
"aria-label": ariaLabel,
} = this.props;

const contentProps = children.props as any;
Expand All @@ -90,6 +91,7 @@ export default class PopoverDialog extends React.Component<Props> {
return (
<React.Fragment>
<View
aria-label={ariaLabel}
aria-describedby={ariaDescribedby}
aria-labelledby={ariaLabelledBy}
id={id}
Expand Down
16 changes: 13 additions & 3 deletions packages/wonder-blocks-popover/src/components/popover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -272,16 +272,26 @@ export default class Popover extends React.Component<Props, State> {
}

renderPopper(uniqueId: string): React.ReactNode {
const {initialFocusId, placement, showTail, portal} = this.props;
const {
initialFocusId,
placement,
showTail,
portal,
"aria-label": ariaLabel,
} = this.props;
const {anchorElement} = this.state;

const ariaDescribedBy = ariaLabel ? undefined : `${uniqueId}-content`;
const ariaLabelledBy = ariaLabel ? undefined : `${uniqueId}-title`;

const popperContent = (
<TooltipPopper anchorElement={anchorElement} placement={placement}>
{(props: PopperElementProps) => (
<PopoverDialog
{...props}
aria-describedby={`${uniqueId}-content`}
aria-labelledby={`${uniqueId}-title`}
aria-label={ariaLabel}
aria-describedby={ariaDescribedBy}
aria-labelledby={ariaLabelledBy}
id={uniqueId}
onUpdate={(placement) => this.setState({placement})}
showTail={showTail}
Expand Down

0 comments on commit 68dd605

Please sign in to comment.