Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/true-guests-drive.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@stackoverflow/stacks-svelte": minor
---

Added aria-label and aria-labelledby props to PopoverContent
69 changes: 69 additions & 0 deletions packages/stacks-svelte/src/components/Popover/Popover.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,75 @@ describe("Popover", () => {
expect(innerContentElement).to.have.class("custom-class");
});

it("should add aria-label to the popover when the ariaLabel prop is provided", async () => {
render(Popover, {
props: {
...defaultProps,
autoshow: true,
children: createSvelteComponentsSnippet([
defaultChildren.reference,
{
component: PopoverContent,
props: {
ariaLabel: "Popover with content",
children: createRawSnippet(() => ({
render: () => "<span>Popover Content</span>",
})),
},
},
]),
},
});

expect(screen.getByRole("dialog")).to.have.attribute(
"aria-label",
"Popover with content"
);
});

it("should add aria-labelledby to the popover when the ariaLabelledby prop is provided", async () => {
render(Popover, {
props: {
...defaultProps,
autoshow: true,
children: createSvelteComponentsSnippet([
defaultChildren.reference,
{
component: PopoverContent,
props: {
ariaLabelledby: "my-label-id",
children: createRawSnippet(() => ({
render: () => "<span>Popover Content</span>",
})),
},
},
]),
},
});

expect(screen.getByRole("dialog")).to.have.attribute(
"aria-labelledby",
"my-label-id"
);
});

it("should not add aria-label or aria-labelledby when not provided", async () => {
render(Popover, {
props: {
...defaultProps,
autoshow: true,
children: createSvelteComponentsSnippet([
defaultChildren.reference,
defaultChildren.content,
]),
},
});

const dialog = screen.getByRole("dialog");
expect(dialog).not.to.have.attribute("aria-label");
expect(dialog).not.to.have.attribute("aria-labelledby");
});

it("add classes to the popover close button component when the class prop is provided", async () => {
render(Popover, {
props: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@
* (if not specified, it will default to 'dialog' for popovers or 'tooltip' when in tooltip mode)
*/
role?: string | null;
/**
* Accessible label for the popover
*/
ariaLabel?: string;
/**
* ID of an element that labels the popover
*/
ariaLabelledby?: string;
/**
* Additional CSS classes added to the s-popover element
*/
Expand All @@ -25,6 +33,8 @@

let {
role = null,
ariaLabel,
ariaLabelledby,
class: className = "",
contentClass = "",
children,
Expand Down Expand Up @@ -65,6 +75,8 @@
id={`${pstate.id}-popover`}
class={computedClass}
role={computedRole}
aria-label={ariaLabel}
aria-labelledby={ariaLabelledby}
use:pstate.floatingContent
use:focusTrap={{ active: pstate.trapFocus && !!pstate.visible }}
use:clickOutside
Expand Down