Search code examples
javascripthtmlkeyboard-eventstogglebutton

How can I let users interact with a toggle button using the spacebar and enter key?


I made a toggle button using the label of a checkbox after this example. Users should be able to control the toggle button with both their mouse/trackpad and their keyboard. Mouse/trackpad controls are working fine, and users can focus/select the toggle button using the tab key on their keyboards. I can't figure out how to make pressing the spacebar and enter key toggle the button though.

I searched Stack Overflow and tried solutions using event handlers for keypress and keydown events on the input and/or label element to fire the toggleContent function. I also tried a solution that checked the keycode for enter (13) before firing the toggleContent function. Since nothing seemed to work, I reverted to the last working code that allows the user to select the toggle button using the tab key, but not to toggle the button using the spacebar or enter key.

This is my HTML:

<div>
     <input type="checkbox" id="toggle" class="toggle" name="checkbox">
     <label for="toggle" id="label" tabindex="0"></label>
</div>

This is my JS:

const checkbox = document.getElementById("toggle");

const basic = document.getElementById("basic");
const professional = document.getElementById("professional");
const master = document.getElementById("master");

function toggleContent () {
  if (this.checked) {
    basic.innerHTML = "19.99";
    professional.innerHTML = "24.99";
    master.innerHTML = "39.99";
  } else {
    basic.innerHTML = "199.99";
    professional.innerHTML = "249.99";
    master.innerHTML = "399.99";
  }  
}

checkbox.addEventListener('change', toggleContent);

Full code and deployment can be found here.

How do I allow users to interact with the toggle button using the spacebar and enter key on their keyboards?


Solution

  • A common way to create a toggle button is using the aria-pressed attribute. It represents the buttons current state. It the documentation this is described as:

    Adding aria-pressed to an element with a role of button turns the button into a toggle button. The aria-pressed attribute is only relevant for toggle buttons. It represents the button's current "pressed" state.

    We also need to make sure the button has an accessible name so we know what it toggles. For this we can use aria-label.

    Using a <button> element also comes with the added benefit that it automatically works with the spacebar and enter keys.

    const button = document.getElementById("toggle");
    
    function toggleContent () {
      const isToggled = button.getAttribute('aria-pressed') === 'true';
      button.setAttribute('aria-pressed', !isToggled);
      
      if(isToggled) {
        // Show monthly prices
      } else {
        // Show annual prices
      }
    }
    
    button.addEventListener('click', toggleContent);
    #toggle {
      background: lightblue;
      width: 4.4rem;
      height: 2.4rem;
      border: none;
      border-radius: 2rem;
      cursor: pointer;
    }
    
    #toggle .inner {
      background: white;
      width: 2rem;
      height: 2rem;
      border-radius: 50%;
      transition: transform 0.2s ease-out;
    }
    
    #toggle[aria-pressed="true"] .inner {
      transform: translateX(calc(100% - 0.4rem));
    }
    <button id="toggle" type="button" aria-pressed="false" aria-label="Show monthly prices">
         <div class="inner"></div>
    </button>