Mathias Bynens

Bulletproof HTML5 <details> fallback using jQuery

· tagged with CSS, HTML, JavaScript, jQuery

The HTML5 <details> element is currently not natively supported in any browser natively supported in Chrome 12 and up. This makes it a little hard to guess how exactly this new element will behave, but reading the spec gives us a pretty good idea. What’s clear is the following:

A details element represents a disclosure widget from which the user can obtain additional information or controls.

This information is hidden by default. It can be made visible by adding the boolean open attribute to the <details> element. After that, the user can toggle the visibility by clicking the <summary>.

The summary element represents a summary, caption, or legend for the rest of the contents of the summary element’s parent details element, if any. If there is no child summary element, the user agent should provide its own legend (e.g. “Details”).

Note that while the spec describes what should happen in case the <summary> element is omitted, it’s still invalid to do so.

It appears to me the summary element should be keyboard accessible as well. You should be able to tab through all different interactive elements (such as links, buttons, form elements), and guess what — summary is one of them. After focusing it with the keyboard, it would be nice to just hit Enter or Space to toggle visibility of the <details> element’s contents. The HTML spec doesn’t say anything about this matter, though.

Note that details got included into HTML5 because it’s such a common behavior for web sites and apps — so common it should be possible to do this without the need for additional scripting to make the whole thing work. However, HTML5 is still a work in progress. The <details> element is not even implemented yet. In the meantime, it’s important to provide a fallback/polyfill when using new features that aren’t (fully) supported cross-browser.

CSS, JavaScript, and jQuery to the rescue

Luckily it’s pretty easy to make <details> work cross-browser using a combination of CSS, (plain) JavaScript, and jQuery.

Detecting native <details> support with JavaScript

First, let’s add class="no-details" to the html element if JavaScript is enabled and the browser does not support <details> natively. This will allow us to write CSS specifically for the occasion our scripts will actually be executed. Adding the class can be done in various ways, but the one I prefer is by placing the following snippet in the <head>:

<script>
// Don’t use this! See note below.
if (!('open' in document.createElement('details'))) {
document.documentElement.className += ' no-details';
}
</script>

Update: Chrome 10 recognizes the open attribute for <details> elements, even though it doesn’t support rendering the element correctly yet. This means the above feature detection method has become unreliable. I’ve now created a more robust feature test for <details>/<summary> support:

var isDetailsSupported = (function(doc) {
var el = doc.createElement('details'),
fake,
root,
diff;
if (!('open' in el)) {
return false;
}
root = doc.body || (function() {
var de = doc.documentElement;
fake = true;
return de.insertBefore(doc.createElement('body'), de.firstElementChild || de.firstChild);
}());
el.innerHTML = '<summary>a</summary>b';
el.style.display = 'block';
root.appendChild(el);
diff = el.offsetHeight;
el.open = true;
diff = diff != el.offsetHeight;
root.removeChild(el);
if (fake) {
root.parentNode.removeChild(root);
}
return diff;
}(document));

So after that, we can just do something like:

<script>
if (!isDetailsSupported) {
document.documentElement.className += ' no-details';
}
</script>

Note that Modernizr currently doesn’t detect <details> support. I’m sure it will be included soon. Update: My feature test for <details> is now included in the Modernizr repository.

Adding some basic style

Now we can add some fundamental styling to the details element and its children.

/* <details> and <summary> are block level elements */
details, summary { display: block; }

/* The following styles will only get applied if JavaScript is enabled and <details> is not natively supported */

