When building modals or dropdown menus, you need to know which elements can receive focus. This selector list covers the usual suspects — links, inputs, buttons, and anything with a non-negative tabindex.

export const FOCUSABLE_ELEMENTS = [
  'a[href]',
  'area[href]',
  'input:not([disabled]):not([type="hidden"]):not([aria-hidden])',
  'select:not([disabled]):not([aria-hidden])',
  'textarea:not([disabled]):not([aria-hidden])',
  'button:not([disabled]):not([aria-hidden])',
  'iframe',
  'object',
  'embed',
  '[contenteditable]',
  '[tabindex]:not([tabindex^="-"])',
]

export const getFocusableNodes = (context: HTMLElement) =>
  context.querySelectorAll<HTMLElement>(FOCUSABLE_ELEMENTS.join(','))

export const getOffset = (element: HTMLElement) => {
  const rect = element.getBoundingClientRect()

  return {
    top: rect.top + window.scrollY,
    left: rect.left + window.scrollX,
  }
}