tabbable: Identify Tabbable DOM Nodes

6.4.0 · active · verified Sun Apr 19

tabbable is a JavaScript utility library designed to accurately identify and return an array of all keyboard-tabbable DOM nodes within a specified container element. It systematically determines tabbability based on standard HTML semantics (e.g., `<button>`, `<input>`, `<a>` with `href`), explicit `tabindex` attributes, and various visibility and accessibility rules. The library is actively maintained, currently at version `6.4.0`, and receives regular minor and patch updates to enhance browser compatibility, support new web standards like the `inert` attribute, and address issues in virtual DOM environments like JSDOM. Its key differentiators include a zero-dependency footprint, small bundle size, high accuracy in diverse scenarios, and optimized performance. It supports a broad range of modern desktop browsers (Chrome, Edge, Firefox, Safari, Opera), but crucially, it dropped support for Internet Explorer browsers starting with v6.0.0. The library also provides granular control over how visibility checks are performed via the `displayCheck` option, accommodating various application needs.

Common errors

Warnings

Install

Imports

Quickstart

Demonstrates how to find both tabbable and focusable elements within a given DOM node using the `tabbable` and `focusable` functions, and how to retrieve their `tabIndex`.

import { tabbable, focusable, getTabIndex } from 'tabbable';

// Helper to create a DOM structure for testing in a browser or JSDOM environment
function createTestDOM(htmlString) {
  const container = document.createElement('div');
  container.innerHTML = htmlString;
  // Append to body to ensure elements are considered 'attached' for visibility checks
  document.body.appendChild(container);
  return container;
}

const testHtml = `
  <div id="root-container">
    <button id="btn1">Click Me</button>
    <input type="text" placeholder="Enter text" />
    <a href="#" id="link1">A link</a>
    <span tabindex="0" id="span1">Custom tabbable</span>
    <div tabindex="-1" id="div1">Focusable but not tabbable</div>
    <button disabled id="btn2">Disabled Button</button>
    <a href="#" style="display: none;" id="link2">Hidden Link</a>
    <p>Some text</p>
    <textarea id="textarea1"></textarea>
  </div>
`;

const containerElement = createTestDOM(testHtml);

console.log('--- Tabbable elements ---');
const tabbableElements = tabbable(containerElement);
tabbableElements.forEach(el => {
  console.log(`Tabbable: ${el.outerHTML}, TabIndex: ${getTabIndex(el)}`);
});

console.log('\n--- Focusable elements (including non-tabbable) ---');
const focusableElements = focusable(containerElement);
focusableElements.forEach(el => {
  console.log(`Focusable: ${el.outerHTML}, TabIndex: ${getTabIndex(el)}`);
});

// Clean up the added DOM element
document.body.removeChild(containerElement);

view raw JSON →