/* Add focus styles (for keyboard accessibility) */
.no-details summary:hover, .no-details summary:focus { background: #ddd; }

/* The following styles are not really needed, since the jQuery script takes care of hiding/displaying the elements. */
/* However, we’re still gonna use CSS as well to prevent FOUC in browsers that understand these selectors. */
/* Remember: by default (and probably most of the time), the contents of the <details> element are hidden. */

/* Hide all direct descendants of every <details> element */
/* Note that IE6 doesn’t support the child selector; we’ll work around that using jQuery later */
.no-details details > * { display: none; }

/* Make sure summary remains visible */
.no-details details summary { display: block; }

/* Apply a pointer cursor upon hover to indicate it’s a clickable element. These styles can be applied regardless of whether the fallback is needed */
summary { cursor: pointer; }

The jQuery magic

I’ve written a jQuery plugin that makes it very easy to emulate <details>/<summary> in browsers that don’t support these elements yet. Check out the code on GitHub.

After including jQuery and the plugin, you can just write something like this to emulate <details>/<summary> where necessary:

$('details').details();

The result of the feature test is stored in $.fn.details.support, which will be true if the browser natively supports <details> and <summary>, and false otherwise:

// Conditionally add a classname to the `<html>` element, based on native support
$('html').addClass($.fn.details.support ? 'details' : 'no-details');

The plugin will also add the appropriate ARIA annotations for optimal accessibility. This will be done even in browsers that natively support <details>, just in case.

Demo

I’ve put up a demo page with heavily commented source code as well. Enjoy!

This fallback works in all A-grade browsers, including IE6. It will only be executed if the <details> element is not natively supported in the browser. If it isn’t, and JavaScript is disabled, all elements will still be visible to the user.

Note that you should never pull in a 25 KiB JavaScript library just to make <details> work — this solution should only be used in cases where jQuery is used already. Of course it’s possible to rewrite this as plain JavaScript, but I’ll leave that as an exercise to the reader ;)

Comments

riddle wrote on :

This is a neat demo, exactly what early HTML5 adopters should be doing. Spot on :)

I’d like to suggest how it should look. There is no information about this part in the spec, but I’ve seen “disclosure widget” used in another spec – The Apple HIG. In Mac OS X, this is a disclosure widget:

Screenshot of a disclosure widget in Mac OS X

It’s pretty obvious what it will do when clicked. I think it’s a good starting point.

Remy Sharp wrote on :

Sorry, but I’m going to call you out on the bulletproof bit. Why I wouldn’t call this bullet proof: you’re relying on jQuery — that’s 25k + your code just to enable details by itself — that’s a lot of code for such as small effect (though to your credit — you are suggesting that someone doesn’t include jQuery just to produce this effect at the very end of your post).

As for the rewrite for sans-jQuery — I wrote this last year and dropped it recently into a gist: http://gist.github.com/370590

wrote on :

Remy: By ‘bulletproof’ I mean it works cross-browser, degrades gracefully without JavaScript and/or CSS, and doesn’t interfere with future native implementations.

Requiring jQuery doesn’t make it any less bulletproof, it just adds a dependency. Yes, this script requires jQuery, but it can be rewritten into plain JavaScript, as I indeed noted in my post (and as you already did last year!). I strongly agree my jQuery solution should never be used in the case where jQuery isn’t already included.

I’m liking your version in plain JavaScript — however, unless I’m missing something it doesn’t seem to check for native support, which renders it ‘not bulletproof’ as well. Your implementation is very likely to break when browsers start supporting <details>.

FYI, your script doesn’t seem to work in any version of Internet Explorer.

wrote on :

Shelley: Ah, gotcha! I hadn’t thought of that, thanks. Of course, that didn’t work since details > * { display: none; } doesn’t apply to direct child text nodes.

This is now fixed. I’ve added two examples to the demo page as well to demonstrate this functionality.

wrote on :

Shelley: Which ARIA roles would you suggest? role="button" for the <summary> element?

Which ARIA properties did you have in mind? Should aria-expanded be used as an attribute to the <details> element? If aria-hidden is used, should it be an attribute to the <details> element? Or should a new element be created to wrap the contents?

I discussed this with some people with a far better understanding of the WAI-ARIA spec than myself, and Benjamin Hawkes-Lewis suggested the following:

<details role="section" aria-expanded="false" aria-labelledby="label">
<summary id="label" role="button" aria-controls="content">Summary goes here</summary>
<div id="content" aria-hidden="true">Content goes here</div>
</details>

Shelley wrote on :

What you need to do is ask Ian Hickson and the HTML WG what the ARIA mapping is going to be. Otherwise, we’re all just guessing, because it’s an ill-defined object in the HTML5 spec.

What H-L suggests is pretty much what I have for my demonstrations on removing the details element from the HTML spec. You can see four different types at http://burningbird.net/html5/.

The two I incorporated were aria-expanded and aria-hidden. I’m not sure you need a button role, because it’s not a button. The tabindex should make it keyboard focusable, and NVDA at least says it is clickable.

