Skip to content

isFocusable/isTabbable has incorrect selectors #8146

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
jamiebuilds-signal opened this issue Apr 24, 2025 · 2 comments
Open

isFocusable/isTabbable has incorrect selectors #8146

jamiebuilds-signal opened this issue Apr 24, 2025 · 2 comments

Comments

@jamiebuilds-signal
Copy link

Provide a general summary of the issue here

https://github.com/adobe/react-spectrum/blob/2e9061df69eb17f17b0fb7d64d318c2835aed145/packages/%40react-aria/utils/src/isFocusable.ts

FOCUSABLE_ELEMENT_SELECTOR

  input:not([disabled]):not([type=hidden]):not([hidden]),
  select:not([disabled]):not([hidden]),
  textarea:not([disabled]):not([hidden]),
  button:not([disabled]):not([hidden]),
  a[href]:not([hidden]),
  area[href]:not([hidden]),
  summary:not([hidden]),
  iframe:not([hidden]),
  object:not([hidden]),
  embed:not([hidden]),
  audio[controls]:not([hidden]),
  video[controls]:not([hidden]),
- [contenteditable]:not([contenteditable^="false"]), // actual: missing `:not([hidden])`
+ [contenteditable]:not([contenteditable^="false"]):not([hidden]), // expected
  [tabindex]:not([disabled]):not([hidden])

TABBABLE_ELEMENT_SELECTOR

  input:not([disabled]):not([type=hidden]):not([hidden]):not([tabindex="-1"]),
  select:not([disabled]):not([hidden]):not([tabindex="-1"]),
  textarea:not([disabled]):not([hidden]):not([tabindex="-1"]),
  button:not([disabled]):not([hidden]):not([tabindex="-1"]),
  a[href]:not([hidden]):not([tabindex="-1"]),
  area[href]:not([hidden]):not([tabindex="-1"]),
  summary:not([hidden]):not([tabindex="-1"]),
  iframe:not([hidden]):not([tabindex="-1"]),
  object:not([hidden]):not([tabindex="-1"]),
  embed:not([hidden]):not([tabindex="-1"]),
  audio[controls]:not([hidden]):not([tabindex="-1"]),
  video[controls]:not([hidden]):not([tabindex="-1"]),
  [contenteditable]:not([contenteditable^="false"]):not([hidden]):not([tabindex="-1"]),
- [tabindex]:not([tabindex="-1"]):not([disabled]) // actual: missing `:not([hidden])`
+ [tabindex]:not([tabindex="-1"]):not([disabled]):not([hidden]) // expected

🤔 Expected Behavior?

😯 Current Behavior

💁 Possible Solution

const focusableElements = [
  'input:not([disabled]):not([type=hidden])',
  'select:not([disabled])',
  'textarea:not([disabled])',
  'button:not([disabled])',
  'a[href]',
  'area[href]',
  'summary',
  'iframe',
  'object',
  'embed',
  'audio[controls]',
  'video[controls]',
  '[contenteditable]:not([contenteditable^="false"])',
  '[tabindex]:not([disabled])'
];

const FOCUSABLE_ELEMENT_SELECTOR = focusableElements
  .map(selector => `${selector}:not([hidden])`)
  .join(",");

const TABBABLE_ELEMENT_SELECTOR = focusableElements
  .map(selector => `${selector}:not([hidden]):not([tabindex="-1"])`)
  .join(",");

export function isFocusable(element: Element): boolean {
  return element.matches(FOCUSABLE_ELEMENT_SELECTOR);
}

export function isTabbable(element: Element): boolean {
  return element.matches(TABBABLE_ELEMENT_SELECTOR);
}

🔦 Context

No response

🖥️ Steps to Reproduce

Version

What browsers are you seeing the problem on?

Other

If other, please specify.

What operating system are you using?

🧢 Your Company/Team

No response

🕷 Tracking Issue

No response

@devongovett
Copy link
Member

FocusScope calls isElementVisible as well, but perhaps these standalone utils should do that too.

export function isElementVisible(element: Element, childElement?: Element): boolean {

@LFDanLu
Copy link
Member

LFDanLu commented Apr 30, 2025

@jamiebuilds-signal in what context are you using isFocusable/isTabbable standalone?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants