Design-systems are a Carnival! One accessible component Many pretty masks | Kathleen McMahon @resource11

Welcome everyone! I’m Kathleen McMahon and I’m here today to talk about a Design System Carnival! One accessible component, many pretty masks. Before we begin, let’s get some details out of the way.

https://noti.st/resource11

My presentation will be posted on Notist, that’s https://noti.st/resource11 — including links to resources — after my talk. I’ll also post the full URL on Twitter after my presentation.

@resource11 Twitter | Instagram | GitHub

You can follow me at resource11 on Twitter, Instagram, and GitHub.

Who are you, again?

Let’s back up so I can introduce myself better…

Kathleen McMahon | Engineer • Designer • Speaker

So I’m an engineer and a designer and I like to speak about things…

image: Me on a cyclocross bike, in Spam, Ninja Turtle, Nerds candy box, Medusa costumes

Occasional cyclocross racer. In costume, of course.

image: a wide-screen view of the colorful lamps and lighting strips adorning my home office desk and bookcases

Lover of lights

image: A wide-planked boardwalk — with soft sand and sea grass surrounding its weathered wooden railing — leads toward the calm ocean during a cloudy afternoon low tide

Beach goer.

image: A montage of sand dollars of various sizes and colors, next to a tiny and medium sand dollar in the palm of my hand.

Sand dollar collector

image: Thor, resting on the windowsill of my kitchen window, enjoying the warm summer breeze and sunshine on his soft beige fur and dreamy blue eyes.

Lover of my cats Thor

image: Otis — my silky black haus panther — nestled between my purple bed pillows, gazing at me with calm golden eyes.

…and Otis.

image: A gathering of green aventurine, sodalite, rose quarts towers, and quarts diamond on the kitchen table

I’m a Crystal collector

image: Otis, the black wonder cat, steps into the frame of my crystal collection

And I try to get good photos but Otis…

image: Otis' paws walk through my crystal arrangement on the kitchen table

…interferes often

image: grouping of citrine, amethyst, and celestite glowing in the sun-washed windowsill

…and has…

image: Otis — sassy black cat — sits exactly on top of all my windowsill crystals, seeking attention.

…none of it. Thanks, Otis

image: In pure art director fashion, Thor sits distinctly on one windowsill sand dollar. Ready to provide his ultimate design judgement..

Thor does the same…

image: Thor looks up from the windowsill to the camera with a very satisfied look. His blue eyes gaze hypnotically my way as his pink nose points upward, whiskers pridefully twitching.

He looks pretty satisfied.

image: Otis looking very cute as he lays upside down on my bed, gazing at me.

Who could resist them, though?

Northwestern Mutual

I’m also a Senior Design Systems Engineer at Northwestern Mutual, working on the Luna Design System. I love my team; they are pretty rad.

Design Systems are ALWAYS the hotness image: Person in inflatable dinosaur costume flips into a raft floating on a pond and claps with glee.

I love design systems; it’s exciting! Especially if you like…

image: Woman attempting to arrange 10 squirming kittens in a straight line, with varied success

…herding kittens. Always fun, lots of moving parts.

Design-systems are a Carnival!

I think Design Systems are like a Carnival! What do I mean by that?

image: Mannequin wearing Bauta mask adorned with navy Tabarro

Well… I visited Venice last fall and was fascinated by the masks. I loved their beauty…

image: Mannequin wearing plague doctor mask in muted purple costume

their variety…

image: A crowd of Jester masks hanging in a Venetian vendor's market

And… they’re everywhere.

image: Rows of brightly-colored porcelain masks handing on a Venetian market wall

Everywhere you look in Venice.

image: A group of very elaborate and detailed bespoke masquerade art pieces in a Venetian gallery

In the shops.

image: Four tiny jester mask magnets hanging in a Venetian shop doorway

…the souvenirs.

image: a white red and orange painted paper mache mask with ribbon ties on a paint-spattered newspapered table

I even made my own mask

image: a person wearing a Jester mask smiling

And I learned the masks have a rich history of providing access. And helping a person blend in…

image: A gathering of people in 18th century costume dancing at the Giacoma Casanova Carnival

…to hide their gender, identity, social class…

image: man walking through a corridor wearing a Baùta and Tabarro

Some of the well-known masks are the Bauta… This mask was great because it had this big jaw so you could go eat and drink and do the things you want to do and not be noticed.

image: red-haired woman wearing a small oval mask, made of Velvet, which is held with the mouth thanks to a button.

There’s the Moretta…

image: man and woman in 18th-century costume wearing cat masks

The Gagna… meow!

image: A man in a Harlequin mask surrounded by two surprised woman and an amused man in 19th-century clothing

The Harlequin..

image: Venetians row during the Carnival masquerade parade on the Venetian Grand Canal.

…and wearing these masks gave you access to places with more freedom — like this parade of gondolas during Venice’s Carnival Similar to a design system. When well-crafted, masks create consistency of experience.

Is it consistent for everyone?

So, is the experience consistent for everyone though? Let’s talk Accessibility.

Our users have different needs at different times

Vision Sensory Hearing Language Motor Cognitive Low bandwidth

From vision hearing, motor skills, cognitive, sensory, language needs, bandwidth, speed, and more. Our users have so many needs, and so often, accessibility is what is handled last. We don’t want to leave our users behind

Why accessible components?

Now what does this mean in terms of accessible design system components?

February 2023 — WebAIM Million — An accessibility analysis of the top 1,000,000 home pages

Well, there is this report called the WebAIM Million report and it’s been released for the past five years now. If you’ve read the results, they’re a bit concerning. It’s an accessibility analysis of the top 1000 homepages. And I’m going to focus on the amount of ARIA present on the homepage.

February 2019 — 60.1% of the 1 million pages had ARIA present

There has been up to a 29% increase the past year, and the amount of ARIA attributes has nearly quadrupled since 2019. So that means that our developers are making the web worse in the spirit of best intentions.

February 2020 — 64.6% of the 1 million pages had ARIA present

There has been up to a 29% increase the past year, and the amount of ARIA attributes has nearly quadrupled since 2019. So that means that our developers are making the web worse in the spirit of best intentions.

February 2021 — 68.1% of the 1 million pages had ARIA present

There has been up to a 29% increase the past year, and the amount of ARIA attributes has nearly quadrupled since 2019. So that means that our developers are making the web worse in the spirit of best intentions.

February 2022 — 74.6% of the 1 million pages had ARIA present

There has been up to a 29% increase the past year, and the amount of ARIA attributes has nearly quadrupled since 2019. So that means that our developers are making the web worse in the spirit of best intentions.

February 2023 — 80% of the 1 million pages had ARIA present

There has been up to a 29% increase the past year, and the amount of ARIA attributes has nearly quadrupled since 2019. So that means that our developers are making the web worse in the spirit of best intentions.

What can we do about this?

So what can we do about this?

This is the W3C’s Web Accessibility Initiative page, and it has some fantastic guidelines for us to follow. Especially for ARIA authoring practices, design patterns, and examples.

image: thumbnails of "accessibility-flavored react components make your design system delicious" talk

Now, I generally with all my talks will give you examples and how-tos on how to make a component accessible, This is not that type of talk. However. I will be providing code examples and resources at the end of the talk. So don’t worry, you will not miss anything. I will have the code examples. I will have the notes. And I always provide notes with my deck so you can sit back, relax, and enjoy the storytelling instead… and the masks.

Disclosure widget

We have this one pattern in a design system that is the basis for things like popups, toggleTips, toggleSearch, and you can see them used in things like a terms of service widget.

One pattern, a few uses

This one pattern has a few uses, and if it’s built correctly, it can have a few uses in your design system. It’s called the Disclosure Widget.

Anatomy of a disclosure widget

The anatomy of a disclosure widget is…

A button that opens & closes a container, then returns focus to the button

A button that opens and closes a container And returns focus to the button.

image: WAI site card view of various design patterns, highlighting the disclosure pattern

And the WAI site has a documented pattern for this basic disclosure widget

Primary keyboard interactions | Space bar/Enter key Escape key Mouse clicks

This pattern has three primary keyboard interactions: • Space bar/Enter key — which comes natively when you use a button to open the disclosure — • Mouse clicks, and • And the ESC key, which is part of the extended disclosure pattern

<button />

So when you build a disclosure pattern you begin with a button JSX button because..