Do not use section. Section is an abstract, ontological role. The Illinois Center for Information Technology Accessibility uses roles of application, tab, and tablist for an accordion and tabbed page, and this is nothing more than a singular accordion panel. So I’d incorporate these.

Again, though, until this is recorded in the HTML5 spec, what you use may or may not be equivalent to HTML5 details. Unless I can convince the powers-that-be to dump the thing, for the ill-defined thing it is. No offense to your and Remy’s hard work trying to come up with an emulation.

Benjamin Hawkes-Lewis wrote on :

I’m not sure you need a button role, because it’s not a button.

Interesting. Seems to me the disclosure clickable is a button as WAI-ARIA defines it (“An input that allows for user-triggered actions when clicked or pressed”). Whether the addition of this role annotation is actually necessary or helpful is a subtly different question though.

Do not use section. Section is an abstract, ontological role.

Oops — good point. I think its concrete child group might be applicable though.

The Illinois Center for Information Technology Accessibility uses roles of application, tab, and tablist for an accordion and tabbed page, and this is nothing more than a singular accordion panel.

I find a tablist containing only one tabitem slightly odd, like an ol with a single li.

Where you have a list (especially a nested list) of details elements, WAI-ARIA tree and treeitem annotations might also be appropriate.

While I imagine it might be pretty straightforward to implement details natively (for example, as an OS X Disclosure Triangle mapped directly to the AXDisclosureTriangle role in the Apple Accessibility API), I don’t think it’s going to be trivial to come up with one satisfactory ARIA mapping that will cover all the ways developers could fake details with CSS and JS.

Shelley wrote on :

We really can’t emulate details, because there is no accessibility attached to details. We’re not even completely sure of the element’s behavior, or what action triggers the behavior.

Now, if we’re concerned about the appropriate use of ARIA annotation for existing implementations of this type of functionality, then we’re looking at a different thing. For instance, this is a behavior, but applied to a table, it has one connotation, when applied to form elements, or a menu, there are different connotations. And different ARIA annotations to match.

If the item is a popup menu, there is one set of roles and states, as demonstrated here: http://test.cita.illinois.edu/aria/menubar/menubar1.php

However, if the context of use differs, then there will be different roles and states. We keep trying to attach semantics to the behavior, when we need to attach semantics to the use. And we won’t know the use, until it’s actually used.

Still, we do have states that map to the behavior: aria-hidden, aria-expanded, aria-haspopup, and others. Mathias, I would recommend looking at the code for jQuery UI. It has implemented ARIA states into many of the effects. I bet it could be an excellent guide.

Benjamin Hawkes-Lewis wrote on :

We really can’t emulate details, because there is no accessibility attached to details. We’re not even completely sure of the element’s behavior, or what action triggers the behavior.

Now, if we’re concerned about the appropriate use of ARIA annotation for existing implementations of this type of functionality, then we’re looking at a different thing. For instance, this is a behavior, but applied to a table, it has one connotation, when applied to form elements, or a menu, there are different connotations. And different ARIA annotations to match.

I think that’s right, although I suspect that defining any particular behavioral implementation of details semantics would be inappropriate for the HTML5 spec. (Just as with input type="file".)

Ryan wrote on :

Totally going away from where this thread is headed, but aren’t the arrows backwards based on state? The arrows should point down when expanded, not to the right. Vice versa for collapsed.

Steve wrote on :

Really handy technique thank you. Been looking into HTML5 and the worry about a fallback is there.

Webstandard-Blog wrote on :

Very interesting, but I think it will take some time until HTML5 will be the Markup-Language no. 1. Using JavaScript for fixing ‘bugs’ is nice, but you will get some code-overhead you don’t really need.

anon wrote on :

it doesn't scroll down automatically when the content is not visible in the viewport something you should fix

Cam wrote on :

How do you default to open? I tried setting the HTML to <details open="open" class="open">, but it seems the script assumes it starts in the closed state. The first click, which should close it, changes that tag to <details> (no attr/class), as it should, but the content stays visible. From then on it works as it should but the content visibility continues to be toggled in the incorrect order.

Cam wrote on :

