diff --git a/change/@microsoft-fast-foundation-7d8d0430-523b-473a-af77-e2bcf0bc6e38.json b/change/@microsoft-fast-foundation-7d8d0430-523b-473a-af77-e2bcf0bc6e38.json
new file mode 100644
index 00000000000..e6da993e8d0
--- /dev/null
+++ b/change/@microsoft-fast-foundation-7d8d0430-523b-473a-af77-e2bcf0bc6e38.json
@@ -0,0 +1,7 @@
+{
+ "type": "prerelease",
+ "comment": "Prevent keyboard navigation to hidden tab",
+ "packageName": "@microsoft/fast-foundation",
+ "email": "7282195+m-akinc@users.noreply.github.com",
+ "dependentChangeType": "prerelease"
+}
diff --git a/packages/web-components/fast-foundation/src/tabs/tabs.pw.spec.ts b/packages/web-components/fast-foundation/src/tabs/tabs.pw.spec.ts
index 4ca4e857224..1ba5cc21fa4 100644
--- a/packages/web-components/fast-foundation/src/tabs/tabs.pw.spec.ts
+++ b/packages/web-components/fast-foundation/src/tabs/tabs.pw.spec.ts
@@ -386,4 +386,70 @@ test.describe("Tabs", () => {
await expect(element).toHaveJSProperty("activeid", secondTabId);
});
+
+ test("should not allow selecting hidden tab using arrow keys", async () => {
+ test.slow();
+
+ await root.evaluate(node => {
+ node.innerHTML = /* html */ `
+
+ Tab one
+ Tab two
+ Tab three
+ Tab panel one
+ Tab panel two
+ Tab panel three
+
+ `;
+ });
+
+ const firstTab = tabs.nth(0);
+
+ const thirdTab = tabs.nth(2);
+
+ const firstTabId = (await firstTab.getAttribute("id")) ?? "";
+
+ const thirdTabId = (await thirdTab.getAttribute("id")) ?? "";
+
+ await element.evaluate((node: FASTTabs, firstTabId) => {
+ node.activeid = firstTabId;
+ }, firstTabId);
+
+ await firstTab.press("ArrowRight");
+
+ await expect(element).toHaveJSProperty("activeid", thirdTabId);
+ });
+
+ test("should not allow selecting hidden tab by pressing End", async () => {
+ test.slow();
+
+ await root.evaluate(node => {
+ node.innerHTML = /* html */ `
+
+ Tab one
+ Tab two
+ Tab three
+ Tab panel one
+ Tab panel two
+ Tab panel three
+
+ `;
+ });
+
+ const firstTab = tabs.nth(0);
+
+ const secondTab = tabs.nth(1);
+
+ const firstTabId = (await firstTab.getAttribute("id")) ?? "";
+
+ const secondTabId = (await secondTab.getAttribute("id")) ?? "";
+
+ await element.evaluate((node: FASTTabs, firstTabId) => {
+ node.activeid = firstTabId;
+ }, firstTabId);
+
+ await firstTab.press("End");
+
+ await expect(element).toHaveJSProperty("activeid", secondTabId);
+ });
});
diff --git a/packages/web-components/fast-foundation/src/tabs/tabs.ts b/packages/web-components/fast-foundation/src/tabs/tabs.ts
index 3c7c07cb9fb..26a0a48e3d2 100644
--- a/packages/web-components/fast-foundation/src/tabs/tabs.ts
+++ b/packages/web-components/fast-foundation/src/tabs/tabs.ts
@@ -130,8 +130,12 @@ export class FASTTabs extends FASTElement {
return el.getAttribute("aria-disabled") === "true";
};
+ private isHiddenElement = (el: Element): el is HTMLElement => {
+ return el.hasAttribute("hidden");
+ };
+
private isFocusableElement = (el: Element): el is HTMLElement => {
- return !this.isDisabledElement(el);
+ return !this.isDisabledElement(el) && !this.isHiddenElement(el);
};
private getActiveIndex(): number {
@@ -272,7 +276,7 @@ export class FASTTabs extends FASTElement {
* This method allows the active index to be adjusted by numerical increments
*/
public adjust(adjustment: number): void {
- const focusableTabs = this.tabs.filter(t => !this.isDisabledElement(t));
+ const focusableTabs = this.tabs.filter(t => this.isFocusableElement(t));
const currentActiveTabIndex = focusableTabs.indexOf(this.activetab);
const nextTabIndex = limit(