CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-material--dom

DOM manipulation utilities for Material Components providing cross-browser compatibility, focus management, and accessibility features.

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

focus-trap.mddocs/

Focus Management

Focus trapping utility for managing focus within modal components like dialogs, drawers, and popups. Ensures keyboard navigation stays within the modal and provides accessible focus management.

Capabilities

FocusTrap Class

Utility class that traps focus within a given root element, intended for modal components.

/**
 * Utility to trap focus in a given root element, e.g. for modal components such
 * as dialogs. The root should have at least one focusable child element,
 * for setting initial focus when trapping focus.
 * Also tracks the previously focused element, and restores focus to that
 * element when releasing focus.
 */
class FocusTrap {
  constructor(root: HTMLElement, options?: FocusOptions);
  trapFocus(): void;
  releaseFocus(): void;
}

Constructor

Create a new FocusTrap instance for a root element.

/**
 * Creates a new FocusTrap instance
 * @param root - The root element to trap focus within
 * @param options - Configuration options for focus behavior
 */
constructor(root: HTMLElement, options?: FocusOptions);

Trap Focus

Activate focus trapping within the root element.

/**
 * Traps focus in root. Also focuses on either initialFocusEl if set;
 * otherwise sets initial focus to the first focusable child element.
 * @throws Error if the root element has no focusable children
 */
trapFocus(): void;

Release Focus

Deactivate focus trapping and restore previous focus.

/**
 * Releases focus from root. Also restores focus to the previously focused
 * element.
 */
releaseFocus(): void;

Configuration Options

interface FocusOptions {
  /**
   * The element to focus initially when trapping focus.
   * Must be a child of the root element.
   */
  initialFocusEl?: HTMLElement;

  /**
   * Whether to skip initially focusing on any element when trapping focus.
   * By default, focus is set on the first focusable child element of the root.
   * This is useful if the caller wants to handle setting initial focus.
   */
  skipInitialFocus?: boolean;

  /**
   * Whether to restore focus on the previously focused element when releasing
   * focus. This is useful if the caller wants to handle restoring focus.
   */
  skipRestoreFocus?: boolean;
}

Usage Examples

Basic Modal Dialog

import { FocusTrap } from '@material/dom/focus-trap';

// Create modal dialog
const dialog = document.querySelector('.dialog');
const focusTrap = new FocusTrap(dialog);

// Show modal and trap focus
dialog.classList.add('open');
focusTrap.trapFocus();

// Close modal and restore focus
function closeDialog() {
  focusTrap.releaseFocus();
  dialog.classList.remove('open');
}

Modal with Custom Initial Focus

import { FocusTrap } from '@material/dom/focus-trap';

const modal = document.querySelector('.modal');
const primaryButton = modal.querySelector('.primary-button');

const focusTrap = new FocusTrap(modal, {
  initialFocusEl: primaryButton
});

// Show modal - focus will go to primary button
modal.style.display = 'block';
focusTrap.trapFocus();

Skip Automatic Focus Management

import { FocusTrap } from '@material/dom/focus-trap';

const drawer = document.querySelector('.drawer');
const focusTrap = new FocusTrap(drawer, {
  skipInitialFocus: true,  // Handle initial focus manually
  skipRestoreFocus: true   // Handle focus restoration manually
});

// Show drawer
drawer.classList.add('open');
focusTrap.trapFocus();

// Manually set focus
drawer.querySelector('.first-item').focus();

// Close drawer  
focusTrap.releaseFocus();
drawer.classList.remove('open');

// Manually restore focus
document.querySelector('.menu-button').focus();

Accessibility Features

Focusable Element Detection

FocusTrap automatically detects focusable elements including:

  • Elements with tabindex attribute
  • Elements with autofocus attribute
  • Interactive elements: a, input, textarea, select, button
  • Elements that are visible and not disabled
  • Elements not marked as aria-hidden="true"

Sentinel Elements

The focus trap uses hidden "sentinel" elements to detect when focus attempts to leave the trapped area:

  • Sentinels are placed at the beginning and end of the trapped region
  • When a sentinel receives focus, it redirects to the appropriate boundary
  • Sentinels are marked with aria-hidden="true" for screen readers

Screen Reader Support

  • Maintains proper focus order for screen reader navigation
  • Doesn't interfere with screen reader virtual cursor
  • Properly handles aria-hidden and aria-disabled attributes
  • Works with assistive technology focus management

Keyboard Navigation

  • Supports Tab and Shift+Tab navigation
  • Wraps focus from last to first element and vice versa
  • Respects custom tab order via tabindex values
  • Handles complex focusable element hierarchies

Error Handling

// FocusTrap will throw an error if root has no focusable children
const emptyDiv = document.createElement('div');
const focusTrap = new FocusTrap(emptyDiv);

try {
  focusTrap.trapFocus();
} catch (error) {
  console.error('FocusTrap: Element must have at least one focusable child.');
}

docs

announce.md

events.md

focus-trap.md

index.md

keyboard.md

ponyfill.md

tile.json