Skip to main content
Ben Nadel at the New York ColdFusion User Group (Mar. 2008) with: Pete Freitag
Ben Nadel at the New York ColdFusion User Group (Mar. 2008) with: Pete Freitag

Linking To A Disclosure (Details) Element

By
Published in ,

In my Big Sexy Poems ColdFusion application, I have several <textarea> elements whose content can support Markdown syntax. Below the textarea, I have a link to a <details> disclosure element that outlines the supported Markdown syntax. Ideally, I'd like said link to both take the user down to the disclosure element and to auto-expand the details. Getting this to work took a little trial-and-error.

Run this demo in my JavaScript Demos project on GitHub.

View this code in my JavaScript Demos project on GitHub.

The Ancestor Revealing Algorithm

In the HTML Standard, the "ancestor revealing algorithm" will try to automatically expose a target element. It does this by locating the target (the element being linked to), and then walks up the node tree looking for hidden elements. Depending on how the element is hidden, the browser attempts to expose it, bring the target element into view.

To auto-expand a <details> element, I could link to the contents of the disclosure. Since they are hidden by default, the browser will use the ancestor revealing algorithm to add the [open] attribute to the details.

I tested this in all the major browsers and it works like a charm. No JavaScript needed. It also works on both the initial page load and subsequent hash-changes.

But, it doesn't feel right. It feels like I'm dumping the user into the middle of content without context. Plus, without additional scroll-margin-block-start CSS, the <summary> of the disclosure widget will likely be scrolled beyond the viewport boundary.

It feels like linking to the content of the disclosure element is a hacky way to get what I want without JavaScript.

Linking To the Summary Element

Ideally, I'd like to link the user to the <summary> element. This element identifies the topic of the <details>; and is actionable. Meaning, once focused, the user can hit the Enter key or Space key to toggle the expansion of the disclosure component.

Aside: the browser doesn't appear to treat the <summary> element as worthy of the focus outline. As such, I had to add some explicit :focus-visible styles to the summary CSS in order to give it an outline-style: solid. Otherwise, linking to the summary element had no visual feedback of focus state.

Since the <summary> element is visible, the browser's "ancestor revealing algorithm" doesn't come into play. In order to auto-expand the content of the <details>, I'm going to watch for the hashchange event; and, if the hash points to a <summary> element, I'm going to ensure that the parent disclosure is opened.

In the following demo, I have three disclosures with a lot of inter-element margin. I added the margin to make sure that the scrolling was working as intended. At the top of the page, I have three links, each of which links down to one of the <summary> elements.

<!doctype html>
<html lang="en">
<body>

	<h1>
		Linking To A Disclosure (Details) Element
	</h1>

	<!--
		Note: I'm linking to the SUMMARY element, not to the details element, since only
		the summary element is actionable: it acts as the toggle for the details control
		and can be triggered with Space key or Enter key. It also provides labeling and
		context to accessibility software.
	-->
	<ul>
		<li>
			<a href="#summary1">Markdown Syntax</a>
		</li>
		<li>
			<a href="#summary2">Keyboard Shortcuts</a>
		</li>
		<li>
			<a href="#summary3">Privacy Policy</a>
		</li>
	</ul>

	<details name="demo">
		<summary id="summary1">
			Markdown Syntax
		</summary>
		<section aria-labeledby="summary1">
			You can use limited Markdown syntax in your content.
		</section>
	</details>

	<details name="demo">
		<summary id="summary2">
			Keyboard Shortcuts
		</summary>
		<section aria-labeledby="summary2">
			You can use the following keyboard shortcuts in the application.
		</section>
	</details>

	<details name="demo">
		<summary id="summary3">
			Privacy Policy
		</summary>
		<section aria-labeledby="summary3">
			All your data is belong to us!
		</section>
	</details>

	<script type="text/javascript">

		// When the page first loads, or whenever the location hash changes, check to see
		// if the hash points to a disclosure summary. If so, ensure that the disclosure
		// is open. The browser will handle the focus automatically (via the hash).
		window.addEventListener( "load", applyHashEventToSummary );
		window.addEventListener( "hashchange", applyHashEventToSummary );

		// Expand details is the summary is the target of the hash.
		function applyHashEventToSummary( event ) {

			// The ":target" pseudo selector matches the element linked-to via the hash.
			var summary = document.querySelector( ":target:is(summary)" );
			var details = summary?.parentElement;

			if ( details && ! details.open ) {

				details.open = true;

			}

		}

	</script>

</body>
</html>

In essence, this code is implementing its own "ancestor revealing algorithm". When I see that the current :target is the <summary>, I walk up the node tree looking for the <details>; and once found, I ensure that the open attribute is applied.

I've added aria-labeledby attributes to the content of the disclosure, pointing back to the <summary> element. I don't know that these attributes are needed; especially since the <details> control doesn't require a child element to work. But, the accessibility tree in Chrome Dev Tools seemed to have no context (by default) when inspecting the <section>.

I still have to go back and fix this in my Big Sexy Poems project. But, I think this creates a decent user experience (UX). I get to have the focus outline of the summary, which gives the user strong feedback about where they are within the document; and, I get to automatically expose the contents of the <details> control.

Want to use code from this post? Check out the license.

Reader Comments

Post A Comment — I'd Love To Hear From You!

Post a Comment

I believe in love. I believe in compassion. I believe in human rights. I believe that we can afford to give more of these gifts to the world around us because it costs us nothing to be decent and kind and understanding. And, I want you to know that when you land on this site, you are accepted for who you are, no matter how you identify, what truths you live, or whatever kind of goofy shit makes you feel alive! Rock on with your bad self!
Ben Nadel
Managed hosting services provided by:
xByte Cloud Logo