<button> | Supports Mouse clicks Enter keypress Spacebar keypress

…you natively get under the hood: mouse clicks, enter keypress and spacebar keypresses by default. This is just built in. Yay HTML. We love HTML. I love HTML.

ARIA support

And… we’ll use just enough ARIA attributes to let screen readers know when the container is being opened and closed — or in the case of if you have many widgets on the page — which container is being opened or closed.

On the button, the three ARIA attributes we’re adding are

Aria-controls to tell assistive technology the id of the associated element the button’s controlling. In this case it would be the name of the container’s id.

[jsx code] aria-controls={ariaControls}

aria-expanded, which conveys whether the widget is expanded or not

[jsx code]

aria-expanded={ariaExpanded}

And aria-label for cases where we need a more accurate button label, especially if we are doing icon buttons

[jsx code]

aria-label={ariaLabel}

State & click handlers

We also need state and click handlers to toggle the container open and closed

We’ll use React’s useState hook to define the isOpen state variable and setIsOpen function, initializing isOpen to false.

[jsx code]

const [isOpen, setIsOpen] = useState(false);

Optionally, we could pass in a boolean defaultExpanded prop, for those cases when we need a widget to be open when a view is loaded.

Like a Terms of Service toggle tip, for example.

[jsx code]

const [isOpen, setIsOpen] = useState(defaultExpanded);

We then make a toggleOpen function that uses setIsOpen to toggle the state between true and false

[jsx code]

const toggleOpen = () => { setIsOpen(!isOpen); };

In the Button, we pass the toggleOpen function into the onClick event

[jsx code]

onClick={toggleOpen}

…the isOpen value into the ariaExpanded prop

[jsx code]

aria-expanded={isOpen}

And add isOpen to the children JSX expression so the children only render in the div if isOpen is true

[jsx code]

<div> {isOpen && children} </div>

Focus management

Focus management. Let’s set our widget up to listen for ESC key presses and return focus to the button when the widget closes

**Focus management is a nice UX enhancement and is an extended disclosure pattern, so you should test this with your users.

We’ll start by creating a buttonRef using React’s useRef hook, initializing to null

[jsx code]

const buttonRef = useRef(null);

…make an onKeyUpHandler function, listening for ESC key presses while the widget isOpen, And if the widget is open, we’ll set IsOpen to false and send focus to the buttonRef

[jsx code]

const onKeyUpHandler = (e) => { if ((e.key === “Escape” || e.keyCode === 27) && isOpen) { setIsOpen(false); buttonRef.current.focus(); } };

Next, we pass in the onKeyUpHandler function to the onKeyUp synthetic event on the DisclosureWidget’s wrapper div, and

[jsx code]

