/**
* `true` when the element is considered disabled — either via a direct
* `disabled` attribute, an `aria-disabled="true"` attribute, or an ancestor
* `
` (which disables all form controls within it, per
* HTML spec).
*
* A `null` element is treated as disabled: callers typically use this to
* guard keyboard navigation, and a missing element should never receive
* focus.
*/
export function isElementDisabled(element: Element | null): boolean {
if (element == null) {
return true;
}
if (element.hasAttribute("disabled")) {
return true;
}
if (element.getAttribute("aria-disabled") === "true") {
return true;
}
// Nearest ancestor disables all contained form
// controls. We walk up the tree rather than relying on :disabled because
// the CSS pseudo-class does not work via `element.matches` in every
// environment (notably happy-dom).
let parent: Element | null = element.parentElement;
while (parent != null) {
if (
parent.tagName === "FIELDSET" &&
(parent as HTMLFieldSetElement).disabled
) {
return true;
}
parent = parent.parentElement;
}
return false;
}