From fdf1bf8cf91c16f3e7a580bb6c7d223ddbb25758 Mon Sep 17 00:00:00 2001 From: chris-doucette-stack Date: Fri, 19 Dec 2025 16:16:32 -0500 Subject: [PATCH 1/4] Adding aria-label and aria-labelledby to PopoverContent --- .../src/components/Popover/Popover.test.ts | 69 +++++++++++++++++++ .../components/Popover/PopoverContent.svelte | 12 ++++ 2 files changed, 81 insertions(+) diff --git a/packages/stacks-svelte/src/components/Popover/Popover.test.ts b/packages/stacks-svelte/src/components/Popover/Popover.test.ts index b9fa312335..135371e80f 100644 --- a/packages/stacks-svelte/src/components/Popover/Popover.test.ts +++ b/packages/stacks-svelte/src/components/Popover/Popover.test.ts @@ -193,6 +193,75 @@ describe("Popover", () => { expect(innerContentElement).to.have.class("custom-class"); }); + it("should add aria-label to the popover when the aria-label prop is provided", async () => { + render(Popover, { + props: { + ...defaultProps, + autoshow: true, + children: createSvelteComponentsSnippet([ + defaultChildren.reference, + { + component: PopoverContent, + props: { + "aria-label": "Popover with content", + children: createRawSnippet(() => ({ + render: () => "Popover Content", + })), + }, + }, + ]), + }, + }); + + expect(screen.getByRole("dialog")).to.have.attribute( + "aria-label", + "Popover with content" + ); + }); + + it("should add aria-labelledby to the popover when the aria-labelledby prop is provided", async () => { + render(Popover, { + props: { + ...defaultProps, + autoshow: true, + children: createSvelteComponentsSnippet([ + defaultChildren.reference, + { + component: PopoverContent, + props: { + "aria-labelledby": "my-label-id", + children: createRawSnippet(() => ({ + render: () => "Popover Content", + })), + }, + }, + ]), + }, + }); + + 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: { diff --git a/packages/stacks-svelte/src/components/Popover/PopoverContent.svelte b/packages/stacks-svelte/src/components/Popover/PopoverContent.svelte index e50ece48ee..4a31f8352e 100644 --- a/packages/stacks-svelte/src/components/Popover/PopoverContent.svelte +++ b/packages/stacks-svelte/src/components/Popover/PopoverContent.svelte @@ -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 + */ + "aria-label"?: string; + /** + * ID of an element that labels the popover + */ + "aria-labelledby"?: string; /** * Additional CSS classes added to the s-popover element */ @@ -25,6 +33,8 @@ let { role = null, + "aria-label": ariaLabel, + "aria-labelledby": ariaLabelledby, class: className = "", contentClass = "", children, @@ -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 From 087939cbddaf7eb8a53af0ae79a015fdf24f30a6 Mon Sep 17 00:00:00 2001 From: chris-doucette-stack Date: Fri, 19 Dec 2025 16:19:26 -0500 Subject: [PATCH 2/4] Adding changeset --- .changeset/true-guests-drive.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/true-guests-drive.md diff --git a/.changeset/true-guests-drive.md b/.changeset/true-guests-drive.md new file mode 100644 index 0000000000..1452649f83 --- /dev/null +++ b/.changeset/true-guests-drive.md @@ -0,0 +1,5 @@ +--- +"@stackoverflow/stacks-svelte": minor +--- + +Added aria-label and aria-labelledby props to PopoverContent From 11be2d6da28c6696d516b2008d9a4965848bcdfe Mon Sep 17 00:00:00 2001 From: chris-doucette-stack Date: Fri, 19 Dec 2025 16:28:42 -0500 Subject: [PATCH 3/4] format --- .../src/components/Popover/Popover.test.ts | 4 ++-- .../src/components/Popover/PopoverContent.svelte | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/stacks-svelte/src/components/Popover/Popover.test.ts b/packages/stacks-svelte/src/components/Popover/Popover.test.ts index 135371e80f..0cf821a2f2 100644 --- a/packages/stacks-svelte/src/components/Popover/Popover.test.ts +++ b/packages/stacks-svelte/src/components/Popover/Popover.test.ts @@ -204,7 +204,7 @@ describe("Popover", () => { component: PopoverContent, props: { "aria-label": "Popover with content", - children: createRawSnippet(() => ({ + "children": createRawSnippet(() => ({ render: () => "Popover Content", })), }, @@ -230,7 +230,7 @@ describe("Popover", () => { component: PopoverContent, props: { "aria-labelledby": "my-label-id", - children: createRawSnippet(() => ({ + "children": createRawSnippet(() => ({ render: () => "Popover Content", })), }, diff --git a/packages/stacks-svelte/src/components/Popover/PopoverContent.svelte b/packages/stacks-svelte/src/components/Popover/PopoverContent.svelte index 4a31f8352e..a1f1628da7 100644 --- a/packages/stacks-svelte/src/components/Popover/PopoverContent.svelte +++ b/packages/stacks-svelte/src/components/Popover/PopoverContent.svelte @@ -8,7 +8,7 @@ * The aria role of the popover * (if not specified, it will default to 'dialog' for popovers or 'tooltip' when in tooltip mode) */ - role?: string | null; + "role"?: string | null; /** * Accessible label for the popover */ @@ -20,22 +20,22 @@ /** * Additional CSS classes added to the s-popover element */ - class?: string; + "class"?: string; /** * Additional CSS classes added to the s-popover--content element */ - contentClass?: string; + "contentClass"?: string; /** * Children snippet */ - children?: Snippet; + "children"?: Snippet; } let { role = null, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledby, - class: className = "", + "class": className = "", contentClass = "", children, }: Props = $props(); From de1b490c8bab67fdadce4144b0ba1d21b886a116 Mon Sep 17 00:00:00 2001 From: chris-doucette-stack Date: Mon, 22 Dec 2025 10:58:43 -0500 Subject: [PATCH 4/4] Fixes from review --- .../src/components/Popover/Popover.test.ts | 12 ++++++------ .../components/Popover/PopoverContent.svelte | 18 +++++++++--------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/packages/stacks-svelte/src/components/Popover/Popover.test.ts b/packages/stacks-svelte/src/components/Popover/Popover.test.ts index 0cf821a2f2..9f54642965 100644 --- a/packages/stacks-svelte/src/components/Popover/Popover.test.ts +++ b/packages/stacks-svelte/src/components/Popover/Popover.test.ts @@ -193,7 +193,7 @@ describe("Popover", () => { expect(innerContentElement).to.have.class("custom-class"); }); - it("should add aria-label to the popover when the aria-label prop is provided", async () => { + it("should add aria-label to the popover when the ariaLabel prop is provided", async () => { render(Popover, { props: { ...defaultProps, @@ -203,8 +203,8 @@ describe("Popover", () => { { component: PopoverContent, props: { - "aria-label": "Popover with content", - "children": createRawSnippet(() => ({ + ariaLabel: "Popover with content", + children: createRawSnippet(() => ({ render: () => "Popover Content", })), }, @@ -219,7 +219,7 @@ describe("Popover", () => { ); }); - it("should add aria-labelledby to the popover when the aria-labelledby prop is provided", async () => { + it("should add aria-labelledby to the popover when the ariaLabelledby prop is provided", async () => { render(Popover, { props: { ...defaultProps, @@ -229,8 +229,8 @@ describe("Popover", () => { { component: PopoverContent, props: { - "aria-labelledby": "my-label-id", - "children": createRawSnippet(() => ({ + ariaLabelledby: "my-label-id", + children: createRawSnippet(() => ({ render: () => "Popover Content", })), }, diff --git a/packages/stacks-svelte/src/components/Popover/PopoverContent.svelte b/packages/stacks-svelte/src/components/Popover/PopoverContent.svelte index a1f1628da7..2d1d6979f2 100644 --- a/packages/stacks-svelte/src/components/Popover/PopoverContent.svelte +++ b/packages/stacks-svelte/src/components/Popover/PopoverContent.svelte @@ -8,34 +8,34 @@ * The aria role of the popover * (if not specified, it will default to 'dialog' for popovers or 'tooltip' when in tooltip mode) */ - "role"?: string | null; + role?: string | null; /** * Accessible label for the popover */ - "aria-label"?: string; + ariaLabel?: string; /** * ID of an element that labels the popover */ - "aria-labelledby"?: string; + ariaLabelledby?: string; /** * Additional CSS classes added to the s-popover element */ - "class"?: string; + class?: string; /** * Additional CSS classes added to the s-popover--content element */ - "contentClass"?: string; + contentClass?: string; /** * Children snippet */ - "children"?: Snippet; + children?: Snippet; } let { role = null, - "aria-label": ariaLabel, - "aria-labelledby": ariaLabelledby, - "class": className = "", + ariaLabel, + ariaLabelledby, + class: className = "", contentClass = "", children, }: Props = $props();