return ( <div onKeyUp={onKeyUpHandler} className=”dwWrapper”> <Button aria-controls={ariaControls} aria-expanded={ariaExpanded} aria-label={ariaLabel} id={buttonId} buttonRef={buttonRef} buttonClasses={buttonClassNames} icon={buttonIcon} iconOnlyBtn={iconOnlyBtn} onClick={toggleOpen} size={buttonSize} > {buttonText} </Button> <div> {isOpen && children} </div>

Pass in the buttonRef to the Button’s buttonRef prop (say that three times fast) Your Widget will now close on ESC keypress and return focus to the Button

This is the extended disclosure pattern. You should test with users

[jsx code]

buttonRef={buttonRef}

CSS focus states

CSS focus states. Now that we have focus management done, let’s get our CSS focus states normalized

Since browsers don’t give a consistent look for focus states, we should make it clearly visible for our users when our interactive controls receive focus.

Let’s add some default styling for our :focus pseudo selector throughout our app, and pick a color with at least a 3:1 contrast ratio or greater.

[css code]

*:focus { outline: 0; outline-offset: var(—s-5); box-shadow: 0 0 0 var(—s-5) var(—purple-orchid); }

We can always override focus styles in our individual CSS files to customize them even more, yet it’s always important to show them.

[css code]

.button { font-weight: var(—font-weight-bold); border: 0; border-radius: var(—border-radius); cursor: pointer; display: inline-block; line-height: 1; transition: background-color 0.2s ease;

:hover { background-color: var(—color-primary); border: 1px solid var(—color-primary); }

:focus { outline: 0.1em solid var(—color-primary-reverse); outline-offset: -2px; box-shadow: 0 0 0 0.2rem var(—color-focus); }

:active { outline: 0.1em solid var(—color-aquamarine-500); }

Mouse click management

Mouse click management. If you have many widgets on the page, you’ll only want to have one widget open at a time, so let’s set up a handler to make that happen

Like our buttonRef, we’ll create a contentRef with useRef, initializing to null

[jsx code]

const contentRef = useRef(null);

Like our buttonRef, we’ll create a contentRef with useRef, initializing to null

[jsx code]

const contentRef = useRef(null);

Create an onClickOutside event Handler function. This will check if the buttonRef or contentRef contains the event target, keep the widget open, otherwise, set IsOpen to false to close the widget

[jsx code]

const clickOutsideHandler = (e) => { if ( contentRef.current.contains(e.target) || buttonRef.current.contains(e.target) ) { return; } setIsOpen(false); };

Now that we have that clickOutsideHandler set up, we can user React’s useEffect hook and some if statements For example, If isOpen is true, we’ll add some document.addEventListener functions for mouseup and keyup and call the clickOutsideHandler for each.

[jsx code]

if (isOpen) { document.addEventListener(“mouseup”, clickOutsideHandler); document.addEventListener(“keyup”, clickOutsideHandler); }

If isOpen is false, we’ll remove those event listeners.

[jsx code]

} else { document.removeEventListener(“mouseup”, clickOutsideHandler); document.removeEventListener(“keyup”, clickOutsideHandler); };

We’ll also do a cleanup function to remove any stray event listeners from running

[jsx code]

return () => { document.removeEventListener(“mouseup”, clickOutsideHandler); document.removeEventListener(“keyup”, clickOutsideHandler); };

Lastly, we’ll pass in isOpen as the second array argument in our hook to be sure useEffect only runs if the isOpen state changes value

[jsx code]

[isOpen]

image: Arrangement of handcrafted Venetian masks displayed in a shop window

Now we can start using this pattern to making many pretty masks… so let’s make a toggle tip.

Toggle tips

Toggle tips are NOT Tooltips

One important thing to note. A tooltip is NOT a toggle tip, the interactions are different.

A tooltip’s interactivity revolves around hovering over the tool tip and maybe focusing on it with a keyboard.

Toggletips

Toggletips contain interactive content,are supported by touch devices, non-mouse pointers, and eye trackers, where tooltips are not

Toggle tips

But technically, what we’ve already built, will support what we need with a little styling, and I know you’re going to go back to your work and do something like this instead

Toggle tips

Mmm hmm. OK y’all. Fine! We’ll make a Toggle tip with an icon-only version.

But let’s talk about icons for a minute

Icons — Informative or decorative

Icons can be informative or decorative

Informative icons need to be paired with descriptive text to be perceivable by screen readers.

Decorative icons need to be hidden from screen readers, because they don’t add significant value to your app

image: code snippet of our button

Since we want to support icons in our Button component, we’ll add in a new component to the mix

The FontAwesomeIcon React component. What I like about the ReactFontAwesome icon under the hood, it uses an SVG. Their team preps their SVG in a way where they set it to be focusable=false so they hide it as a decorative icon already. So it’s up to you to use the ARIA labels/everything else to make it informative, if you want. It’s a nice way to use a decorative icon, then pair it with children into a span and use CSS for positioning. We’ll gate them behind the icon prop to render them only when we need them.

[jsx code]

{icon && ( <FontAwesomeIcon icon={icon} className={iconOnlyBtn ? iconBtnClasses : iconClasses} size={size !== ButtonSizes.small ? “lg” : “sm”} /> )}

We can pair an icon with visible button text

[jsx code]

<Button icon={buttonIcon}> {buttonText} </Button>

And since we added that aria-label support in earlier, we can pair an icon with an aria-label here and support screen readers

[jsx code]

<Button aria-label={buttonAriaLabel} icon={buttonIcon} iconOnlyBtn={true}

{buttonText} </Button>

And we have a way to add extra CSS to override Button styles in icon-only scenarios

[jsx code]

<Button iconOnlyBtnClasses={styles.btnIcon} > {buttonText} </Button>

Now that we have the button adjusted, we can use our DisclosureWidget and build our ToggleTip

[jsx code]

export default function ToggleTip() { return ( <DisclosureWidget aria-label=“Fruit trivia” buttonClasses={styles.toggleTipButton)} buttonIcon=”apple-alt” iconOnlyBtnClasses={styles.btnIcon} iconOnlyBtn={true} > <div className={styles.floatingContainer)}> <p className={styles.toggleTipContainer}> Hungry for more interesting fruit facts? View a{” “} <a href=”https://google.com”>full list of fruit trivia</a> in at our virtual farm stand. </p> </div> </DisclosureWidget> ); }

First we’ll pass in the buttonIcon, set iconOnlyBtn to true and pass in an aria-label

[jsx code]

<Button aria-label={buttonAriaLabel} icon={buttonIcon} iconOnlyBtn={true}

{buttonText} </Button>

export default function ToggleTip() { return ( <DisclosureWidget aria-label=“Fruit trivia” buttonClasses={styles.toggleTipButton)} buttonIcon=”apple-alt” iconOnlyBtnClasses={styles.btnIcon} iconOnlyBtn={true} > <div className={styles.floatingContainer)}> <p className={styles.toggleTipContainer}> Hungry for more interesting fruit facts? View a{” “} <a href=”https://google.com”>full list of fruit trivia</a> in at our virtual farm stand. </p> </div> </DisclosureWidget> ); } Then, we’ll add some styling to the button and the icon

Then, we’ll pass in a div with a paragraph and a link to our widget.

[jsx code]

<div className={styles.floatingContainer)}> <p className={styles.toggleTipContainer}> Hungry for more interesting fruit facts? View a{” “} <a href=”https://google.com”>full list of fruit trivia</a> in at our virtual farm stand. </p> </div>

