Understanding and developing for your users

DOMinate your accessibility

How element placement in the DOM impacts the user experience

Eric Olkowski
PatternFly

--

Co-author: Jessie Huff

HTML structure in the browser’s dev tools
Photo by Pankaj Patel on Unsplash
PatternFly’s branded divider, our logo centered between two lighter lines.

Empathy will almost always get you further in any endeavor, and user experience is no different. Understanding how our users interact with our software and what tools they’re using gives us insight into how to better help them. Some of us are accustomed to looking at a site, scanning through the headings, scrolling to the portion that we want, and clicking to interact with elements on the page.

If I have a motor impairment, I might use a keyboard to interact with a page to get to that element instead of a mouse. I might tab through the page or use hotkeys to quickly get the information I need. I might even be the type of user that goes back and forth between tools depending on my needs. Or if I’m a blind user, I might use a screen reader to help me navigate a page. I might use screen reader menus to quickly get the main categories on the page like headings, landmarks, form controls, or links. (However, it’s important to note that there are tons of types of users that fit these categories, across categories, and other categories that we won’t mention.) So when we’re considering these experiences, we have to understand how these tools interact with a website.

Structuring accessibility

The almighty DOM, Document Object Model, is incredibly important when it comes to assistive technology. Both keyboard and screen reader will rely on the DOM to navigate and interpret what is happening on a page. It translates the content of an HTML document into a standardized object that functional programming languages like JavaScript can easily access and modify. All dynamic web pages rely on the DOM to display and function properly.

An illustration of the Document Object Model (DOM) hierarchy
The Document Object Model from Wikipedia

Every web page has a structure which you can see by using the inspector tool:

The DOM structure in Chrome’s dev tools for PatternFly.org
PatternFly’s homepage and structure

The DOM or structure is what will be used by assistive technologies to interpret what is happening on the page. Assistive technologies like screen readers will go through the DOM and try to interpret the elements being used, the order of these elements, and what these elements are expected to do.

Let’s say that we have a UI where you can add content — maybe even blogs like this one! On that page, we have a floating “add” button so that users can easily add content wherever they are on the page. Well, that seems like a cool concept, right?

A floating action button in the bottom right corner of an app
A floating action button example from Dribbble

Now let’s say I’m a keyboard or screen reader user. I got to this page, I’m ready to add my voice to the conversation, and I’m looking for the add button. How the developer marked up this code in the DOM will affect everything. A lot of developers will render the button at the bottom of the DOM and just visually re-position the element to look like it’s floating and following you as you scroll the page. However, it’s still at the bottom of the DOM the entire time.

So as a keyboard or screen reader user, I’m navigating through the page, and weirdly enough I can’t find the add button. I’m seeing links to blog post after blog post on the main page, but no place where I can add my own blog post. I start to wonder if this site doesn’t actually let users post their content and if their advertisement was wrong. It’s been a few minutes of going through the page, and I’m already feeling annoyed.

Ah, at last, I’ve finally found the add button. Why on earth did they put the add button at the very bottom of the page? Did they really want to drive me crazy and make me work so hard just to contribute? The honest answer is that the team probably had zero idea of how difficult they just made their UI for a good percentage of users. They probably saw the floating button and thought, “wow, that looks cool” and never genuinely sat down and thought through these different types of experiences.

We see the world through our own lens, sometimes making it difficult to realize that someone else’s lens might be totally different. It’s not easy to think through every experience, but we certainly should try to learn about different users and their experiences. Otherwise, we might miss out on helping our awesome customers, not to mention we have the ability to make their lives a lot harder if we don’t. So when another designer comes to you with a super cool, new, spiffy idea, stop and think through how different types of users would interact with it. If you’re going to have an “add” button on your page, where in the flow does it make the most sense for users to discover it? If you’re a developer, ask the designer questions about these different user interactions. Everyone should be on the same page when it comes to expected interactions.

Now that we understand a little bit more about different types of user experiences and how important the order of your elements can be, let’s discuss more of the nitty-gritty technical details.

PatternFly’s approaches to appending to the DOM

When using a design system like PatternFly, the possibilities are nearly endless in terms of the interactions you can create. Some of those possibilities can be more advantageous than others, and some can create unexpected issues for users. That’s why it’s important to consider the implications of your approach to these interactions.

Before going over PatternFly’s approaches, let’s first get a little background about the menuAppendTo React property used in several PatternFly components. While what actually gets appended may depend on the component — on a dropdown only an opened dropdown menu will get appended rather than the toggle, while an entire modal would get appended — the property essentially does the same thing: it appends the component to the specified container in the DOM.

With the menuAppendTo property, there is room for flexibility in order to append a component anywhere in the DOM, but it all boils down to two basic appending types: an “unnatural” DOM order and a more natural DOM order.

An “unnatural” DOM order