Mathias: Thanks for writing back! I looks like on your demo page, your <details> element with the open attribute isn’t working either. I’m using Firefox 3.6.10 (most recent version out at this date). It works fine in Chrome, but in FF it doesn't close the first time clicked, then alternates normally, but showing/hiding the content at the opposite times it should.

wrote on :

Cam: Ah, I see it now; thanks! I had made some changes to the demo page recently and should’ve tested more thoroughly afterwards. It seems Firefox 3.6.x doesn’t like this line of CSS:

.no-details details[open] > * { display: block; }

Since this rule is not really necessary anyway (we use JavaScript to take care of displaying/hiding the contents), I just removed it. Works fine now :)

Cam wrote on :

That's got it! Thanks so much, Mathias. Fantastic work. I love being able to use HTML5 elements with graceful fallback like this.

Prestaul wrote on :

This worked great a week ago, but in the latest version of Chrome (10.0.648.82) the native support detection no longer works properly. <details> nodes now have an open property that seems to behave properly (e.g. if you node.setAttribute('open', 'open'); then node.open == true) but there is no visible change to the element.

Time to find a new method of detection!

wrote on :

Prestaul: You’re right, the WebKit team has started implementing <details> and this is the first phase of that.

You should note that this only affects nightly builds and beta releases though. The latest stable Chrome release at this time is 9.0.597.102 (not 10.0.648.82).

This is a known ‘bug’ in WebKit. Check out comment #48 which I wrote a couple of days ago:

As long as this patch isn’t landed, WebKit false positives on the feature test for native <details> support (without actually supporting it) […]

As long as there’s no stable browser release with this issue, I don’t think we should start looking for a more complicated feature test.

Jonathan wrote on :

Looks as though the stable Chrome 10.0.648.127 has broken this script. I'm not using exactly this method on my own site (I use Prototype) but I've put up a Gist with a possible change to this one. Sadly it's based on browser detection, but it shouldn't catch the latest stable Safari because of the version detection.

wrote on :

Jonathan: That is very sad news indeed. The solution you have right now is the following:

if (!('open' in document.createElement('details')) || ($.browser.webkit && $.browser.version >= 534.16)) {
// <details> is not natively supported
}

As you mentioned, it’s a shame that we have to rely on browser detection for something as simple as this. The code will have to be edited even more as soon as WebKit fully supports <details>.

Let’s see if we can come up with a more robust feature test. Maybe support could be detected by injecting <details><summary>foo</summary>bar</details> into the document, checking the height of the <details> element, adding the open attribute (or triggering onclick on the <summary>), then checking the height again to see if it changed. If it did, <details> is likely to be supported.

David Mark wrote on :

First off, why would you use jQuery to detect HTML5? jQuery is clearly not appropriate for modern browsers (and Prototype less so) and only a handful of modern browsers have started to implement HTML5. There are so many things wrong with the strategy; it’s hard to know where to start.

Mathias has the basic idea, but I sure wouldn’t rely on jQuery’s height method. ;)

I am glad to see that attribute reflection and inject-and-detect feature testing have finally reached the LCD libraries. You’re welcome. :)

http://www.cinsoft.net/host.html

But it is disappointing to see developers dropping back to baseless UA sniffing as soon as they hit a perceived wall. Browser sniffing?! More like browser winning! :)

Took them five years to get there, but they’ll go back in five minutes. Anything to “save time” and “just get things done”. It’s worse when you have a hundred cooks in the kitchen.

BTW, this script that is monitoring my keystrokes is terrible (terribly slow anyway). The only cross-browser keyboard handler on the Web is here: http://www.cinsoft.net/mylib-keyboard.html

Yes, it’s an add-on for My Library, but there is a slightly lesser generic version located in the Primers section. As one might expect, both are fast. Accurate, too. And, wonder of wonders, no browser sniffing and no broken or “unsupported” browsers in its wake. Look at the typical “framework” for help with keyboard input and you find lots of browser sniffs, abominable performance and virtually no explanation of their shortcomings. I’m sure whatever jQuery plug-in is used here is of similar “quality”. And, as a user, I’m complaining about it. Never mind the script; the rendered behavior is headache-inducing.

David Mark wrote on :

And dammit, I can’t believe you are trying to use the attr method for this. Of all things. :)

http://www.cinsoft.net/attributes.html

