Created
June 28, 2022 15:44
-
-
Save romaricpascal/d5771e6008a5fa82f16d3240f0d02bd1 to your computer and use it in GitHub Desktop.
Stimulus controller and helper functions for handling disabled elements via `aria-disabled`
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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