A tiny polyfill for browsers that cannot focus a scrollable element (notably affecting keyboard accessibility of horizontally scrollable <pre> blocks in some environments).
Some browsers, especially older versions or specific rendering engines, do not allow scrollable elements to receive keyboard focus. This can create accessibility issues, particularly for horizontally scrollable <pre> blocks or other scrollable containers that should be navigable via keyboard.
This polyfill automatically detects if the browser has this limitation and applies a fix by adding tabindex="0" to scrollable elements, making them keyboard accessible.
npm install scroll-focus-polyfillYou can import the polyfill directly from unpkg.com without any build step:
<!-- Auto-execute version (detects and applies automatically) -->
<script src="https://unpkg.com/scroll-focus-polyfill"></script>
<!-- ES Module version -->
<script type="module">
import 'https://unpkg.com/scroll-focus-polyfill';
</script>The simplest way to use the polyfill is to just import it. It will automatically detect if it's needed and apply itself:
<script src="https://unpkg.com/scroll-focus-polyfill"></script>Or with npm:
<script src="node_modules/scroll-focus-polyfill"></script>// Auto-executes on import
import 'scroll-focus-polyfill';// Auto-executes on require
require('scroll-focus-polyfill');You can configure the polyfill using data attributes on the script tag:
<!-- Enable debug logging -->
<script src="https://unpkg.com/scroll-focus-polyfill" data-debug="true"></script>
<!-- Force application (skip browser detection) -->
<script src="https://unpkg.com/scroll-focus-polyfill" data-force="true"></script>
<!-- Custom selectors -->
<script src="https://unpkg.com/scroll-focus-polyfill" data-selectors="pre, .scrollable, [data-scroll]"></script>
<!-- Combine multiple options -->
<script src="https://unpkg.com/scroll-focus-polyfill"
data-debug="true"
data-force="true"
data-selectors="pre, .code-block"></script>If you want full control over when and how the polyfill is applied, use the function export:
// Import the function export (does NOT auto-execute)
import { applyPolyfill } from 'scroll-focus-polyfill/fn';
// Apply with default options
applyPolyfill();
// Apply with custom options
applyPolyfill({
debug: false, // Enable debug logging (default: false)
force: false, // Force polyfill even if browser supports focus (default: false)
selectors: ['pre'] // CSS selectors for elements to make focusable (default: ['pre'])
});
// Example: Enable debug logging
applyPolyfill({ debug: true });
// Example: Apply to custom elements
applyPolyfill({ selectors: ['pre', '.scrollable', '[data-scroll]'] });
// Example: Force application with custom selectors
applyPolyfill({
force: true,
selectors: ['pre', '.code-block']
});The package provides two entry points for different use cases:
| Entry Point | Auto-Execute | Use Case |
|---|---|---|
scroll-focus-polyfill (default) |
✅ Yes | Quick plug-and-play with automatic detection |
scroll-focus-polyfill/fn |
❌ No | Full control over application timing and options |
// Default: Auto-execute with detection
import 'scroll-focus-polyfill';
// Function export: No auto-execute, full control
import { applyPolyfill } from 'scroll-focus-polyfill/fn';
applyPolyfill({ debug: true });
// Force mode via function export
import { applyPolyfill } from 'scroll-focus-polyfill/fn';
applyPolyfill({ force: true });<!-- Default: Auto-execute with detection -->
<script src="https://unpkg.com/scroll-focus-polyfill"></script>
<!-- Force mode via data attribute -->
<script src="https://unpkg.com/scroll-focus-polyfill" data-force="true"></script>
<!-- With options via data attributes -->
<script src="https://unpkg.com/scroll-focus-polyfill"
data-debug="true"
data-selectors="pre, .scrollable"></script>debug(boolean, default:false): Enable console logging for debuggingforce(boolean, default:false): Force the polyfill to apply even if the browser natively supports focusing scrollable elementsselectors(array, default:['pre']): CSS selectors for elements that should be made focusable when they have scrollable content
- Detection: The polyfill checks if the browser needs it by testing if a
<pre>element with scrollable content can receive focus - Application: If needed (or if
force: true), it addstabindex="0"to matching elements that have scrollable content - Observation: It monitors the DOM for new elements and applies the fix automatically
This polyfill works in all modern browsers and will only activate if needed. It uses:
MutationObserverfor DOM monitoring- Standard DOM APIs for element detection
Contributions are welcome! Please see CONTRIBUTING.md for detailed information about:
- Development setup
- Available scripts
- Commit guidelines
- Pull request process
- Code style
This project uses:
- Vite for building and bundling
- Biome for linting and formatting
- commitlint for conventional commits
- lefthook for git hooks
- semantic-release for automated versioning
Please ensure your commits follow the Conventional Commits specification.
MIT