Don’t do what Resig did (e.g. try to copy the code without understanding it). If you think about what you are doing, you will realize that you don’t need a wrapper for this at all.

PS. There’s nothing self-documenting (or magic) about jQuery code. Think about it.

wrote on :

Native support for <details> and <summary> just landed in WebKit. <summary> elements aren’t keyboard-navigable yet, but accessibility issues will be handled in future patches.

What’s exciting is that the native behavior looks almost identical to the demo page :)

Cam wrote on :

It looks like Chrome 10 has implemented <details> with an open attribute, but the functionality doesn’t work yet. So your detection code things Chrome’s good to go even though it’s not.

Is there a more consistent way to detect if the functionality works?

wrote on :

Cam: You may wanna read the above comments, starting at comment 25. I describe a possible feature test for <details> support.

Your comment convinced me I should write it out, so here goes:

var isDetailsSupported = (function(doc) {
var el = doc.createElement('details'),
fake,
root,
diff;
if (!('open' in el)) {
return false;
}
root = doc.body || (function() {
var de = doc.documentElement;
fake = true;
return de.insertBefore(doc.createElement('body'), de.firstElementChild || de.firstChild);
}());
el.innerHTML = '<summary>a</summary>b';
el.style.display = 'block';
root.appendChild(el);
diff = el.offsetHeight;
el.open = true;
diff = diff != el.offsetHeight;
root.removeChild(el);
if (fake) {
root.parentNode.removeChild(root);
}
return diff;
}(document));

The isDetailsSupported variable will be true if <details> is natively supported, and false if not.

Feel free to use the above snippet as you please. It’s public domain, really. Update: This code snippet has since been included in has.js and is available as a Modernizr plugin as well.

Some notes:

  • As you can see, the script will automatically create a new <body> element if there isn’t one already (i.e. when the script is called from the <head>). This is done to make sure the test <details> element is visible so we can measure its height. The fake <body> element will be removed from the DOM afterwards. This technique is used a lot in has.js, the à la carte feature detection library.
  • The snippet creates a new <details> element and sets its display CSS property to the block value. This is done for two reasons. Firstly, most browsers that don’t support rendering <details> and <summary>, treat these elements as inline elements (display: inline). If we don’t override that, there’s no way to get reliable results for the height in all browsers. Secondly, this makes sure the test will still return the correct result when the document has details { display: none; } in its style sheet. (Edge case, but still.)

Mark wrote on :

Your code seems to break with the new jQuery 1.6.1. With 1.6.0 the fallback in FF etc. works just fine, but with the new jQuery version the open attribute gets ignored.

open = $details.prop('open'); (as they suggested for boolean values) doesn’t work either…

Carlos Ramirez III wrote on :

I was experienced an issue where the open attribute wasn’t being removed upon collapsing the details element. It seemed like the call to $details.attr('open') was always returning undefined.

I replaced that expression with $details.is('[open]') instead and that seemed to fix the issue.

Did a quick check on a bunch of different browsers and it seemed to work correctly. Hope that can help anyone else seeing the same issue.

Stephan Sokolow wrote on :

Your implementation of the open attribute seems to be broken in Firefox 6.

Works in Chromium 13.0.782.107’s native details support but all examples display collapsed in Firefox 6 once I tell NoScript to allow JS.

Daniel wrote on :

Thanks for this script it works great, bar one thing.

If there are any <script> tags within the details element it gets the attribute display: block; added to it. This subsequently prints the actual code between the script tags to the screen in Safari and possibly other browsers that don’t natively support the details tag.

What code would need to be added in order for the script tags to be left alone?

Kristof Smessaert wrote on :

Nice script. It seems to work well in IE7 and IE, however, I’m using the latest jQuery library and the code doesn’t work properly in old IEs then. (Tried $details.is('[open]') but didn’t seem to work.)

I decided to try and build a kind of an ‘override’ or ‘custom’ for the details and summary. (Quite simply just a little script that shows and hides the content when clicked upon.) It works a charm but of course there are now 2 buttons in Chrome… My image and the black default triangle.

My question of course: does anyone know how to get rid of the black triangle in Chrome (and other future browsers)?

I’m trying to switch to HTML5 AND use correct elements and tags, but the details tag got me thinking — how are we to style something that’s native or hardcoded in the browser? I mean, the black triangle thing just looks awful and it just seems kinda stupid to me — correct me if I’m wrong — that we’re not able to get rid of it…

