diff --git a/packages/calcite-components/src/components/button/button.e2e.ts b/packages/calcite-components/src/components/button/button.e2e.ts
index 604cc470148..3fc1e942a6b 100644
--- a/packages/calcite-components/src/components/button/button.e2e.ts
+++ b/packages/calcite-components/src/components/button/button.e2e.ts
@@ -644,4 +644,27 @@ describe("calcite-button", () => {
expect(button1.textContent.length).toBeLessThan(longText.length);
expect(button1.getAttribute("title")).toEqual(longText);
});
+
+ it("should set aria-expanded attribute on shadowDOM element when used as trigger", async () => {
+ const page = await newE2EPage();
+ await page.setContent(html`Info
+
+ Information
+ `);
+
+ const calciteButton = await page.find("calcite-button");
+ const button = await page.find("calcite-button >>> button");
+ expect(button.getAttribute("aria-expanded")).toBe("false");
+ expect(calciteButton.getAttribute("aria-expanded")).toBe("false");
+
+ await calciteButton.click();
+ await page.waitForChanges();
+ expect(button.getAttribute("aria-expanded")).toBe("true");
+ expect(calciteButton.getAttribute("aria-expanded")).toBe("true");
+ });
});
diff --git a/packages/calcite-components/src/components/button/button.tsx b/packages/calcite-components/src/components/button/button.tsx
index 5aa7441aa18..6930f4a1277 100644
--- a/packages/calcite-components/src/components/button/button.tsx
+++ b/packages/calcite-components/src/components/button/button.tsx
@@ -26,6 +26,11 @@ import { Appearance, FlipContext, Kind, Scale, Width } from "../interfaces";
import { ButtonMessages } from "./assets/button/t9n";
import { ButtonAlignment } from "./interfaces";
import { CSS } from "./resources";
+import {
+ GlobalAttrComponent,
+ unwatchGlobalAttributes,
+ watchGlobalAttributes,
+} from "../../utils/globalAttributes";
/** Passing a 'href' will render an anchor link, instead of a button. Role will be set to link, or button, depending on this. */
/** It is the consumers responsibility to add aria information, rel, target, for links, and any button attributes for form submission */
@@ -39,6 +44,7 @@ import { CSS } from "./resources";
})
export class Button
implements
+ GlobalAttrComponent,
LabelableComponent,
InteractiveComponent,
FormOwner,
@@ -175,6 +181,7 @@ export class Button
connectInteractive(this);
connectLocalized(this);
connectMessages(this);
+ watchGlobalAttributes(this, ["aria-expanded"]);
this.hasLoader = this.loading;
this.setupTextContentObserver();
connectLabel(this);
@@ -189,6 +196,7 @@ export class Button
disconnectMessages(this);
this.resizeObserver?.disconnect();
this.formEl = null;
+ unwatchGlobalAttributes(this);
}
async componentWillLoad(): Promise {
@@ -268,6 +276,7 @@ export class Button
target={childElType === "a" && this.target}
title={this.tooltipText}
type={childElType === "button" && this.type}
+ {...this.globalAttributes}
>
{loaderNode}
{this.iconStart ? iconStartEl : null}
@@ -344,6 +353,10 @@ export class Button
resizeObserver = createObserver("resize", () => this.setTooltipText());
+ @State() globalAttributes = {
+ ariaExpanded: undefined,
+ };
+
//--------------------------------------------------------------------------
//
// Private Methods
diff --git a/packages/calcite-components/src/utils/globalAttributes.ts b/packages/calcite-components/src/utils/globalAttributes.ts
index 0fcde59a844..05f7880eec4 100644
--- a/packages/calcite-components/src/utils/globalAttributes.ts
+++ b/packages/calcite-components/src/utils/globalAttributes.ts
@@ -1,8 +1,8 @@
import { createObserver } from "./observers";
type AttributeObject = { [k: string]: any };
-type AllowedGlobalAttribute = "lang" | "role";
-const allowedGlobalAttributes = ["lang", "role"];
+type AllowedGlobalAttribute = "lang" | "role" | "aria-expanded";
+const allowedGlobalAttributes = ["lang", "role", "aria-expanded"];
const elementToComponentAndObserverOptionsMap = new Map<
HTMLElement,