[WIND BLOWING] ADAM ARGYLE: (SPOOKILY)
Welcome to another episode of "GUI Challenges"-- [EVIL LAUGHTER] --where I build
interfaces my way. And then I challenge
you to do it your way, because with our brains
[SNORTING] combined, we will find multiple ways
to solve these interfaces and expand the
diversity of our skills. [MUSIC PLAYING] (SPOOKILY) In-- [CLEARS THROAT] (NORMAL VOICE) In today's
GUI challenge, we are going-- it's not going to be that
spooky the whole time. There's just no way. But in this GUI challenge, we're
talking about multi-select. And look at this. Multi-select, this is
like a filtering system. People need to be making some
choices in your interface to filter a big set
of data that you're trying to reduce cognitive
overload by giving some powers to the user. And look at these
new controls in iOS. These are cool. Love it. So I'm going to tell you how
we got these controls, how I set this up,
because look, we have desktop users being empowered. We have mobile users
being empowered. Here it is over on Android. Got to love this here. We'll make two selections. And look at our
filters set here. And over here, power
through with our keyboard-- Space, Space. Everything works
just as we want. So there's multiple
controls in here. And all of them are just trying
to serve these different users that need to make some
filter choices that we want their input and that you're
going to want to skim and make choices really fast and not be
bogged down by some sort of-- I don't know-- really
extravagant filtering system. So anyway, this is the
one that I chose to build. This was my style today. And let me show you
some of the cool features it has, like
the theme that's in here. We have a light
and a dark theme. We cover color schemes in one
of the earlier GUI challenges. So I'm just going
to quote that one. That's where all these
values came from. And go there if you want
to learn about it more. There is a subtle thing, though,
I want to show you in here. And that is if you
look at the accent color on these
checkboxes here, they match the focus within state
border of this field set. And I don't change the
focus color of the outline. That's just the one that
comes with the browser here. So let's come over here. Ah, see how the
focus within is set and the checkbox accent color
is coming from the same one? And I just thought that
gave a really nice look. It's like you're interacting
with this group here. And you're interacting
with this group. And the colors kind of
come through as this sort of like focus color. Well, it's not really focus. But you know what I'm doing? I'm bringing attention
to these areas using like-oriented
colors that are making them pop off the page. Anyway, it's really
easy to miss at first. And I thought it had a
really powerful effect. And this component is also
managing a lot of the states. So if we look up here, this
is holding on to three items. So this is a state where
there's more than one. Down here, there's
more than one. And here I'm just going to
refresh Firefox, which Firefox persists your checkboxes, like
your choices, which is kind of a cool feature actually. Anyway, so here I am. I refreshed. I have none selected, which
means I see everything. And that's an interesting
state for this component and this other component to
have a relationship with. Now, I didn't go into
how we built this today. Now, this sweet grid is built
with Isotope, just a library I love to work with. And it has a sort
and filter API that will automatically rearrange
all of the items in here. And then, of course,
I just love delays. So I put a little bit of a
delay between each one, which is, again, part of its API. And it just looks
so nice, doesn't it? Anyway, Isotope, kick butt. If you've never used it
before, go check it out. It's really fun. But anyway, the component
today that we're talking about is this managing-- in this case, the items that
are selected, the filters. And so we have none selected. There's a scenario where
there's one selected. You can have many selected. And then you can have
all of them selected. And that's just the states
that it needs to manage. And the hard part
between my solution here is that I have a checkbox
system and a select box system. This one is using
a multi-select. Here we are in iOS. And I love this interface. So I think this is just so
much better than I would build. But I have to integrate with it
as a separate type of component for users that are
coming from touch. They're going to be very
familiar with this interface. This is going to look
nearly native to them. And they get the
results really fast. So I don't think they
need anything additional. Plus you get to save so
much space on mobile. Look at all that space we save. Oh, that's so cool. But yeah, I have to manage
two different components. And so that trade
off was something I was willing to work with. And I'll show you
that in the JavaScript as I resolve both of the
choices from the user into the same object so
that I can submit them to a database as a
normalized value set. Anyway, we'll get there. But first, let's look at more
of the interaction models because there's some cool
things I want to show you, like keyboard traversal. Here, let's spend some
time in iOS right now. And I'll hit Tab. I'll hit Space. I'll hit Space. I'll hit Shift-Tab, Shift-Tab,
Space, Shift-Tab, Space. You can even be using
a gamepad right now. Imagine you're on your
Switch, and you're just hitting up and down
in the Nintendo store, and you have different games
showing up here on the right. Super easy interface for
keyboards, gamepads, and stuff like that. Nothing too surprising. But follow me over
to a larger browser where I've kind of
fooled my system. And let's take a look. Over here, I'm in
the Responsive Mode of DevTools in Desktop touch. So I don't really know right
now Desktop touch scenarios. So maybe you tell me one where
you wouldn't have a mouse or wouldn't have a
stylus or something, where you're only on desktop. I mean, Windows
probably has this. But anyway, in
that rare scenario, you may see an
input like this one. And this is for
multi-select in here. I have it open over
here-- select multiple. And this is the default
layout you get when something can be multiple selected. Like here, if I hit Shift,
I can select both of those. Or I can hit click,
and just get one. I can Command-Click. So here I'm going to get
30 Days, Command-Click, and I can make multiple
selections like this. But what's really fun
is if I hit just Down and Up here, I can go through
all these items on my keyboard. And anyway, I just like showing
you this because the grid is so responsive and the choices
are so cool that I can-- here, I'll hold Shift and
just go up and down. It's just fun. This is just a fun
visual thing to do. And hopefully, you
were entertained by all the swooshy squares like
I was when I realized this. Anyway, let's go back
to talking about some of the other features
in the debugging corner. Well, now we got to talk a
little bit about reduced motion because you know
I just love that. And today I'm going to
show you through simulation in our operating system. Usually, I open
it up in DevTools. But let's go into
Accessibility today and to Display
and Reduce Motion. Pull that back. And what should change? First off, we see
instant highlights. We're not scaling
that because why not? That looks great. And when we choose, we see an
instant result in our grid. Very nice. So mindful, right? Light and dark,
motion, no motion. We're just flipping
tiny little variables in our system to make
sure that this all works. And that's so cool. I'm going to go ahead and turn
Reduced motion off, go back to the overview. And yeah, that's so nice. OK, cool. Let's turn off the
lights again because I think that's just fun when we
do the screen reader experience. And I'm going to go through
our checkbox system. Check it out. So here, let me
dive into Chrome. I'm going to hit Command-F5. SCREEN READER: Multi-Select
vertical line GUI Challenges. Web content. ADAM ARGYLE: All right, we
are inside of the web content. And I'm going to tap
into our first field set and to make a couple
of filter choices. SCREEN READER: Leaving
toolbar item palette. Entering Multi-Select GUI
Challenges web content. Last 30 Days, unchecked,
checkbox, New, group. Last 6 Months,
unchecked, checkbox. Checked. 2 filters giving 6 results. Table Lamps. Desk Lamps, unchecked, checkbox. Checked. 3 filters giving 10 results. ADAM ARGYLE: Did you hear
how that's telling me how many filters I have
applied across all of there and how many results there are? Isn't that neat? I mean, wouldn't
you want to know that if you were hitting
filters and nothing was sort of telling you how
many were behind each choice that as soon as
you made a choice, you were reminded how many
filters you've chosen? I thought that was so cool. And the way that I did it is
a combination of counters, and JavaScript, and
using some ARIA roles. And by assigning an element
a certain ARIA status, it's able to announce the
changes that are happening. And I thought that was just
the neatest little experience. So let me go ahead
and turn that off. I hope you found
that interesting. The article, of course,
will have all of it spelled out very
clearly for you. But OK, let's turn
on the lights. I mean, it was the spooky
episode. (SPOOKILY) So maybe we should leave
them? (NORMAL VOICE) No, let's turn them on. Let's turn them on. OK. SCREEN READER: VoiceOver off. ADAM ARGYLE: That was nice. All right, next I want to
check out the right to left. Let's go look at
a bigger browser. I'm going to open
up the DevTools. And notice we have a
select element here with all the option groups. And that's how you get all
those different grouped areas. Anyway, cool feature. Right to left, here we go. And well, look at that. Isn't that handy? We hover on each for labels. They automatically
highlight the checkbox. And if we choose them, we
get a nice filtered grid. That's just so cool. If you've got a
keen eye, though, do you see the bug
in the grid here? This is Isotope laying
it out, not CSS Grid. And these two squares
should be over here because the inline
start is here. The directionality now is
going from right to left. So interesting, right? By using a library, which
gave us a lot of cool tools, it actually is hindering some
of our internationalization of our content. But well, maybe it's
not hindering it. But in this case, maybe
someone would notice. But kind of cool. Still, all of our styles
here in the sidebar and the multi-select and
that interaction we want, that, though, all
works in right to left. Let's go back to left to right. Nice. Now, the layouts in this
multi-select scenario ended up not being
that exciting. So we can have the
body and the main. Those are centering
all the content here, putting some space
between our grid and our header for this
little layout here. But if we go to the aside, the
aside has no special layout other than-- you can see
our counter-reset, though, or filters counter set. So we were talking
about that earlier. Our form, though,
does have a layout. And so we're using the form to
group all of the input types that were trying to collect
information from our users and putting it into
one spot so we can just use the form as an
object for querying what the values are for these. But look, it's a grid. It's a grid. It has a gap. That's nice. Look, I can drag the gap. Wee. The new length tool's
looking sweet in DevTools. I don't know if
you tried it yet. It's also got a type of popup. Look at that. You can change all the
different units right here. So in case you're even learning
units, they're right there. Anyway, enough fan boying
about the length tool. This, though, is interesting. So display grid,
not interesting. Length tool, well, that was,
I think, very interesting. But the max-inline-size
at 30 characters, this is kind of crucial in that
I'm setting the sidebar size on the form
with a character unit selector or a character
unit relative unit, which is sort of like making sure
that the items here never go beyond a certain width. And I think that's really
normal for a sidebar to sort of have a max
width, and then you let lines wrap for these
different label elements. So that's how I did it. It was with a max-inline-size
of 30 characters. And I felt like 30 characters
was a good size for showing a filter in a sidebar. And that sets pretty much the
width for the entire thing all the way down. Kind of interesting. So here, let's
look at a fieldset. Fieldset just has some spacing,
nothing really that interesting here. We're using 2-- I love using
2 characters everywhere. It's just sort of a great unit. The legend here that's
inside of this fieldset, now, it's not necessarily
layout related. But look at how it sits in here. It's a very unique way
that it's positioned. And it's unique to the
fieldset and legend. This just comes free
with the browser. And I thought it
looked really nice here as we're not only visually
grouping the elements, we're giving it a label. But that label is also
read to screen readers. And so when it said, Last 30
Days-- that's what this one is. This is a New category section. And so New is
what's written here. And screen readers
and sighted users are all going to get
to see this value. And I just thought it worked
out really nice that way. And down here, this is just
our label and our checkbox. We're using flex. And they're aligned
to the center. So it's just really cool, right? So there's our layout. Nothing really too surprising. But really stable and
really nice for us. Now, there was one
kind of crucial thing that I do want to go over, which
was toggling the visibility of this select up here. So by default, the select
is set to Display None because we're kind of assuming
a user is coming with a mouse. Now, if they're not
visiting with a mouse, they're visiting
with pointer coarse, let's go see what we do. For example, here
in the fieldset. So our fieldset-- and
here's all of our styles. We have this media
query called useSelect. So if we're using the select
in this particular use case, so this would come
back as true or false based on if the user
is using a mouse or if they're
using their finger. And if they're
using their finger, we want to set the
fieldsets to display none. So no checkboxes. Those are just too
tedious for your finger. And we'll go turn the
select element on. And it can now show
and be the dominant way to put input into the form. So that was it. I used custom-media
up here with the rest of my stashed custom-medias,
like motionOK and dark and light, which we use
in all sorts of episodes. And this one is
called useSelect. And I just thought it
made things nice to read. Time to talk about JavaScript. I'll just try to
briefly go over it because I think what's
more interesting is the results in the console. So here's where I'm
importing Isotope. I initialize Isotope here,
give it some of my preferences here that I use to make a grid. And then here's my
filterGrid function that gets called with the things
that's trying to be matched. And here's where I check
prefers-reduced-motion on the client. And this is where I
set the new filter. So I arrange. I set the new query that's
going to set what is to be shown and what's not. Here's the stagger, which
changes the delay for each of them by 25
milliseconds, and then the transitionDuration,
which I set to either 0 if motion is not OK. Or I set it to
something if it is OK. Down here, I prepare
the select options. So when you use
a select element, there's a way to get
all the values out of it using
element.selectedOptions. And here I make an array from
it and sort of push things into a data format that looks
a lot like what the form is getting with the checkboxes. Here's where I'm
watching for the select to change so that I know if I
need to go prepare the values. Then here's where
I'm creating a query and then invoking Isotope
to filter the grid. Down here, this
is the checkboxes. So the checkbox is watching
all the forms for input. Whenever the
checkbox is changed, we go grab form data
for the whole form, and we output a new
object to the console. I'll show you that in a second. And here's where I
create another query, this time, again, for Isotope. And I set the filter here. And then down here at the
very bottom, a querySelector, applied-filters, textContent,
it's giving this many results. And so this is what's spoken
out to the screen reader because it's being
inserted to an element that it knows to
announce to the user. So we modify it with
CSS and JavaScript. And both those combine into
an announcement to the user. OK. Let's go look at the
results in the console because I think
it's kind of fun. All right, let me
pull open the console. Hit Escape down here so we
pull open the JavaScript. Look, we've already been
making some choices. But all of our choices have
been checkboxes so far. So if I hit Refresh-- well, I want to see
some grid items. There we go. And if I check one, I check
two, look, we have an array. There's the group. And here's the value. Here's the group and the
value, "last 30 days." So this means that they're on. These are binary. So these are only if
they're on are they going to show up in this list. And that was the way that the
checkbox element and the form element reported these. So these could be
submitted to a server. Let's fool the
browser a little bit here and change some of these. Great. So now I have
Multiselect down here. So I've named them in
my console warning. That's what's giving me this
nice little yellow here. And if I twirl this open,
"new," "last 30 days," "new," "last 6 months." So I'm making sure that
the data structure that's getting created by the
multi-select and the data structure that's being
created by the checkboxes are the same things so that I
can submit them to one place. And that API only has to care
about one type of filter set or one type of sorting set. But my interface
on the client side can sort of do the
hard work to manage a touch input, and a desktop
input, and a gamepad input, and all these different
interfaces on mobile and tablet and desktop and combine them
into one so that the server doesn't have to care. The server doesn't
want to have to care that there's a user using this
brand-new input on Android or if they're using a
brand-new input on iOS. They just want to
get some values and show them to their user. Just really, really neat stuff. So I hope you enjoyed
this multi-select episode. This is a fun type
of user experience that I've built so many
times over the years. And I know you've built one too. Send it to me. It can always make for these
really neat interactions, where we're just sort of like going
in and showing and hiding different elements
based on selections. What have you built? I'm dying to see it. (SPOOKILY)
Dying to see it. (NORMAL VOICE) And I hope you have
a good holiday. And take care, you all. I'll see you in the
next "GUI Challenge." [HOWLING] [MUSIC PLAYING]