Thx for taking the time to answer!

wrote on :

Carlos, Stephan and Kristof: I just added support for jQuery 1.6+ by replacing $details.attr('open') with this.getAttribute('open').

[D]oes anyone know how to get rid of the black triangle in Chrome (and other future browsers)?

I’m not sure how feature browsers will implement it, but in WebKit browsers you can use ::-webkit-details-marker:

summary::-webkit-details-marker {
display: none;
}

Daniel: Got a link to a test case? I cannot seem to reproduce the issue of <script> elements becoming visible. Anyhow, you could probably use jQuery#not somewhere to fix it.

Daniel wrote on :

Hey Mathias,

I have put up a test case here for you to look at. Think I have set everything up correctly as it seems to function correctly, bar the script tag being printed to the screen in Safari.

I'm using OSX 10.7.1 Safari 5.1

wrote on :

Daniel: Hmm, I cannot reproduce the issue on my demo. Perhaps you’re using a modified version of my script?

Of course, ideally there wouldn’t be any <script> elements inside of the <details> element. Scripts should go at the bottom and all that ;)

Thierry wrote on :

If $(document.createElement('summary')) works in IE, but not $('<summary>'), it is for the same reason that section, article, footer, etc. fail. For IE to “understand what to do with those”, we need to rely on document.createElement():

document.createElement('abbr');
document.createElement('section');

wrote on :

Thierry: That’s not the whole story, though. I’m including the HTML5 shiv on the demo page, and even then $('<summary>') doesn’t work. Perhaps something like innerShiv would help, but for now, this quick and dirty fix is good enough for me :)

Peter Sylvester wrote on :

I have tried Remy Sharp’s version. For Opera, I needed to modify the attribute logic:

if (this.hasAttribute('open')) {
this.setAttribute('open', '');
this.removeAttribute('open');
} else {
this.setAttribute('open', 'open');
}

The removeAttribute doesn’t seem to work.

In order not to interfere with native handling, and to avoid warnings from the W3C HTML5 validator I used blockquote instead of details, and header instead of summary.

html5anchor wrote on :

Hello Mathias

Great fallback.

Two suggestions:

  • Add a child combinator to the selector on line 39. So 'summary' becomes '> summary'. This allows for nested details elements to work properly.
  • Make it a real jQuery plugin so that you can decide when the code should run and that you can easily reinitialize it after you have loaded content with AJAX.

LedgeT wrote on :

Whilst I love this post as a wonderful example of the collective evolution of ideas. By the time I've read through all the different comments I'm left baffled by how to implement effectively these particular elements, which I think was whole point of Mathiass' original post.

Is the demo the most up to date / recommended implementation? If not would someone be able to help with what is?

Cheers Guys and Gals.

LedgeT wrote on :

Thanks Mathias. I have a responsive design that requires the details to be closed in one view but open in another. Is it possible to do this based on changing the parent class?

Alice Wonder wrote on :

Personally I am just using the details tag as it is. I use it on one site for a “works cited” page, it works great in Chrome but I was using it there for well over a year before Chrome supported it.

I am also using it on a few other sites.

Browsers that do not support it still render the content, and that’s fine by me — it just means the user does not get to decide when it is displayed or hidden, it is simply always displayed.

But with respect to a comment earlier in this thread with the enormous size of the jQuery library, Google has it on their public CDN. Use that and chances are really good anyone coming to your site will have a cached copy already so it will usually not impact page load time.

Michael A. Peters wrote on :

I’m taking a different approach to details emulation (but also using jQuery), attempting to make it accessible at the same time. My attempt is at http://www.domblogger.net/Projects/JSdetails.

Currently it works everywhere I have tried except for IE8 (haven’t tried 6/7/9) where I think it is CSS issues and not JS issues. I would appreciate any feedback on my method.

For what it is worth, Alice Wonder (posted above me) and I are working together on this.

David Higgins wrote on :

I love this script. I tested your demo page in all the modern browsers, it works a treat.

However, on this page: http://iwantaneff.in/toolset/

I noticed on Chrome (16.0.912.75), some SPANS (<span style="display:none"></span>) were incorrectly styled as display:none (When <details> was supported natively, that is.)

