Accessible Clickable Area

by _sir

HTML

<div class="actionable" data-click-area-expanded>
  <p>
  So much content
  that it's not funny
  </p>
  <p>
  <a href="#" class="learnMore">Learn More</a>
  </p>
  <label for="buttonBlue" class="sr-only">View Details for Check 844</label>
  <button id="buttonBlue" class="viewDetail" data-click-area-target="true">
    &rarr;
  </button>
</div>

<div class="actionable" data-click-area-expanded>
  <p>
  So much content
  that it's not funny
  </p>
  <button class="info learnMore">
  ℹ️
  </button>
  <label for="buttonRed" class="sr-only">View Details for Check 123</label>
  <button id="buttonRed" class="viewDetail" data-click-area-target="true">
  <span>&raquo;</span>
  </button>
</div>

CSS

div.actionable {
  margin: 1em;
  padding: 1em;
  border: solid gray;
  border-width: 1px 0;
  height: 4em;
  position: relative;
}

.actionable button.viewDetail {
  background: steelblue;
  color: white;
  font-weight: bold;
  font-size: 2rem;
  position: absolute;
  border: none;
  height: 100%;
  top: 0;
  right: 0;
}
  
button.info {
  border: none;
  background: none;
}
  
#buttonBlue {
  background: steelblue;
  color: white;
}

#buttonRed {
  background: maroon;
  color: white;
}
  
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  border: none;
}

JavaScript

document.getElementById('buttonBlue').addEventListener('click', () => console.log('We clicked the blue button!'));
document.getElementById('buttonRed').addEventListener('click', () => console.log('We clicked the red button!'));

[...document.querySelectorAll('.learnMore')].forEach(el => el.addEventListener('click', () => console.log('Learn more!')));

const clickableElemTypes = ['a', 'button', 'input'];


[...document.querySelectorAll('[data-click-area-expanded]')].forEach((container) => {
  container.addEventListener('click', (e) => {
    const targets = [...container.querySelectorAll('[data-click-area-target]')];
    if (targets.length !== 1) {
      throw new Error('Could not find single click target');
    }
    const [actionTarget] = targets;
    const clickables = [...container.querySelectorAll('a,button,input')];
    const inClickable = clickables.some((el) => el.contains(e.target)); 
    if (inClickable) {
      return;
    }
    console.log('Passing the action from the click area.');
    actionTarget.click();
  });
});