Lately I decided I was going to recreate the interactive features of the details
element using JavaScript (apparently the same day as fellow Brightonian Jeremy Keith).
However I ran in to some very serious issues with the tag, so serious, in it’s current state, it’s unusable.
Overview of the details element
The details
element, by default, is a collapsed element whose summary, or label, is the first child legend
(if no legend
is used, the UA provides a default, such as “Details”), with a triangular button to indicate it’s current open state.
If you include the open
attribute, then the element is open by default. In theory, you could attach a click event to the legend, and switch the open
attribute.
The markup would roughly be this:
<details open="open">
<legend>Terms & Conditions</legend>
<p>You agree to xyz, etc.</p>
</details>
Here’s the details test page I was working from: HTML 5 details test
The issues
The biggest problem, and the show stopper for me, is that the browser’s treatment of the legend
element completely breaks this markup pattern – this is true for all the major browsers: Opera, Safari, Firefox and IE (tested in all the latest and some older browsers). I’ll go in these issues in detail in a moment.
Other problems include:
- Styling the legend element is exceptionally difficult, particularly positioning
- Using the WHATWG guidelines to styling the
details
element prove both difficult to interpret and difficult to implement. - When using CSS to style the open state of the
details
element using:details[open] { height: auto; }
, meant that once I changed the open state using JavaScript, it wouldn’t trigger the browser to redraw (as it would if I had added a class). I’ve run in to this before, CSS 2.1 is styling source, not the DOM.
Legend treatment
Surprisingly Firefox is the worst one out in these issues, the rest of the browsers have fairly same treatment of the issue. In the screenshots, I’ve included a fieldset
and nested legend
for reference.
Internet Explorer
IE7 & IE8 closes the legend
element it encounters when it’s not inside a fieldset
element and move it’s contents out to an adjacent text node.
What’s also strange, is that looking at the DOM it also creates another empty(?) closed legend
element after that text node. It doesn’t have any effect, but just looked odd:
Opera
Opera (9 & 10b) is very similar to IE in it’s treatment of the legend
in the details element, except it doesn’t create the second closing legend
node. It just closes the legend
, and creates the adjacent text node.
Safari
Safari simply strips the legend
all together out of the DOM. So much so, that if you open the web inspector, then the error console, you’ll see it warning out that it’s encountered an illegal element, ignoring it, then encountering the closing tag, so it ignores that too. You’re left with just the text node.
Firefox
The best for last. Firefox goes one step beyond the other browsers. It assumes you’ve forgotten to include the fieldset
element. So when it hits the legend
element, Firefox inserts an opening fieldset
up until it finds (I believe) the closing fieldset
element, which obviously it doesn’t so the result is the rest of the DOM, after the first illegally placed legend
ends up eaten by fieldset
element, which leaves my DOM in a mess:
Impact on other elements
details
isn’t the only element that reuses the legend
element for labelling, the figure
element also is supposed to support the legend
element. The result is obviously going to be the same.
Conclusion
We can’t style the legend element when the text is being thrown out by all the browsers, and Firefox’s DOM mangling is just too painful to look at.
This basically means that we can’t, in any reasonable amount of time, use the legend
element inside both the details
and figure
element in the spec’s current state.
For me, I’ll be using an alternative element, probably just a p
element styled to look like a legend
, but that’s really not the point. Ideas anyone?
It turns out we weren’t the only ones looking at this and Ian Hickson has responded on the issue:
My plan here is to continue to wait for a while longer to see if the parsing issues can get ironed out (the HTML5 parser in Gecko for instance solves this problem for Firefox). If we really can’t get past this, we’ll have to introduce a new element, but I’m trying to avoid going there.
It’s fine to think that Gecko will update, but it’s IE that I’m worried about, they won’t turn out their render engine, and the result is we’ll have to avoid using the legend
in any element other than fieldset
.
19 Responses on the article “Legend not such a legend anymore”
Oddly, Remington, I’d also been playing with <figure> for my OSCON and decided not to demo it as I couldn’t reliably style the legend that it uses to caption an image.
Here’s a test to style
legend
green, with nestedsmall
element blueWarning: image of me in cocktail dress.
Thanks for writing this up, Remy. I was going to shoot off an email to the WHAT WG list to explain what I found when I tried the same experiments as you but this makes it a lot clearer where the problems lie.
W3 seems to say that the correct markup for details is:
Your example has it open=open, I’m sure it won’t make any difference as legends have always been horrible to position but thought I’d point it out anyway.
Also, your Firefox example is using the source generated by Firebug. Not sure how Firebug generates it’s HTML but it seems to insert all kinds of crap that isn’t actually in the page (check the actual source in Firefox, those Fieldsets are not there) so I’m not sure who is producing the correct HTML; firebug or view source in Firefox?
I suppose Firefox will get this right in the next version using the HTML 5 parser Henri Sivonen is working on. But that might mean it won’t be usable until Firefox 3.5 has died out. Or that we have to send pages as XML to the Fox, as with FFox 2 and header, footer, aside, section, etc.
@Chris Mahon
There is a difference between GENERATED source and the original source. Firebug shows the former, aka the internal DOM representation of the document. The tool is not the problem. The HTML parser is.
Can you provide a graphic of how it’s supposed to look, cause I don’t understand the use atm. triangular button?
The legend element is a bit of a nightmare for current browser support. Even as a company that prides itself on accessibility, there have been several occasions we’ve dropped the use of legend in fieldsets in favour of headings.
FWIW. I ran the test page in Minefield. The DOM is OK with HTML 5 parsing turned on.
It is also OK as expected in 3.5 using XHTML.
More confusing discrepancies: In FFox 3.5 document.querySelector and document.querySelectorAll tracks the DOM, not the source, in the few tests I just ran.
I’ve always hated legends and fieldsets. It just seems to go against the standard styling behaviour every other element obeys.
If an element 1 is inside div A and div A is set to overflow:hidden then any portion of element 1 that extends beyond the width/height of div A is not visible. Right?
But Legends are by default positioned to be halfway outside the top edge of the fieldset and when you make the fieldset overflow:hidden you can STILL SEE THE ENTIRE LEGEND! It does not obey! It’s so rude!
@Chris Mahon – looks like your markup was stripped from the comment. None the less:
1. The open=”open” is valid, I suspect you had open=”true” or just ‘open’ as an attribute. It’s boolean, but not in the sense of it should be equal to true or false, it just needs to be present.
2. Firebug is showing me the rendered DOM which is what is being styled. So, the source code is one thing, the rendered DOM is the actual thing we’re interested in, and using Firebug, or the IE developer toolbar, we can see that the browser has changed the DOM to suit it’s parsing rules – hence this whole mess with the
legend
element.@Lars Gunther – thanks for testing with the HTML 5 parsing turned on – and you’re right, it’s not going to be on by default until FF 3.5 has died out, ignoring IE for the minute – that’s going to be a long while! Which is what takes me back to using another element other than
legend
. Sending XHTML is fine, but not suitable for IE, and IE still and will continue to, have majority market – so we, as authors, need a solution that truly does pave the cowpaths.Regarding the querySelector and querySelectorAll – I expect it to run against the rendered DOM, rather than the source. Keep in mind that this would then break if we modified the DOM, say changing the ID of an element, and ran querySelector – it should query the latest version of the DOM, and not the original source code that was delivered to the browser.
@Adam – the closest I was going by the description in the specs, but I’m no browser vendor, so I wouldn’t like to say! I’m assuming it looks like a normal
p
element with a triangle to the right that rotates when it’s open (again, this is going by the spec). Either way, without the triangle, it should appear, something like the normal legend + fieldset combo (I think!)Woah. That’s nuts. I’ve been using figure/legend quite extensively and hadn’t encountered this. I think it’s possibly because we aren’t using the document.createElement trick? Looking at our test pages in Firebug I just see the legend element has been disappeared from the DOM and it’s contents appears as a child of the figure.
Ah, scratch what I said about the Javascript. Firefox doesn’t generate random fieldsets if the figure is contained within a block level element.
I’m working on this issue right now, and I have a forward and backward compatible way to make this work, but unfortunately, it does require a little addition markup:
{details}
{legend}{span class=”legend”}Details{/span}{/legend}
{div}
{p}Detailed contents go here. They must be nested in a div unless I figure out a reliable way to move the original contents of the details element into a new div dynamically created. If you can help with that, I will be thankful; it’ll cut down on the extra markup required.{/p}
{/div}
{/details}
Once I am done with my solution, I will post a link to it here.
I revamped my Fiks.html script and moved it to Google code. It includes the cross-browser solution for the details element and html 5 in general: http://code.google.com/p/fiks-html5/
@Aleksey – as much as I hate to rain on your fire, but your solution doesn’t quite work :-( (it looks great by the way) – I released a similar demo last week: http://remysharp.com/demo/details-with-js.html (but I’m still not happy with it – the label element doesn’t have keyboard support in Safari, and Firefox still has general problems with keyboard focus).
Anyway, here’s where it doesn’t quite work: remove the wrapping div from the entire solution, and you’ll see Firefox trigger the vomit bug. Here’s a demo of that happening. Check out the markup delivered to Firefox, then check the rendered DOM (in Firebug), you’ll see they’re completely different. ;-(
Close, but interesting that the vomit bug doesn’t trigger if the
details
andlegend
element aren’t a direct decedent of thebody
element.I didn’t implement keyboard yet, but I think I can make it work correctly. I think we can put the ideas together and get something that at least somehow works. I don’t think we’ll have a choice when we start implementing this than to wrap details in a known block level element to be compatible with Firefox (new html 5 block elements don’t prevent the vmoit bug).
Also, there’s a problem with your solution with switching the display for the elements inside the details element which would make it have problems with elements that wouldn’t have a default display of block. The WHATWG recommendations specifies the default look for details like so:
the DOM would then be:
details
..legend
..p the actual details
but what is getting styled would look like this:
details
..block_legend_wrapper (invisible to DOM)
….legend
..block_contents_wrapper (invisible to DOM)
….p the actual details
The legend is already a block element, so I just use that, but I emulate the contents wrapper with a div inside the details element which works, but is visible to the DOM of course.
Sorry, small correction: legend isn’t a block element, but acts like one in most browsers when forced to be used inside a details or figure element.
Updated my solution to include keyboard support. It works in Safari 4, but not Safari 3. Seems to work fine in Firefox too; what exactly goes wrong in Firefox with your’s?
[…] element may be a fieldset, figure or details element. However, Remy Sharp’s article entitled legend not such a legend anymore shows why it is not practical to use legend for the new elements details and figure – because […]
Join the discussion.