Toggle tip

Boom. ToggleTip

ToggleSearch

Let’s make a Disclosure with an embedded search form

First…

[jsx code]

export default function ToggleSearch() { return ( <DisclosureWidget buttonClasses={clsx(styles.searchMenuButton)} buttonText=”Find a fruit” buttonIcon=”search” > <form onSubmit={(e) => e.preventDefault()} > <Input label=”Search” name=”value” type=”search” /> <Button>Go</Button> </form> </DisclosureWidget> ); }

We’ll pass in some buttonText and an icon to our disclosureWidget button For the purposes of this prototype, we’ll pass in a form and prevent the default onSubmit action

[jsx code]

aria-label=“Fruit trivia”

buttonIcon=”apple-alt”

iconOnlyBtn={true}

Add an Input component with a label, name attribute and a input type of search, and a Button component. We don’t need to specify a submit type for the button, since it’s embedded in a form and we get that attribute for free.

[jsx code]

buttonClasses={styles.toggleTipButton)}

iconOnlyBtnClasses={styles.btnIcon}

Targeted focus management

An embedded search widget is the perfect use case for some enhanced UX… like targeted focus management.

In other words, when we open the widget, we’ll send focus right to the search input.

To do that, we’ll use the useRef hook to create the DOM reference to our input, create a variable called firstItemRef, and assign useRef to null

[jsx code]

const firstItemRef = useRef(null);

We’ll pass firstItemRef into the DisclosureWidget prop …and our Input component’s inputRef prop

[jsx code]

<DisclosureWidget firstItemRef={firstItemRef} buttonClasses={clsx(styles.searchMenuButton)} buttonText=”Find a fruit” buttonIcon=”search”

<form onSubmit={(e) => e.preventDefault()} > <Input inputRef={firstItemRef} label=”Search” name=”value” type=”search” /> <Button>Go</Button> </form> </DisclosureWidget>

In our DisclosureWidget useEffect’s first if statement, we’ll add a nested if statement checking if the firstItemRef is defined,

And if so, send focus to that firstItemref

We’ll also pass in firstItemRef as second argument to the useEffect function array to prevent component re-renders

[jsx code]

if (firstItemRef) { firstItemRef.current.focus(); }

Embedded search widget

And now we have an embedded search widget. These are some really great patterns based on the enhanced disclosure widget.

This is where it gets tricky

This is where it gets tricky, because this is the point where things get tempting for a developer.