But not to worry, I patched this up. I got it to work with not much hardship involved — apart from the horrible ‘hacky’ way I approached the problem.

Let me know if I’m doing anything wrong.

Steve Faulkner wrote on :

Mathias: Hi Mathias, I have detailed an example implementation: HTML to Platform Accessibility APIs Implementation Guide.

Corresponding ARIA attributes: to the summary element add a role="button" making sure the keyboard behaviour associated with buttons is added i.e. focusable, enter or space activates the button) and aria-expanded="true/false" (the states corresponding to the absence/presence of open attribute on details). Note that aria-expanded is on the summary, not the details. That’s it.

I should add that tabindex, and the aria-* stuff should still be added to Chrome as it currently is not focusable and does not expose any semantics.

wrote on :

Steve: Thanks for the input! I’ve updated the plugin; v0.0.4 adds the appropriate ARIA annotations to <summary> elements (even in browsers that natively support <details>).

Jonathan Schmid wrote on :

Nice, thanks! Unhappily it doesn’t work with text-align:right applied to the <summary> element. You should better wrap the summary text and apply the image to this tag.

Thomas Landauer wrote on :

Hey, thanks for the script!

The drawback is that with JavaScript disabled (i.e. screenreaders) the entire <details> are always shown (which isn’t always acceptable).

My solution: Right below the <summary>, open a <div style='display:none'>. Then remove the style with JavaScript. To display the <details> without JavaScript, I insert a link into the <summary> and process it server-side.

I would be great if you could integrate this option somehow! If you’re interested, just contact me via email.

arlen wrote on :

Just a heads-up. This seems to be completely broken by jQuery 1.9.1. Detail blocks open but do not close.

Scott wrote on :

One thing I would like to be able to account for is having the ability to toggle all other detail entries closed when one is opened. Additionally I should be able to add a ‘switch’ to the page that lets the user disable this if they prefer to be able to click multiple detail entries open. Are there any hooks for this in the script at the moment?

Nice job by the way. :)

Erik wrote on :

A problem with <details>/<summary> on iBooks 3 for iPad 2: I have made an iBook/EPUB3 study book, with solutions just after the problems, so I can easily expand to see the solution. Very nice interactivity, I think. The book has the page numbering of the original hardcopy book on the left side on the iPad screen. When I expand the <details> block, the page numbers are off by the number of lines of the <details> block. So when I leave some <details> blocks open, the numbering can go seriously haywire. I also cannot see how many <details> blocks I have expanded. To get my page numbers back, I’d have to scroll all the way back to the beginning of the book and close <details>.

Leave a comment

Comment on “Bulletproof HTML5 <details> fallback using jQuery”

Some Markdown is allowed; HTML isn’t. Keyboard shortcuts are available.

It’s possible to add emphasis to text:

_Emphasize_ some terms. Perhaps you’d rather use **strong emphasis** instead?

Select some text and press + I on Mac or Ctrl + I on Windows to make it italic. For bold text, use + B or Ctrl + B.

To create links:

Here’s an inline link to [Google](http://www.google.com/).

If the link itself is not descriptive enough to tell users where they’re going, you might want to create a link with a title attribute, which will show up on hover:

Here’s a [poorly-named link](http://www.google.com/ "Google").

Use backticks (`) to create an inline <code> span:

In HTML, the `p` element represents a paragraph.

Select some inline text and press + K on Mac or Ctrl + K on Windows to make it a <code> span.

Indent four spaces to create an escaped <pre><code> block:

    printf("goodbye world!"); /* his suicide note
was in C */

Alternatively, you could use triple backtick syntax:

```
printf("goodbye world!"); /* his suicide note
was in C */
```

Select a block of text (more than one line) and press + K on Mac or Ctrl + K on Windows to make it a preformatted <code> block.

Quoting text can be done as follows:

> Lorem iPad dolor sit amet, consectetur Apple adipisicing elit,
> sed do eiusmod incididunt ut labore et dolore magna aliqua Shenzhen.
> Ut enim ad minim veniam, quis nostrud no multi-tasking ullamco laboris
> nisi ut aliquip iPad ex ea commodo consequat.

Select a block of text and press + E on Mac or Ctrl + E on Windows to make it a <blockquote>.