Wednesday, January 20, 2016

HTML5 accordion: Overview and an example

The concept of accordions/show more elements using HTML5 <details> and <summary> elements is not totally new in terms of W3C specs, but the browser support for it  has been somewhat sparse as of this writing, in spite of which there seems to be a considerable usage of this approach with polyfills. Perhaps I should say explorations for the lack of exact data on production implementations, but I hope this post inspires more developers to use this approach thus leading to more browsers supporting it.

In this post, I will give a brief overview of the specifications and explorations so far; examine the concept from a more holistic perspective of UX, accessibility and performance; share some quirks that I came across in my implementation and a few challenges that I solved to add on to the existing information contributed by other awesome developers referred in the links here and any others that I may have missed.

How does the HTML5 accordion code differ from the current implementations?


Briefly put, HTML5 based “accordion” (to keep it as a catch-all term) provides HTML elements such as a clickable <summary> element which is basically what it states to be, a summary of the information that you will see in more detail within the parent <details> element and the browser inherently adds an “open” attribute to the details of the summary element when opened without the need of any additional Javascript.

Furthermore, the open and unopen/native states are easily stylable with CSS including custom markers (arrow indicators) for the summary elements as :before pseudo elements which are discussed in much detail in some of the links I've shared in this post.

On the contrary, as you might be aware, traditional accordion code just makes use of a basic div content or <section> coupled with CSS and Javascript/jQuery. There are also examples of purely CSS based accordions making use of checkbox hack  or CSS :target pseudo selector which do have some issues and constraints.

Here's a markup snippet in brief. Note that summary is a child element of the details in the DOM (?!).

1
 2
 3
 4
 5
 6
 7
 8
 9
10
<details>
<summary>Summary of the information on an interesting </summary>
<p>Here’s where we add more details on what we summarized above. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris orci 
sem, suscipit id placerat eget, porta ornare turpis. Maecenas eget risus
eget ligula lobortis laoreet. Donec nec pellentesque elit. Nullam nibh 
mi,rhoncus pretium dolor et, mollis convallis enim. Ut accumsan 
faucibus tortor a porta. Nam sollicitudin elit urna, eu scelerisque 
purus venenatis vel. Aliquam non magna sit amet est pulvinar finibus.
</p>
</details>

And a simple example of corresponding CSS below.

1
2
3
4
<style>
details > summary { transition: color 1s; color: $primary; }
details[open] > summary { color: $links; }
</style>


With this brief introduction, I consider this an appropriate, useful and semantic HTML element for a major UI, UX pattern that we can harness with basic markup and CSS.

Why an accordion/"show more" element? 


As with any UI, UX pattern and implementations of it, I think it is important to do our due diligence weighing in on all aspects (usability, accessibility, performance) and justify its use before jumping in and littering the interwebs with questionable patterns, which we have a good many of and struggling to get away from.

Used appropriately, coupled with good information scent, especially on mobile, I think a 'show more'/reveal/accordion/FAQ pattern is helpful in presenting a user with progressive disclosure and the benefit of scanning available options before focusing in on one, instead numerous choices thrown all at once, while also conserving crucial mobile real-estate.

It might be stating the obvious (but still seen quite often), but it shouldn't be used to just hide the most important content of a page, eg. the top 5 things that we’ve chosen carefully that you will need on this page/portal/app which are now hidden needing a click to reveal, just beats the purpose of having carefully curated such content, and as with any other UX interaction pattern, the usability analysis and user behaviors on your site is what matters most, although we can use general industry studies and data as a starting point, many of which may very well resonate with the ours, such as the ones below.

https://www.nngroup.com/articles/mobile-accordions/
https://www.nngroup.com/articles/accordions-complex-content/

I agree with the above article to a great extent that accordions should be minimally and carefully used on desktop experiences, although I feel the use of accordion for FAQs on content rich pages helps users with glance and focus from my own experience and other studies even if involving an additional click.

Current browser support; is it worth using now with a polyfill and what about accessibility?


While I wouldn’t recommend using this approach for something that can be accomplished with simple hide/show div script if that’s all you need on a page, but if you're using multiple patterns e.g. an FAQ accordion; a show more navigation element (for mobile) or a show more content feature... this helps consolidate all of them with one markup presented with multiple CSS (or common CSS when applicable), which I think is a big win with reducing/consolidating code and patterns.

