Button States
2021-10-15
I was recently asked to style a html control panel interface for a client. It's essentially a grid of buttons that trigger a macro when pushed. One of the requirements was to have a visible change to the button when it was pressed.
Easy - I’ll said I'll just style out the :active CSS pseudo-class of the button, when a user clicks the button the :active pseudo-class will be toggled triggering a visual change on the button.
"The :active CSS pseudo-class represents an element (such as a button) that is being activated by the user. When using a mouse, "activation" typically starts when the user presses down the primary mouse button. The :active pseudo-class is commonly used on a & button elements" read more about :active pseudo class here
.button--marco {
background-color: $primary;
color: white;
border: 1px solid $primary;
padding: .95rem;
@include transition;
:active{
border: 1px solid $secondary;
background-color: $secondary;
color: white;
}
}
This worked fine on my desktop, until I spun up a ngrok tunnel to test on my iphone. When I clicked the button, nothing happened. Hmmm. Turns out on ios the active states are sent so quickly that the down/active state is never received read more about this on stackoverflow
OK, so scrap that. I'll try a JS solution instead. Let's add an active class to the button when it's clicked. Expermented with the touchstart event for a while, adding an touchstart eventlistener to each button, but just scrolling the page on a touch screen was enough to trigger a button click - ba boww.
Finally settled on the following JS solution that listens for a mousedown event which triggers adding a class of active to the button followed by a timer that removes the class of active from the button after a short delay. Simulating a button ‘press’.
document.querySelectorAll('.button--marco').forEach(function(button){
button.addEventListener('mousedown', function (e){
this.classList.add('active')
if (this.classList.contains('active')) {
setTimeout(() => { this.classList.remove('active') }, 500);
}
});
})