Skip to content

Instantly share code, notes, and snippets.

@romaricpascal
Created June 28, 2022 15:44
Show Gist options
  • Save romaricpascal/d5771e6008a5fa82f16d3240f0d02bd1 to your computer and use it in GitHub Desktop.
Save romaricpascal/d5771e6008a5fa82f16d3240f0d02bd1 to your computer and use it in GitHub Desktop.
Stimulus controller and helper functions for handling disabled elements via `aria-disabled`
import { Controller } from 'stimulus';
/**
* Help manage disabling of buttons through the `aria-disabled`
* attribute, rather than the harsher `disabled` attribute.
* Set on the `<html>` or `<body>` element, and get:
* - automatic cancellation of `click` events from targets
* with or within an`aria-disabled` element
* - two actions (`cancelIfDisabled`, `cancelUnlessDisabled`)
* to prevent events and stop their propagation if or unless
* their target is with or within an `aria-disabled` element
*
* @example
* <body data-controller="aria-disabled">
* <!-- ... -->
* <!--
* Render a bootstrap tooltip only if the button is disabled,
* providing feedback to users
* -->
* <button
* aria-disabled="true"
* data-bs-toggle="tooltip",
* title="Can't use me because..."
* data-action="show.bs.tooltip->aria-disabled#cancelUnlessDisabled"
* >...</button>
* </button>
*/
export default class extends Controller {
connect() {
this.element.addEventListener('click', this.cancelIfDisabled, true);
}
/**
* @param {Event} event
*/
cancelIfDisabled(event) {
// The event's target may be a `<span>` or `<svg>` inside the `<button>`
if (withinDisabled(event.target)) {
// Prevent the browser from doing whatever it would have done
event.preventDefault();
// Prevent other JS code from getting an event,
// making it like the event never happened
event.stopImmediatePropagation();
}
}
/**
* @param {Event} event
*/
cancelUnlessDisabled(event) {
console.log('Is event disabled', event);
if (!withinDisabled(event.target)) {
event.preventDefault();
event.stopImmediatePropagation();
}
}
}
/**
* @param {HTMLElement} element
*/
export function enable(element) {
element.removeAttribute('aria-disabled');
}
/**
* @param {HTMLElement} element
*/
export function disable(element) {
element.setAttribute('aria-disabled', 'true');
}
/**
* @param {HTMLElement} element
*/
export function isDisabled(element) {
return element.getAttribute('aria-disabled') == 'true';
}
/**
* @param {HTMLElement} element
*/
export function withinDisabled(element) {
return element.closest('[aria-disabled="true"]');
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment