Hacker News new | past | comments | ask | show | jobs | submit login
Using <details> for menus and dialogs (2019) (css-tricks.com)
144 points by todsacerdoti on April 24, 2021 | hide | past | favorite | 50 comments



The <menu>[1] and <dialog>[2] elements are also pretty good for menus and dialogs.

Full working example of a modal dialog:

    <dialog id="dialog">
      <form method="dialog">
        What is your favorite color?
        <input name="color">
        <button>Save</button>
      </form>
    </dialog>

    <button onclick="dialog.showModal()">
      Show dialog
    </button>
The dialog element is fully supported in Chrome/Edge and Firefox nightly, and there's a polyfill[3] for the others.

[1]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/di...

[2]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/me...

[3]: https://github.com/GoogleChrome/dialog-polyfill


If you need to polyfill for 2 of the most popular 3 browsers then you might as well just use a JS modal library that looks nicer and has more functionality.


Those libraries will come and go, but <dialog> is part of the HTML specification. I like to invest in learning things that are more likely to be around for a while.

On browsers, it's at 73% native support on caniuse, and the polyfill is high-quality, by the Chromium team.

As far as looks, it's all fully styleable with CSS so you can make it look however you like.


Those libraries will come and go, but <dialog> is part of the HTML specification. I like to invest in learning things that are more likely to be around for a while.

Historically it's more likely that an unpopular tag will be removed from the HTML spec and removed from browsers than JS will lose compatibility with your code.

For example, a JS flashing text effect from 25 years ago still works. <blink> tags don't.

Most tags that are deprecated in the spec aren't removed (eg marquee) but you shouldn't assume something in the spec will be available forever.


It's a fair point that specs evolve, and that sometimes includes deprecation. I do feel slightly aggrieved about the `scoped` style attribute being spec'd, implemented, and then dropped shortly thereafter.

But overall I feel this approach has worked well over the years. With jQuery for example, I only learned enough to get by working in those codebases, but I committed to internalized all of the standardized DOM methods and Array methods and naive XHR workings. Now in these modern times, jQuery still _works_, but whatever I came to know of it is no longer very useful to me, day to day.


Deprecated HTML tags are relatively rare though, especially more recently. You can pretty much categorize every one of them into tags that are purely concerned with styling, frame support and applet type things. And in all cases, the deprecation took a long time, long enough that it would outlive most apps.

