Skip welcome & menu and move to editor
Welcome to JS Bin
Load cached copy from
 
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>Trying to fix vendor issues with the details element</title>
</head>
<body>
<h1>Trying to fix vendor issues with the details element</h1>
<p>Date: October 2024</p>
  
<h2>0. Native element: problems with VoiceOver on iOS and Dragon</h2>
<details>
  <summary>Help with nationality</summary>
  <p>
      We need to know your nationality so we can work out which elections you’re entitled to vote in. If you cannot provide your nationality, you’ll have to send copies of identity documents through the post.
  </p>
</details>
<p>
  The native element works as expected in VoiceOver on iOS 18 and iOS 17.5.
  It doesn't work at all in older iOS 15.8. (Only the text, but no role or state gets announced.)
  But it used to work better (although not perfectly) in older iOS version 12.5. (That announces the name and state but not the role.)
</p>
<p>
  The native element doesn't work with Dragon (in Chrome) when saying "click [label of the summary]".
  It does work with "mouse grid" or "tab tab tab [etc] enter".
</p>
<h2>1. VoiceOver on iOS problem with our old version</h2>
<details>
  <summary style="display: inline-block;" class="triangle">Help with nationality</summary>
  <p>
      We need to know your nationality so we can work out which elections you’re entitled to vote in. If you cannot provide your nationality, you’ll have to send copies of identity documents through the post.
  </p>
</details>
<p>
  VoiceOver in Safari has an issue when
  <code>display: inline-block</code>
  is used on the <code>summary</code> element.
  When encountering the element it is correctly saying name, role and state.
  But when toggling it open, it only announces the name but not the role and state.
  When encountering it after it has been opened, it announces the name and role but not the state.
</p>
<p>
  Side note: Because <code>display: inline-block</code> removes the visual disclosure triangle,
  this version adds it back via CSS.
</p>
  
<h2>2. Fixed (ish) for VoiceOver on iOS</h2>
<details>
  <summary style="display: block; width: fit-content;" class="triangle">Help with nationality</summary>
  <p>
      We need to know your nationality so we can work out which elections you’re entitled to vote in. If you cannot provide your nationality, you’ll have to send copies of identity documents through the post.
  </p>
</details>
<p>
  We fixed this (but only for the most recent VO versions) with setting
  <code>display: block</code> and <code>width: fit-content</code>
  on the <code>summary</code> element.
  This now works the same way as the native element does in the iOS versions we've tested,
  so works in latest two versions (18 and 17) but not older versions.
</p>
<p>
  Side note: Because <code>display: block</code> removes the visual disclosure triangle as well,
  this version also adds it back via CSS.
</p>
<h2>3. Fixed for Dragon, new problem for VoiceOver/Safari on macOS</h2>
<details>
  <summary role="button">Help with nationality</summary>
  <p>
      We need to know your nationality so we can work out which elections you’re entitled to vote in. If you cannot provide your nationality, you’ll have to send copies of identity documents through the post.
  </p>
</details>
<p>
  The only thing that makes the <code>details</code> element work properly with Dragon is
  a <code>role="button"</code> on the <code>summary</code> element.
  Although that creates an issue with VoiceOver in Safari on macOS. (It doesn't announce the state.)
</p>
<p>
  Adding an explicit <code>role</code> on something that <a href="https://www.w3.org/TR/html-aria/#el-summary">doesn't have an implicit role</a>
  also means that this will now be announced differently by some screen reader / browser combinations.
  It's specifically Narrator, TalkBack and VoiceOver on macOS with Chrome which would usually announce the role of "disclosure triangle".
  And VoiceOver on macOS with Safari and Firefox announces its role as "summary".
  This change means they all now consistently (for better or for worse) say "button".
</p>
<h2>4. Fixed for Dragon and VoiceOver/Safari on macOS</h2>
<details>
  <summary role="button" class="expanded-state" aria-expanded="false">Help with nationality</summary>
  <p>
      We need to know your nationality so we can work out which elections you’re entitled to vote in. If you cannot provide your nationality, you’ll have to send copies of identity documents through the post.
  </p>
</details>
<p>
  Also setting <code>aria-expanded</code> accordingly on the <code>summary</code> element fixes the issue for macOS.
  Technically, this would now also need an <code>aria-controls</code> (and <code>id</code> on what it controls).
  But that is going down the rabbit hole of completely poly-filling it, which we wouldn't want to do,
  also for performance reasons and because otherwise we wouldn't need to use the details element at all.
</p>
<h2>5. All fixes together</h2>
<details>
  <summary role="button" style="display: block; width: fit-content;" aria-expanded="false" class="expanded-state triangle">Help with nationality</summary>
  <p>
      We need to know your nationality so we can work out which elections you’re entitled to vote in. If you cannot provide your nationality, you’ll have to send copies of identity documents through the post.
  </p>
</details>
<p>
  This is fixed for Dragon and VoiceOver on iOS 18 and 17.
  And it doesn't create any significant new problems for other assistive technology.
</p>
  
  
</body>
</html>
 
/* emulating the disclosure triangle
for when browsers remove the original
when using `display: inline-block`
or `width: fit-content` */
summary.triangle {
  position: relative;
  padding-left: 20px;
}
summary.triangle:before {
  content: "";
  position: absolute;
  top: -1px;
  bottom: 0;
  left: 0;
  margin: auto;
  display: block;
  width: 0;
  height: 0;
  -webkit-clip-path: polygon(0 0, 100% 50%, 0 100%);
  clip-path: polygon(0 0, 100% 50%, 0 100%);
  border-color: transparent;
  border-style: solid;
  border-width: 7px 0 7px 12.124px;
  border-left-color: inherit;
}
 
document.querySelector(".expanded-state").addEventListener('click', toggleExp);
function toggleExp(evt){
  const el = evt.target;
  const exp = el.getAttribute("aria-expanded");
  
  if (exp === "true") {
    el.setAttribute("aria-expanded", false);
  } else {
    el.setAttribute("aria-expanded", true);
  }
}
Output

You can jump to the latest bin by adding /latest to your URL

Dismiss x
public
Bin info
selfthinkerpro
0viewers