Hamburger navigation [image: navigation with apple, orange, grape link that visually present as buttons

What if your designer comes up with this hamburger navigation pattern? Hmm. Looks like a good case for a disclosure pattern, right?

Well, if it’s navigation, those items should look like links not buttons, so we should adjust them…

Hamburger navigation

…to have underlines and less of a button-y look to communicate intent. Because cognitive accessibility is important too. Now let’s get back to the building it.

Hey Links Whoa

Let’s add some links in there.

Cool. Let’s add some links into our disclosure widget now. We’ll find a quick way of doing this, like, passing an unordered list.

And mapping those links. Yeah, this is cool. We could just… map in some links.

And hey! We can have a widget with a hamburger menu, and make this toggle menu links just to have a quick thing without even making it a new component. That could be fun.

[jsx code]

export default function ToggleMenuLinks() { return ( <DisclosureWidget aria-label=”fruit choices” buttonClasses={clsx(styles.disclosureButton, styles.chooseFruitButton)} buttonIcon=”bars” iconBtnClasses={clsx(styles.btnIcon)} iconOnlyBtn={true} > <ul className={clsx(styles.floatingContainer, styles.disclosureMenuList)}> {items.map((item, i) => { return ( <li className={styles.disclosureMenuListItem} key={i}> <a href={item.link}>{item.title}</a> </li> ); })} </ul> </DisclosureWidget> ); }

How about Buttons Whoa

How about buttons?

We could pop in buttons in this list as well… What else could we do with this?

[jsx code]

export default function ToggleMenuButtons() { return ( <DisclosureWidget aria-label=”fruit choices” buttonClasses={clsx(styles.disclosureButton, styles.chooseFruitButton)} buttonIcon=”bars” iconBtnClasses={clsx(styles.btnIcon)} iconOnlyBtn={true} > <ul className={clsx(styles.floatingContainer, styles.disclosureMenuList)}> {items.map((item, i) => { return ( <li className={styles.disclosureMenuListItem} key={i} <Button>{item.title}</Button> </li> ); })} </ul> </DisclosureWidget> ); }

Yes… Roving Focus Whoa

How about roving focus?

image: code snipped of roving focus

We could add up and down arrow key support and optional home and end key support, because you see some of those patterns.

You see that on components sometimes and even on the WAI site, so that’s nice. We’ll add that to our component. That’ll be fun.

Yo TagPalooza I’m clever

Oh wait!

We’re doing a list, but inside this list… how about — instead of passing in a link or button — let’s like make this funky Tag component.

And then, we can pass in whatever element we want into the tag prop, and the component will render that element.

We could pass in an “a” and render a link.

Pass in a “button” and render a button.

Pass in an “input” and render an input.

This could be really cool. This could be really powerful!

[jsx code]

return ( <li> <Tag {…props} onClick={handleSelect} onKeyPress={handleSelect} ref={ref} tabIndex={focus ? 0 : -1} > {character} </Tag> </li> );

Check out my Fancy List Separation of concerns, baby.

Check out my fancy list, separation of concerns, baby.

And while we’re here, we can start working on some separation of concerns.

So now that we have this fancy Tag component, we can make a list item. We can make a list, have this roving focus, and start building this pattern.

Oh, this is getting fun. Now the component’s getting kind of big.

[jsx code]

import React from “react”; import clsx from “clsx”; import ListItem from “./ListItem”; import useRoveFocus from “./utils/useRoveFocus”; import masks from “./data/masks”; styles from “./css/DisclosureWidget.module.css”;

const List = () => { const [focus, setFocus] = useRoveFocus(masks.length); return ( <ul aria-labelledby=”menubutton” className={clsx(styles.floatingContainer, styles.disclosureMenuList)} > {masks.map((mask, index) => ( <ListItem key={mask} setFocus={setFocus} index={index} focus={focus === index} mask={mask} tag=”a” /> ))} </ul> ); }; export default List;

Some Ternary magic? …Hey now. Maybe some ternary magic? Hey now…

Oh! And then… in our uber disclosure widget… we could have our enhanced widget, but then if it’s a list, we could pass it a list prop, …and we could render a List, …and we’d have ListItems where we could pass in a tag prop. …and render whatever element we want.

What could go wrong?

[jsx code]

{isOpen && isList ? ( <div ref={contentRef} id=”dwContainer”> <List /> </div> ) : ( <div className={styles.dwContainer} ref={contentRef} id=”dwContainer”> {isOpen && children} </div> )}

image: Jim Halpert slowly reclines in the car passenger seat, hiding in embarrassment

Maybe this is a bad idea.

What pattern is this?

Because at this point, what pattern is this? Now we’re starting to dip into different patterns. We went from a Disclosure pattern…

image: Menu and Menubar pattern highlighted on WAI page

…into a Menu and Menubar pattern.

image: WAI-ARIA Roles, States, and Properties – WAI page

…and the menubar pattern has menuitem roles, and menuitem checkbox, and menuitem radio roles, and all these different states that are needed for unordered lists and their respective children.

A hamburger navigation, however, is technically part of the disclosure widget implementation.

Therefore, in a disclosure navigation pattern, no ARIA menu roles should be added to any unordered lists in a component implementation.

Because it’s a different use case. This is where devs incorrectly mix WAI patterns.

image: Menu and Menubar Pattern – WAI page

But when you start thinking about those mega menus at the top of a nav that have those fly outs that go to the right that’s simulating those desktop menus like Electron or anything else.

That’s what those mega menus are trying to simulate, with nav and the checkboxes and the radios.

image: Mythical University mega menu example – WAI page

That is what a mega menu pattern is, and there’s this confusion when a designer comes in with a pattern. They see this beautiful pattern, and they don’t understand the logic behind these two patterns that are being coded versus what you see in a design.

image: Menu button pattern highlighted – WAI page

And then it gets mixed into your disclosure widget, and it doesn’t get documented.

And then you get this mega component.

And then people start using it.

And then you get into accessibility audit.

And then there’s this mess.

And so you have these components with this pattern.

image: Menu Button Pattern – WAI page

That mix one pattern.

image: Disclosure (Show/Hide) Pattern – WAI page

With another pattern.

image: brown squirrel sitting on a picnic table, shouting with outstretched paws

Whoa, Nellie… Even though the one pattern can have many uses, it’s important to keep your pattern uses separate.

image: Shrimp and lime jello mold, plated with apple slices

And you begin to make unwise decisions… like creating dishes with jello and shellfish. And things can go wrong very quickly.

Don’t mix the masks. [image]: Red squirrel with one paw outstretched in a "please stop!" gesture

SO… You shouldn’t be mixing your masks. And breaking the rules of ARIA.

You should be separating your components out into their purposeful intents.

You may think that your magical mask will give you access to that very exclusive Carnival masquerade, but instead you may end up at a completely different Carnival…

image: vibrant Carnival, with sweeping bright lights of chaos and a clown, Paolo Nicolello — Unsplash

Like this… and then things can go wrong very quickly.

image: Carousel illuminated at night, Lorenzo Dominici — Unsplash

And then it can go even more wrong and…oh god. And here comes the carousel.

image: Open UI homepage

I do have to say, though, the Open UI W3C Community group is working on a solution for native components for this. Una Kravets will touch upon this briefly in her talk tomorrow.

A solution is coming

I am very happy a solution is coming. So definitely check out her talk tomorrow.

image: 60-foot inflatable viking monster float lurks over a crowd

Avoid chaotic carnivals like this one. The Viareggio Carnival with some extremely large floats in Italy.

image: 60-foot inflatable viking monster float holding a beheaded Caesar

…and a completely different experience than you wanted. Don’t mix your masks.

Wrap-up

So to wrap up…

Design-systems are a Carnival!

Design Systems are a Carnival!

Our users are diverse

Our users are diverse

image: Red squirrel with one paw outstretched in a "please stop!" gesture

Don’t mix your masks

image: Shrimp and lime jello mold, plated with apple slices

Or you’ll make bad choices

image: 60-foot inflatable viking monster float lurks over a crowd

Or you may end up at a completely different Carnival…

image: 60-foot inflatable viking monster float holding a beheaded Caesar

…with a completely different experience than you wanted.

image: Person in inflatable dinosaur costume flips into a raft floating on a pond and claps with glee.

And Design Systems are always the hotness.

Thank you.

https://noti.st/resource11/

Slide deck posted after the talk

@resource11 Twitter | Instagram | GitHub