And nowadays, even if dialog happened to be deprecated, you could always continue to support it using a custom element if you really needed to (which probably wouldn't be the worst approach even if you were building it from scratch, to be honest).


It’s even better than that, stylistically speaking. It’s the first element whose default styling, irrespective of the parent node, is naturally centred both vertically and horizontally with height and width constrained to content size (this alone being one of the CSS holy grails), but also explicitly sidestepping z-index issues even for elements within a nested stack context. All things a polyfill cannot do without caveats.


> On browsers, it's at 73% native support on caniuse

Alternatively: it works in Blink, but nowhere else.


Too late to throw this shade around, I’m afraid, because it’s also available now in Firefox nightly builds (GP may wish to edit to mention) and it’s looking pretty good to me.


This seems to have been supported in nightly for over a year and behind a feature flag even longer but it's still nowhere near ready for GA.

Meanwhile Safari doesn't support it at all.

The stats on caniuse are skewed by Chromium as usual.


On the contrary. It’s very usable in FF nightly right now, including dialog forms, and I know this first-hand because I’m using it. Safari TP support is developmental, not absent.


I'm not saying it's not usable in FF nightly, I'm saying there are major blockers for it to go into GA.

As far as I can tell the rendering is currently hacky (i.e. it doesn't follow the spec but achieves the same visual result) and the implementation is supposed to be tied to the `inert` attribute, which isn't currently implemented in FF. This may not matter to most users but if left as-is would result in cross-browser compatibility issues.


This scuttlebutt is misdirection. No GA browser has release support for the inert attribute, which sits behind an experimental feature flag for both Chrome and FF. The inert subtree work is ongoing, and notably, inert support is not showing as a release blocker. Yes, it'll be great to have, but it's far from mandatory.

The significant outstanding blocker for FF is re. focus twiddling for better a11y, per recent discussion at whatwg/html#5678, c.f. bugzilla#1660271 & #1701230, and this is hardly boiling-the-oceans stuff.

I'm excited for <dialog>, it's a survivor, and a great simplifier - particularly of dev conversations - and I recommend it (even with interim polyfill) to all and sundry.


Ah, yes indeed! Firefox nightly has native support for <dialog> now...



And similarly that library might as well reuse the standardized APIs of "<menu>" and "<dialog>" where possible. Then eventually, you might not need any library and there will be no code change required.


The <menu> element is unfortunately deprecated[0]

I would avoid using it.

[0]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/me...


No, the context menu variant (<menu type="context">) is deprecated. Hence, why the deprecation note is on the example of that variant, not on the element

of course, much of the rest is experimental and unimplemented.


But, unlike <details>, is not Javascript-free.


This is true. On the other hand, <details> for menus and dialogs is a stretch, semantically. And <dialog> natively supports ESC to close/cancel.


> On the other hand, <details> for menus and dialogs is a stretch, semantically.

Not really, for either menus or non-modal dialogs:

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

https://html.spec.whatwg.org/multipage/interactive-elements....


Sure, but this is at the cost of requiring Javascript (on non-supported browsers) just to display some links to navigate your website. Maybe you could use `<script>` and `<noscript>` to better extend support... [1]

[1] https://www.w3schools.com/TAGs/tag_noscript.asp


It is actually possible to style a <dialog> with a pure CSS fallback for reveal, e.g such that it also appears via :focus-within activated using a <label> that targets a nested but invisible input, which is feasible even if JS is disabled or locally malfunctioning. I’ve made this construction work but it is obviously a hack, and rather page-specific so we didn’t turn it into a library component. The result also had accessibility issues, which we did fix with JS, rationalised on the basis that ARIA by definition means JS availability.

Personally I’d rather that the toggle was available as an activation behaviour, and this is an open issue for the HTML standard. https://github.com/whatwg/html/issues/3567


For the note, in Sciter (https://sciter.com) these (JS):

    Window.this.modal(<info>Hello world</info>);
    Window.this.modal(<alert>Hello world</alert>);
    let r = Window.this.modal(<question>Hello world</question>);
will create real modal dialogs (as separate desktop windows).


I saw several posts about using `<details>` in this way, but none that fully implemented what I was looking for. So I implemented a site navbar that uses `<details>` in two ways: for dropdowns, and for a sidebar.

A working reference implementation can be found here [1]. Additionally, I ended up using a version of this on my personal site [2]. This works on stable versions of Chrome, Edge, Firefox, and Safari.

One thing to be careful of when using `<details>` in interesting ways: accessibility. At a minimum, I encourage folks to make sure that screen readers work as expected.

[1] https://codepen.io/devadvance/pen/bGBvvWv

[2] https://github.com/devadvance/devadvance.github.io/blob/mast...


Vertical scroll doesn’t work on Firefox Daylight 33 iPhone. So I open the menu and the the submenu and I can’t see the rest of the menu


If longer menus are needed, it might be necessary to manually set `overflow: scroll` and hide the scrollbar.


The internet is mainly being used for web apps instead of documents for a while now. Why can’t browser vendors reflect this and provide all those Interfaxe prototypes we need out of the box? Why do we have five bazillion modal libraries instead of a native one? Is there really any value in pretending the web revolves around documents when it had been revolving almost exclusively around apps for quite a while now?


Because HTML elements are forever while js modal libraries change yearly. It’s best for browsers to wait a few years and if there is one thing that has consistently been used and will be forever, then add it. The details element is a good example.

And even when we have an element, most devs end up replacing it with a JS version anyway. The HTML select element is a good example. The built in one almost always gets replaced with something that looks nicer and has more features like icon support and themeability


> Because HTML elements are forever while js modal libraries change yearly. It’s best for browsers to wait a few years and if there is one thing that has consistently been used and will be forever, then add it. The details element is a good example.

While I agree all these API need to be carefully crafted, this one is very much a no brainer. Mozilla (and Apple) should be at the forefront of these native UI improvements, because it allows the developer to rely on standard behavior rather than rolling out one's own broken UX.

> And even when we have an element, most devs end up replacing it with a JS version anyway.

No they don't.

> The HTML select element is a good example

Yes, because it's almost impossible to style it or make it display some custom content that isn't a line of text. The problem isn't its existence, it's its shortcomings because it was basically speced 25 years ago. I'll take a standard widget that I know will work in an expected fashion across many devices rather than someone's personal library in GitHub that is broken in subtle ways. That's the idea behind standards.

I was on a site not long ago, which displayed a modal pop up, well the page was going up and down frenetically every half second because the developer probably used a library that wasn't tested on the browser I used. the UX was completely broken. With standards, if a polyfill is broken then you have a good argument to confront its developer with (if I can put it that way).


>it was basically speced 25 years ago

How do we fix it though? It clearly needs major changes and improvements, but those can't be made without breaking compatibility. Do we add a select2 element? modern-select?


I'd plump for dropdown, if there really needs to be a new element. Not sure why options elements couldn't accept more attributes, they're easily ignored and don't affect the DOM tree. What's wrong with an icon attribute, for example, that points to an image?

I don't know, but looking at the timeline for other features to be implemented that virtually (if not literally) every web dev has cried out for since year dot like vertical align and grid, I'm putting my money on a new select element around 2035.


> The built in one almost always gets replaced with something that looks nicer and has more features like icon support and themeability

Then why don’t we improve the capabilities of the built in one?

I’ve always found this odd, JavaScript and CSS are constantly improving, and there’s a steady stream of new things to make development easier. But no-one seems to care about improving HTML, despite being by far the best focus of efforts.

Rich functionality via new/improved HTML tags would be accessible, performant, would work without JavaScript, and in many cases could be easily polyfilled.


I’ve taken to using <details> in markdown docs on github to make them more concise to read.


Recommended: take a look at how hey.com uses <details>/<summary> with <a> to enable dynamic drop-down menus and progressive enhancement via Hotwire, it’s inspiringly simple and elegant.

I’ve also used them for modals and slideovers. Use in conjunction with an [open] selector and adjacency combinators for maximum utility.

See also: <dialog>, already in Chrome, and for which Firefox’s support is looking good in nightly builds; and the :focus-within pseudo-class.

From the department of “You might not need (much) JavaScript”, which has come a long way from checkbox hacks.


As discussed in the podcast ShopTalk Show[0], of which Chris Coyer is a host. this is actually a more complex idea than this article let’s on, a corollary article from the co-host of that show, Dave Rupert, on why it’s a difficult idea and maybe not the best thing to do[1]

To quote the article:

>tl;dr - <summary> is a button and buttons eat semantics

[0]: https://shoptalkshow.com

[1]: https://daverupert.com/2019/12/why-details-is-not-an-accordi...


Now I'm very curious why <summary> is a button. Off to read more.

That second link is great, and this sentence caught my attention: "At the risk of being a broken record; HTML really needs <accordion> , <tabs>, <dialog>, <dropdown>, and <tooltip> elements." At first glance, that sure would simplify a lot of the work I've done in the past.


> Now I'm very curious why <summary> is a button.

I’m fairly certain it’s a shadow DOM implementation detail. While it technically toggles a binary state and is probably more semantically similar to a checkbox, I think the way it’s exposed to web APIs makes that either impractical or non-obvious.


"Toggle buttons" are a thing in ARIA: https://developer.mozilla.org/en-US/docs/Web/Accessibility/A...

Conceptually the summary is a toggle button: you click it to toggle the display state of the details element.


That’s true and what I assumed of summary. Although toggle buttons are fairly useless in plain HTML without JS, which is why checkbox is the more obvious semantic analogue outside the shadow DOM.


those, and some additional form elements/implementing the spec for existing ones (e.g. range) more fully would be great. There's a lot of widgets that get built over and over again that could really benefit from being in the browser (especially for accessibility's sake)


Came here to mention this too. It’s even worse than the tl;dr, if I recall correctly those semantics can’t be reinstated with more semantics.

There are some other cases where certain newer features like display: contents also hide content from assistive tools. I’m pretty sure some of these are being worked on, but don’t have great recall of whether that includes details/summary.


In WebKit, <details> was one of the first test-bed for (then non-exist) Web Components infrastructure. Before that, it directly manipulated the internal rendering tree, which is often error prone. Using higher-level primitive (Web Components) felt like a no-brainer but turned out to be a very tricky, took much longer to fresh it out. Because, after all, there was no such thing like Web Components!

Apparently this element is still implemented in Shadow-DOMy way [1]. So the effort was worth something after all, I guess.

[1] https://github.com/WebKit/WebKit/blob/main/Source/WebCore/ht...


I've used details for optional or dynamic html forms, as they gracefully degrade even for mobile browsers from the pre iphone era that can't use JS. They work pretty well.


Does anyone else notice that many 'hamburger menus' don't work when JS is disabled? It would be considerate to use the <details> element to make a hamburger menu work with JS disabled, for that dynamic effect. Note: I surf the web with JS disabled by default, and only run JS on sites I trust (i.e not Youtube who are known to fingerprint you with webgl)


I'm not sure how much <details> can be customized, but there's also a CSS-only route using a hidden checkbox beneath the hamburger icon and looking for the input[type="checkbox"]:checked selector. (Example: https://codepen.io/plavookac/pen/qomrMw)


you could also use the checkbox trick to make this work without javascript before <details> (and in e.g. ie11). Although <details> is amazingly widely supported, weirdly I had never heard of it until very recently.


One important caveat with using `details` is that browsers will render an icon (generally rendered as a triangle) to indicate the collapsed/expanded state on the `summary` element. There's no reliable cross-browser way to get rid of this icon.

I recently implemented a design comp with plain HTML/CSS that had several expandable sections and dialogs and for some of them `summary` was a good choice but other times a combination of `:hover`, `:focus` and `:focus-within` (while making sure to only hide the content visually because these interactions don't play well with screenreaders) ended up being a better choice.

When considering the options, keep in mind that although "JS interactions are inaccessible" is widely held as common knowledge, it's not an absolute truth and neither is the inverse "non-JS interactions are never inaccessible". It's important to understand the accessibility implications of what you're doing. With JS this means you may have to do additional things (e.g. dynamically setting ARIA attributes), without CSS this means you have to avoid doing certain things altogether (e.g. toggling `display: none` to hide content).


I use this technique for the hamburger and cog icon menus in Datasette, eg on this page: https://datasette-graphql-demo.datasette.io/github/users


Which one is better for accessible menus: <details> or using a checkbox hack? I assume both require some aria attributes to mark that the element is a menu.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: