In HTML there are three list elements that are considered
semantic :- Unordered list (
<ul>
) - Ordered list (
<ol>
) - Description list (
<dl>
)
Browsers apply a default user agent style to modify the appearance of these elements. This is
where a problem presents itself – we have a list of items but the default browser list styles
are not wanted.
Using plain <div>
tags would get us the right style, but shouldn’t a semantic list element be
used instead?
To be able to use the sematic list element a new component or class would be need to be created
to conditionally undo the browser styles. That’s a bit of a pain.
To add to the effort, in this case the need for an unstyled list is turning out to be a common
global pattern, so the new styles would need to be part of the central design system.
Is it really worth all the effort of a new design system release? There’s not even any visible list
styles! Aren't we just being pedantic about semantics?
A list should be a list
Writing semantic HTML involves structuring the web
page using elements that convey meaning.
The meaning is separate from the appearance, content or functionality of the element, but it does
inform both human and machine of what the element is for.
We could write the list as:
<div>Content</div>
<div>More content</div>
<div>Even more content</div>
That would get us roughly the appearance of what we want - an unstyled single column of elements sat
on top of eachother.
The <div>
s share no semantic meaning at all so the only thing that could make this a list is a human
interpretation of either the content placed inside them or their appearance on the webpage.
Here’s the same thing using semantic list markup:
<ul>
<li>Content</li>
<li>More content</li>
<li>Even more content</li>
</ul>
Regardless of the content or appearance meaning can be gathered from this.
<ul>
- it’s an unordered list, we want the contents to be grouped as one list but it doesn’t matter what order the items display in.<li>
- a list item, the contents of this element represents one item within a list of items.
You might think calling it a ul
and li
is stupid, but it doesn’t really matter because semantics
is more than opinions or naming, it’s about there being a non-subjective shared meaning.
In HTML the meaning is openly documented through a specification
that browsers aim to consistently adhere to across every HTML page. So we don’t have to invent or
document ways to structure all these elements between projects, it’s already sorted.
The hidden benefits of semantics
Okay, we’ve called a list a list, but only developers and machines will see this, nobody else will
care, it still feels like we’re being a bit pedantic.
As we’ve already spoken about semantics isn't about the final output, but the shared meaning does
inform both human and machine what the output should be (a list).
For example, screen readers and other assistive technologies read the semantic meaning of elements out loud to
describe the content to users.
Here's a video showing the two implementations of the list from earlier being read out by Mac Voiceover.
As expected, the semantic <ul>
element gets read out as a list:
- “List with 3 items”
- “Content 1 of 3”
- “More content 2 of 3”
- “Even more content”
The contents of the <div>
s on the other hand are read out with no grouping or indication of what the
items are meant to be part of.
Assistive technologies are just one example that leans on the consistent application of semantic
HTML elements – any tech that crawls web pages like search engines rely on semantics to accurately
read the content, browser user agent styles rely on them to apply default styles that make the webpage
readable and functional in the absence of CSS or JS.
We can’t be sure how all these technologies will make use of the semantic elements in the future.
What we can be sure about is that if we don’t use the semantic elements then no intended meaning
will be shared to benefit end users.
Applying semantics within a design system
Hopefully by now we’re convinced that semantics are important, so let’s go right back to how to
approach the original problem – it should be clear that we should not just form this list using
plain <div>
elements.
Something not mentioned yet that might be tempting here is the availability of
ARIA role
attribute which would at least get
us similar accessibility benefits to the semantic list.
<div role="list">
<div role="listitem">Item 1</div>
<div role="listitem">Item 2</div>
<div role="listitem">Item 3</div>
</div>
This would be against the first rule of ARIA
and for good reason – remember there’s three different semantic list elements in HTML? This role only
covers one with no user agent styles.
In the MDN documentation
for this role it states:
Only use `role="list"` and `role="listitem"` if you have to — for example if **you don’t have control over your HTML** but are able to improve accessibility dynamically after the fact with JavaScript.
The point is this: as design system authors, we should do everything in our power to avoid
restricting consumers on their use of semantic HTML elements.
Getting into implementations, that might look like this with
“HTML web components”
which wraps around the semantic markup:
<ds-list list-style="none">
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
</ds-list>
Or in Angular which supports component attribute selectors:
<ul ds-list list-style="none">
<li ds-list-item>Item 1</li>
<li ds-list-item>Item 2</li>
<li ds-list-item>Item 3</li>
</ul>
Or using as
props in JSX based frameworks like React, in this case it’s important to also spread
the props onto the underlying element to make sure all the HTML attributes are supported:
<list as="ul" liststyle="none">
<list.item as="li">Item 1</list.item>
<list.item as="li">Item 2</list.item>
<list.item as="li">Item 3</list.item>
</list>
No matter the implementation, it should be our responsibility not to hide away or restrict use of
semantic HTML elements and provide guidance within the design system documentation to advise on
how to use them.
Moving beyond utilities
As we’ve seen HTML gives us so much hidden power for free by relying on the shared meaning of
semantics causing a consistent application of the right elements in the right places. Semantics
are important!
We could stop where we our with the now semantic list component, most generic lists could use it
and it’d be a good improvement.
But a design system should create and document a shared meaning around specific entities within the
problem space. We can take HTMLs lead when considering custom design system components – if all we
had in the design system were utility components it would be a bit like using <div>
elements
everywhere in HTML.
For example, if we take this imaginary list scenario and consider it from a semantic point of view,
we might notice our product(s) include this list when the content is a reciept like price breakdown
in carts and payment checkout flows.
In this case a more semantic implementation could look like:
<price-breakdown>
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
</price-breakdown>
Suddenly, this begins to form more meaning, it’s not just a list, it’s a price breakdown list and
in turn that informs the output “this is how price breakdowns look and behave in our product”.
In the same way as semantic HTML, the price breakdown components output is detached from the meaning
which leads us to hidden benefits such as the ability for the appearance or functionality of price
breakdowns to be targeted and then used, adapted or improved globally over time without having to
edit every instance.
This shows the power of using semantics to inform our decisions around building and using design
system components. All through considering semantics we’ve gone from a meaningless unstyled set of
elements and ended up with a future-proof and accessible semantic design system component.