From 3e5c2d558c9a02d7f1275bb4f8877b5decb01c55 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Thu, 23 Apr 2026 20:08:49 +0300 Subject: [PATCH 1/3] feat(core): expose element internals to a11y tools --- .changeset/two-moose-cough.md | 4 ++++ core/pfe-core/controllers/internals-controller.ts | 4 ++++ 2 files changed, 8 insertions(+) create mode 100644 .changeset/two-moose-cough.md diff --git a/.changeset/two-moose-cough.md b/.changeset/two-moose-cough.md new file mode 100644 index 0000000000..105733b3f6 --- /dev/null +++ b/.changeset/two-moose-cough.md @@ -0,0 +1,4 @@ +--- +"@patternfly/pfe-core": patch +--- +`InternalsController`: allows accessibility auditing tools to access element internals. diff --git a/core/pfe-core/controllers/internals-controller.ts b/core/pfe-core/controllers/internals-controller.ts index 84b8c7a6c3..10ee1a0c70 100644 --- a/core/pfe-core/controllers/internals-controller.ts +++ b/core/pfe-core/controllers/internals-controller.ts @@ -263,6 +263,10 @@ export class InternalsController implements ReactiveController, ARIAMixin { this.initializeOptions(options); InternalsController.instances.set(host, this); this.#polyfillDisabledPseudo(); + // Expose internals to aXe Core + // https://github.com/webcomponents-cg/community-protocols/pull/75 + globalThis._elementInternals ??= new WeakMap(); + globalThis._elementInternasl.set(this.host, this.internals); } /** From 18ce995f3b82352496a62775f8fc6b869e177644 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Fri, 24 Apr 2026 08:04:53 +0300 Subject: [PATCH 2/3] fix: typescript wrangling, typo --- core/pfe-core/controllers/internals-controller.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/pfe-core/controllers/internals-controller.ts b/core/pfe-core/controllers/internals-controller.ts index 10ee1a0c70..c3b01f27ee 100644 --- a/core/pfe-core/controllers/internals-controller.ts +++ b/core/pfe-core/controllers/internals-controller.ts @@ -264,9 +264,8 @@ export class InternalsController implements ReactiveController, ARIAMixin { InternalsController.instances.set(host, this); this.#polyfillDisabledPseudo(); // Expose internals to aXe Core - // https://github.com/webcomponents-cg/community-protocols/pull/75 globalThis._elementInternals ??= new WeakMap(); - globalThis._elementInternasl.set(this.host, this.internals); + globalThis._elementInternals.set(this.host, this.internals); } /** @@ -339,6 +338,8 @@ export class InternalsController implements ReactiveController, ARIAMixin { /** @see https://w3c.github.io/aria/#ref-for-dom-ariamixin-ariaactivedescendantelement-1 */ declare global { + // https://github.com/webcomponents-cg/community-protocols/pull/75 + var _elementInternals: WeakMap; // eslint-disable-line no-var interface ARIAMixin { ariaActiveDescendantElement: Element | null; ariaControlsElements: readonly Element[] | null; From a9ca7e30e40ef241400908f22a2d573c171956d9 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Fri, 24 Apr 2026 17:43:33 +0300 Subject: [PATCH 3/3] perf: check presence of sidechannel only once --- core/pfe-core/controllers/internals-controller.ts | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/core/pfe-core/controllers/internals-controller.ts b/core/pfe-core/controllers/internals-controller.ts index c3b01f27ee..153b175a48 100644 --- a/core/pfe-core/controllers/internals-controller.ts +++ b/core/pfe-core/controllers/internals-controller.ts @@ -4,20 +4,22 @@ import { type ReactiveControllerHost, } from 'lit'; -function isARIAMixinProp(key: string): key is keyof ARIAMixin { - return key === 'role' || key.startsWith('aria'); -} - type FACE = HTMLElement & { formDisabledCallback?(disabled: boolean): void; }; +interface InternalsControllerOptions extends Partial { + getHTMLElement?(): HTMLElement; +} + const protos = new WeakMap(); let constructingAllowed = false; -interface InternalsControllerOptions extends Partial { - getHTMLElement?(): HTMLElement; +globalThis._elementInternals ??= new WeakMap(); + +function isARIAMixinProp(key: string): key is keyof ARIAMixin { + return key === 'role' || key.startsWith('aria'); } /** @@ -264,7 +266,6 @@ export class InternalsController implements ReactiveController, ARIAMixin { InternalsController.instances.set(host, this); this.#polyfillDisabledPseudo(); // Expose internals to aXe Core - globalThis._elementInternals ??= new WeakMap(); globalThis._elementInternals.set(this.host, this.internals); }