The browser support for this is yet to be supported by major versions of Internet Explorer (still undead for many of us in analytics) and Firefox (really disappointing), so if one were to argue is this really worthwhile using javascript, jQuery based polyfills to accomplish, ironically, a markup to create an accordion markup without javascript (in many others that support it), my answer is yes, for the reasons below.
  • Semantic markup, clean and lean code when compared to the bloat that goes into many current implementations. 
  • Polyfills such as these below, address and fix accessibility issues
    https://github.com/mathiasbynens/jquery-details

    https://mathiasbynens.be/notes/html5-details-jquery

    while taking advantage of the browsers that already support natively. One can roll their own work-arounds for any specific options needed and as soon as more browser support becomes available just drop the polyfill script. 
  • Many existing cross-browser support scripts/polyfills are light-weight and accessible, more so than some current non HTML5 implementations I’ve seen on pages. Eg. jQuery UI library dumped in to just provide this one functionality!! eg. the polyfill linked here adds aria-expanded="true" tabindex="0" to the elements to be better accessible. To quote WebAIM, "A tabindex value of 0 indicates that the element should be placed in the default navigation order. This allows elements that are not natively focusable (such as <div>, <span>, and <p>) to receive keyboard focus".
If you want to dig into more details, here are some links:
http://html5doctor.com/the-details-and-summary-elements/
https://github.com/mathiasbynens/jquery-details
http://blog.teamtreehouse.com/use-details-summary-elements

There are some Vanilla JS polyfills as well in the above links.

Quirks, issues and additional information that I came across in my implementation


Not being able to deep link into a specific FAQ (e.g. http://localhost:8888/yourpage.html#faq3) was one of the issues/caveats that folks have raised in the above links/discussions, which I was able to address and make it work, as briefly described below, by treating each summary element as a named anchor tag, coupled with a few additional lines in jQuery below the mark-up.

Although I’ve tested this in multiple browsers, this has not been tested exhaustively just yet and I may be updating this post with more issues/solves if any. This markup and related script I added (for deep-linking into the accordion) is in conjunction with the polyfill script in the above link, so some of my notes and code may correspond to that (extending it) although this approach may very well work with other scripts for cross-browser support also.

1
 2
 3
 4
 5
 6
 7
 8
 9
10
<details> 
<summary>
<a name="faq3" id="faq3" class="faq"></a>
FAQ 1
</summary>

<p> <strong>Answer to FAQ 1. The details go here.</strong> senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. <em>Aenean ultricies mi vitae est.</em> Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed,, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci, sagittis tempus lacus enim ac dui. <a href="#">Donec non enim</a> in turpis pulvinar facilisis. Ut felis.
</p>

</details>

Get the location hash for the anchor link into a variable.

1
var currentAnchor = window.location.hash.substr(1); //substr(1) to get rid of the # prefix

Make sure you have checked for the presence of location hash with anchor name. Then find the details element closest to that anchor and set the attribute of that to open, so when the URL with that hash is hit, users will see the specific FAQ/content open.

1
2
3
if (currentAnchor.length > 0) {
jQuery('a[name=' + currentAnchor + ']').closest('details').attr('open', '');
}

NOTE: I used .attr as .prop doesn't work in non-compliant browsers. Also needed to include an empty value for open instead of 'true' as Firefox, implemented via the polyfill was choking on the latter and wouldn’t enable 'close' on the 'opened' details element within the focused summary element.

The above approach was also to make it work in Firefox which doesn’t seem to fire a focus event for anchor tags in the URL as opposed to something like below which worked in browsers that did fire a focus event on anchor tags in a URL (obviously our friend Chrome) by focusing in on the class of the summary element containing current anchor name in focus e.g. #faq3 and getting to its closest detail by (this). So if you're thinking like below, it didn't work cross-browser.

1
jQuery('.faq').focus(function () { jQuery(this).closest('details').prop('open', true); });

While styling with CSS, make sure you include styles for both details element and details .open class that the polyfill above adds to non-supporting browsers.

NOTE: As of this writing, the height transition of CSS didn’t quite work in spite of trying out a set height for details[open] element although I wouldn’t really recommend a set height for most cases as it is better left at auto height.

Well, it ended up to be quite a longer post than I expected for a 'simple' accordion. Hope you learned something new here and hope more browsers implement this soon and your analytics will show mostly browsers that support. We can only wish.

References:


https://html.spec.whatwg.org/multipage/forms.html#the-details-element

http://caniuse.com/#feat=details
http://html5doctor.com/the-details-and-summary-elements/
https://mathiasbynens.be/notes/html5-details-jquery
https://github.com/mathiasbynens/jquery-details
https://www.nngroup.com/articles/accordions-complex-content/
https://www.nngroup.com/articles/mobile-accordions/

No comments:

Post a Comment