Category: browser Since: 1.0.0 Tags: dom, element, interactive, event, button, form
isInteractiveElement
Determines whether an element is interactive or is contained within an interactive element.
Usage
import { isInteractiveElement } from "@petr-ptacek/js-core";
document.addEventListener("click", (event) => {
const target = event.target as Element;
if (isInteractiveElement(target)) {
console.log("User clicked an interactive element");
} else {
console.log("User clicked a non-interactive area");
}
});Why This Utility Exists
Distinguishing between clicks on interactive elements (buttons, links, form controls) and other elements is a common need in web applications. This is especially important for implementing custom click handlers, delegated event logic, or overlay behaviors that should skip interactive elements. The utility provides a reliable cross-browser way to check if an element is interactive using CSS selectors and the DOM's native closest() method.
Signature
function isInteractiveElement(element: Element | null, options?: InteractiveElementOptions): boolean;Parameters
element(Element | null): The DOM element to test. Ifnull, the function returnsfalse.options(InteractiveElementOptions, optional): Configuration for interactive element detection.selectors(readonly Selector[], optional): Custom CSS selectors that define interactive elements. If not provided,DEFAULT_INTERACTIVE_SELECTORSare used. Providing an empty array disables detection and always returnsfalse.
Return Type
Returns true if the element matches or is inside an interactive element based on the active selector set, otherwise false.
Type Declarations
type Selector = keyof HTMLElementTagNameMap | string;
type InteractiveElementOptions = {
selectors?: readonly Selector[];
};Default Interactive Selectors
The following CSS selectors are considered interactive by default:
button- HTML button elementa- HTML anchor (link) elementinput- HTML input elementtextarea- HTML textarea elementselect- HTML select element[contenteditable='true']- Any element with contenteditable set to true
These can be imported and extended:
import { isInteractiveElement, DEFAULT_INTERACTIVE_SELECTORS } from "@petr-ptacek/js-core";
isInteractiveElement(element, {
selectors: [...DEFAULT_INTERACTIVE_SELECTORS, "[role='button']", ".custom-interactive"],
});Design Notes
The implementation uses the DOM's native Element.closest() method to check if the element or any of its ancestors matches the interactive selectors. This approach is:
- Performance-efficient: Leverages native DOM methods
- Flexible: Supports custom CSS selectors
- Null-safe: Handles null elements gracefully
- Ancestor-aware: Detects nested interactive elements (e.g., a span inside a button)
The function joins selectors into a single CSS selector string for closest(), making it performant even with multiple selectors.
When To Use
Use isInteractiveElement when you need to:
- determine if a click target is an interactive element
- implement custom click delegation logic
- skip interactive elements in overlay or modal handling
- prevent default behaviors on non-interactive elements
- implement accessible focus management
When Not To Use
Avoid when:
- you only need to detect a specific element type (use
instanceofortagNameinstead) - you need to validate form inputs or user data
- you're implementing keyboard navigation (use native browser APIs)
- the selectors will be extremely large or complex (consider performance impact)
Summary
isInteractiveElement provides a reliable, flexible way to detect interactive elements in the DOM. By leveraging CSS selectors and the native closest() API, it handles both direct matches and nested scenarios with minimal performance overhead.