An unnatural DOM order refers to when an element’s place in the DOM doesn’t match its visual or expected tab order. The most common example of this is appending some dynamically rendered content to the document body. Some PatternFly components that can often be appended to the document body are dropdown-like components such as dropdown or select, tooltips, and modals, just to name a few.

Appending things in a more unnatural DOM order can certainly have its place. When rendering a modal, appending to the document body can make sense since it should be the only thing that can receive focus or be interacted with by users, so the usual downside to an unnatural DOM order may not necessarily apply. A component like a tooltip could be another case where an unnatural DOM order makes sense since the contents of the tooltip itself won’t ever receive focus (though should still be conveyed to users of assistive technologies such as screen readers). Similarly, toast alerts that visually “pop up” on the upper-right corner of the page could be appended “unnaturally” if there is no interactive content inside the alerts, such as links to more information or buttons to dismiss the alert.

When you start having more complex nesting of components, such as a dropdown inside of a wizard inside of a modal, appending the dropdown to the document body or the modal might even help ensure the dropdown menu appears above all other content rather than being covered up and cut off by anything.

Two instances of a dropdown inside a wizard inside a modal, showcasing two different methods of appending to the DOM
Left: a dropdown with a default “menuAppendTo” React prop, cut off by other content. Right: a dropdown appended to the document body, visually above other content.

Despite there being use-cases for it, one downside to this approach is it can make things less accessible for users who navigate and interact via keyboard or assistive technologies.

If a dropdown toggle is rendered in the middle of the DOM, while the dropdown menu is appended to the document body, the expected tab order and the actual tab order won’t match up. Depending on how many other focusable elements there are between the toggle and the menu in the DOM, instead of pressing the Tab key once to enter the dropdown menu, you may need to press it an unknown number of times, navigating through the entire rest of the page before finally having focus placed inside of the dropdown menu.

Likewise, if you close a dropdown menu via the Escape key, you might expect that pressing Tab would place focus on the next focusable element following the dropdown toggle. What actually receives focus is the next valid element from where the dropdown menu was appended at the end of the document body. If there are no other focusable elements, then you would end up tabbing to the top of the browser window.

Another downside to this approach is that it can require the consumer to implement focus management to avoid those issues, assuming the component doesn’t handle it for you (which won’t be immediately apparent).

Why a component may not handle focus management

Some components have very straightforward use cases and interactions. A button for example will typically just be something you click on and something happens in response to that click.

Other components, however, may not be as straightforward, and the use cases may differ wildly depending on who is using it and the context in which it’s being used. While implementing focus management, or some other functionality, within the component itself may be helpful for one person’s use case, it could cause issues or be an unwanted experience for someone else’s use case.

A more natural DOM order

By appending components in the DOM in a way that better matches their visual or expected tab order, you can completely avoid some of the issues when appending in a more unnatural DOM order.

Using our dropdown scenario from the previous section, if a dropdown menu is visually “after” a dropdown toggle and the menu should receive focus immediately after the toggle, then the menu should be appended so that it comes after the toggle in the DOM, or as close to it as possible. The main takeaway with this approach is to avoid having unrelated and perceivable elements between two related elements that should receive focus after or before the other.

One downside to this approach is that there may still be some focus management to be implemented by the consumer or the component itself, mainly ensuring that any element that triggered content to dynamically render will receive focus after that content is no longer visible. However, this is focus management that would need to be implemented regardless of where you append a component.

The upside to this approach — other than improving accessibility — is that you don’t have to worry about implementing much more focus management since it should be taken care of by the DOM order. You also don’t have to figure out whether the component handles that functionality for you, or whether it only partially handles it for your use case.

PatternFly’s recommendation for menuAppendTo

The following recommendation is based on v4 of PatternFly. However, with more composable components being introduced in the upcoming v5 in 2023, some of which still retain the menuAppendTo functionality, the recommendation would still apply.

For most situations, PatternFly recommends the natural DOM order approach. For several components this can be achieved by passing in a “menuAppendTo” React prop with a value of “parent”. For finer control over where content is appended, you can also pass in a function that returns a query selector, though you should still append as close to a natural DOM order as possible when doing so.

For situations where a natural DOM order isn’t as important — such as modals — or where trying to deal with the z-index or stacking context isn’t easily manageable — such as complex nesting of components — the unnatural DOM order approach can certainly be more useful. This approach can be achieved by passing in a function that returns “document.body” or a query selector to the “menuAppendTo” React prop. Ideally this should be a last resort, though, especially if it makes more sense to append an item in a more specific place in the DOM.

Much like accessibility itself, there may not always be a single solution that works for every single situation and resolves every problem for everyone. PatternFly’s recommendation may not always be the best choice for your specific situation, but it’s important to understand the implications of whichever approach you take.

PatternFly’s branded divider, our logo centered between two lighter lines.

Have a story of your own? Write with us! Our community thrives on diverse voices — let’s hear yours.

--

--