Author: Jerry Jones

  • The Bias of Timed Code Tests

    The Bias of Timed Code Tests

    I clearly remember the code test when going through the hiring process at Automattic. As someone with imposter syndrome and anxiety, the thought of having my code under a microscope, and confirming my fear of not being a “real” developer, isn’t exactly my idea of a fun time.

    But, I made it through, and was hired as a JavaScript Engineer last year.

    I recently switched over to the Hiring team, and my first task was to go through the code test again. The first time may have been stressful, but this time would be different, wouldn’t it?

    After all, I’d done the test before and there was no way for me to fail now. No pressure, no stress, right?

    Nope! I still felt extremely anxious doing the test.

    This made me wonder: Why did I still feel so much anxiety and pressure when I could have failed miserably and still been fine?

    The Psychology of Time Limited Tests

    In the instructions of our code test, we recommend a 6 hour time limit:

    We ask that you spend around 6 hours on this test (not counting any needed setup and/or research time) and that you complete it within one week of the test being sent to you. To be clear, please do not spend a full week of work on this. We don’t want to take up too much of your time.

    Even though it’s a recommendation, as soon as I read “6 hours,” a timer started clicking in the background of my mind.

    I played armchair psychologist and looked up a paper on what time-limited tests do to performance and how valid they are for evaluation. The paper talked a lot about a timed test vs an untimed power test. Our code test would be more like a power test intended to evaluate deeper skills, but we impose a non-restrictive time limit.

    tl;dr: Having a time-limit, even an artificial one, is biased and not so great for people’s performance.

    Time-Limited Tests Are Less Reliable

    “For nearly a century, we have known that students’ pace on an untimed power test does not validly reflect their performance.”

    They make it clear early on that speed does not equal skill or knowledge in an area. This has been studied with students in psychology, engineering, chemistry, finance, and more. Performance under time does not help evaluation because, “putting time limits on power tests introduces irrelevant variance

    The, “for nearly a century part,” is backed-up too. From a study done in 1914, they say:

    If we seek to evaluate the complex ‘higher’ mental functions, speed is not the primary index of efficiency, as is borne out by the evidence that speed and intelligence are not very highly correlated.”

    Finally, they make their recommendation for improving reliability very clear:

    “[…], we have known for decades that the best way to improve a time-limited test’s reliability is simply to remove its time limits.”

    Time-Limited Tests Are Less Inclusive and Less Equitable

    In the US, students with disabilities often get extended time on timed assessments. However, rarely do they actually use more than the standard time, and when they do, it’s generally only a small portion of the available extra time. In the paper, they say:

    When students request extended time or time and a half, what they are really requesting is not to feel the pressure of time ticking off; not to experience anxiety about running out of time; not to have [an untimed] power test administered as a [time-limited] test.”

    Furthermore, when most people are untimed, they are fairly efficient and accurate:

    “As we have known for a century: Many students, including those without disabilities, are ‘relatively inefficient in such timed … tests … [but] are able to do relatively efficient and accurate work when allowed to work more slowly.‘”

    After all of this, their final recommendation shouldn’t come as a much of a surprise:

    Remove all time limits from all higher educational tests intended to assess power. In addition to improving the tests’ validity, reliability, inclusivity, and equitability, removing time limits from power tests allows students to attenuate their anxiety (Faust, Ashcraft, & Fleck, 1996; Powers, 1986), increase their creativity (Acar & Runco, 2019; Cropley, 1972), read instructions more closely (Myers, 1960), check their work more carefully (Benjamin, Cavell, & Shallenberger, 1984), and learn more thoroughly from prior testing (Chuderski, 2016).

    https://www.ncbi.nlm.nih.gov/pmc/articles/PMC7314377/

    So, if we really want to suggest a 6 hour limit to be respectful of their time, it’s better to give a test that takes around 6 hours (or less) to be fully complete (at a high quality) and not mention a time limit. That way, it takes 6-ish hours —and we don’t introduce all the negative side-effects of having a time limit.

    But we’re not really timing them

    For Automattic, 6 hours is a recommendation. We want to be respectful of people’s time, which is great. We don’t do anything to actually time them, and we make it clear they can go over the time limit. A lot of the studies don’t fully apply in our situation, but it doesn’t mean the time limit doesn’t have an impact.

    I had a person within my first few code test reviews mention they felt they could have done better, but went over the 6 hours. As in, they self-imposed the 6+ hour limit, even though we are not imposing it.

    Their test was incomplete.

    I can relate. I think one of the big reasons it affected me is that I felt like I wasn’t qualified if I couldn’t do the test within 6 hours. So I put that extra pressure on myself to prove I could. In the end, I think a lot of people disqualify themselves because they didn’t complete the test within 6 hours.

    So, do the people who submit incomplete or not-so-great tests do so because they can’t do it, or because they feel like they aren’t qualified if they can’t?

    Who is more likely to succeed on a time-limited test?

    In the spirit of inclusion, I also wondered who is more likely to succeed on time limited tests, and if that is a hidden bias built into our code test.

    The study above mentioned the benefits of removing time limits for many different people:

    “[…], numerous studies show that removing time limits boosts the performance of numerous students, including students who are learning English, students from underrepresented backgrounds, and students who are older than average. Removing time limits also attenuates stereotypic gender differences.”

    That’s a whopper. It’s worth reading again.

    Another study had this to say about the gender bias with time limited tests:

    “The effect is driven by a strong negative impact on females’ performance, while there is no statistically significant effect on males. […] Female students expect a lower grade when working under time pressure, while males do not.

    http://ftp.iza.org/dp8708.pdf

    So, if you’re working in a white, male dominated field like tech, and have a time limited test in your hiring process, it shouldn’t be a surprise if you keep hiring mostly white males.

    What are we doing about it?

    Since we’re not really timing them, it would be better to not mention a time limit which could add further pressure..

    So, that’s what we’re going to do.

    We’re drafting up new instructions that remove the time limit. We’re also giving out an anonymous survey to evaluate how much pressure candidates feel during the hiring process. We don’t expect this to fix everything, but we’ll keep working towards making it better.

    Everyone is different, and applying for jobs is clearly a high-stress environment, but the more we can do to put people at ease, the more accurate and inclusive our process will be. 

  • More than a Seat at the Table

    Pre-COVID when we could go to restaurants, there were times I’d sit down at the table unnoticed. The servers would walk by. After a few minutes, I’d wave to get their attention as they passed by again.

    It’s happened to all of us. It’s not a big deal.

    But what if the server continues to go to other tables? They never acknowledge you.

    You wave. You speak up. You’re there. You need help too.

    Maybe they eventually look over and nod a little sign of recognition. But they still don’t do anything. They never come by.

    Maybe they eventually briefly stop to tell you they can’t serve you. They don’t have the time. They don’t have the resources.


    I recently read Disability Visibility, and so many of the personal stories in the book shout out, “I’m here. I don’t need to be fixed. The world around me is broken.”

    Our world could be radically different and inclusive if it hadn’t been built by and for able-bodied people. But, for now, we live in an ableist world that ignores and hides away disability. Maybe those with disabilities can sit at the table, sometimes, but that doesn’t mean they’re acknowledged or that their needs are served by these ableist systems and structures.


    All this time, you’re still sitting at the table. Waving, speaking-up, doing your best to draw attention. This isn’t the first time, and it won’t be the last.

    Now imagine being reminded everyday that you live in a world that doesn’t consider you. A world that doesn’t value you. A world that says your needs aren’t important enough. A world that tries to contort you to fit inside it.

    This is the world we’ve built.


    I don’t have any answers, and I am not trying, as an able-bodied person, to speak on behalf of those with disabilities. I’m trying to share an idea that resonated with me in order to hopefully create more empathy and action amongst other able-bodied folks. We need a table where all are welcomed, included, and respected. Rather than listen to me, please check out Disability Visibility and follow disabled activists on Twitter like Alice Wong and Imani Barbarin

  • Must Read: Unspeakable Conversations

    I started reading Disability Visibility this week to expand my understanding of the experiences of the one in five people with disabilities in the US.

    I had intended to do a blog post on things I learned, what struck me, etc. However, instead of reading what I think, please read Unspeakable Conversations (which is the first chapter of Disability Visibility) from Harriet McBryde Johnson.

    The first paragraph will draw you in better than anything I could write:

    He insists he doesn’t want to kill me. He simply thinks it would have been better, all things considered, to have given my parents the option of killing the baby I once was, and to let other parents kill similar babies as they come along and thereby avoid the suffering that comes with lives like mine and satisfy the reasonable preferences of parents for a different kind of child. It has nothing to do with me. I should not feel threatened.

    Harriet McBryde Johnson, Unspeakable Conversations

    It’s beautifully written. Deeply personal, raw, complex, funny, and profoundly impactful.

  • How I Debug

    How I Debug

    For most of my career I thought there was always something missing with how I debugged, like I needed to set-up an advanced error reporting system that would log and track down every error seamlessly. Then, I would really know how to debug like a 1337 haxor.

    Now that I have a big kid job, how has my debugging system evolved to be more professional?

    It hasn’t.

    The same things I did when I started, I still do. I still console.log things. I still var_dump or print_r() arrays to see what’s going on. Even in extremely complex codebases and systems, the same ideas work.

    Debugging is Problem Solving

    What I understand now is that console.log or var_dump isn’t debugging. Those are tools to help you debug. The real debugging happens with you.

    I don’t consciously go through this checklist, but this is the general idea of how I debug.

    Recreate the bug.

    Can you reliably reproduce the bug? If you don’t know what environments and situations it happens in, it’s extremely hard to debug. Is it a certain browser? A certain device? Does it happen consistently after a certain action?

    Check your assumptions.

    Is that variable really what I think it is? Does that function really return what I think it does? This is where I will console.log stuff, or code directly in the console to test basic functions and methods to make sure I really understand what does happen vs what is supposed to happen.

    Isolate.

    Reduce the scope of your issue to the tiniest bit of code you can. If you’re working on a complex CSS issue, how can you boil it down to the most basic test case possible?

    If you’re not able to isolate the issue and reliably reproduce it, then you don’t really understand what the fix is. CodePen is great for helping with this, as you can isolate in a clean environment and then share results with your team.

    Be persistent.

    There’s nothing incredible or advanced about debugging. It’s just about being persistent to understand the root cause of the issue. Some bugs take a long time, but the more you poke and prod at it, the more you’ll understand it.

    You’re Debugging. Not the Tools.

    Remember, you’re the one doing the debugging. To put it all together, we’ve got:

    • Recreate the bug.
    • Check your assumptions.
    • Isolate.
    • Be persistent

    We can easily remember this with RCIB, or BIRC, or hrmm.. CRIB? I bet you’ll be OK without an acronym, there are already enough things to remember.

    The tools assist you, and can help guide you to the issue. In the end, you’re the one solving the problem, so use whatever tools you want to help you. 🙌

  • Across the Atlantic Handoffs

    Across the Atlantic Handoffs

    Automattic is a large worldwide team, made up of smaller, worldwide teams where everyone works remotely. That was one of the things that made me excited to work there, but also very curious as to how it worked in practice.

    Would the timezone differences slow us down? Would we unintentionally get in each other’s way? What if we needed an answer from someone who had already logged off hours ago?

    Working as a Team

    The team of eight I’m on is made up of people from 6 countries:

    • Argentina
    • Czech Republic
    • Germany
    • England
    • United States
    • Greece

    And it’s amazing. We work so well together. This boils down to:

    • Caring about doing a good job.
    • Wanting to help the team.
    • Being responsible and motivated to work independently.
    • Communicating * 3

    I’m a big fan of everyone on the team. We all do the above points well, in my opinion. I’m not sure how well it would work otherwise.

    The End of Day Handoff

    One thing that really helps us work efficiently is our End of Day notes. Everyday before logging off for the day, you post:

    • The status of what you’ve been working on.
    • Any PRs you need reviewed.
    • Is there anything you want to handoff? Lots of notes here, if so.
    • Is there anything blocking or that you need help with? Similar to the above, but not exactly. This could be something outside of a code-related thing.

    This helps us know the status of everything in a consistent way, while also being able to pick-up work or help each other out. We call this asynchronous communication. A lot of things don’t need to be real-time conversations if you communicate clearly enough.

    The handoff works especially well when there are two people spread out over far enough timezones that they have 2 – 4 hours of overlapping time. One person starts work in a more focused way, then there’s enough overlap time for working together and getting on the same page, then handing off to the next person to work on it.

    It also builds a lot of team camaraderie as well as being deeply satisfying when you say you need help with something, go to bed, then wake up and find it’s taken care of.

    Working in Sync

    Earlier on when I’d joined Automattic, I was helping out on a complicated issue where two of us were working actively on the same PR. I was trying to act in a supporting role to get it over the finish line without getting in the way. I tried to walk the line between helping out without taking over.

    I reached out to my co-worker Damián to make sure I wasn’t stepping on his toes by working on the issue.

    “Please, step on my toes.” he said. “I’ll let you know if something isn’t going well, and I ask you to do the same for me.”


    So many places look at being in one office at one location as an advantage, but I’d argue that this kind of open, honest communication and End of Day handoffs allows our team to work more efficiently than if we were all in one area.

    Either way, it’s an amazing team. We’re hiring, so be sure to apply if you think you’d enjoy working remotely on a worldwide team.

  • Setting up NVDA on Parallels with macOS

    This is mostly personal notes that I hope can be helpful to someone else. A lot of this info I gathered and consolidated from Deque’s super helpful post, Using Windows Screen Readers on a Mac.

    Get Parallels

    Download Parallels and follow the set-up. I don’t want to put instructions here, as they’ll likely change and be outdated before too long.

    Why Parallels? I found Parallels to be a lot easier to use and friendlier to set-up access to macOS’s network for local development (like connecting to localhost, custom local domains, etc). Being able to access Windows programs as standalone Apps on your Mac is really nice.

    NVDA Set-up

    A lot of the NVDA set-up should be basically the same between Virtual Box and Parallels, but I haven’t confirmed that.

    First, Download and install NVDA on your new Windows set-up.

    NVDA uses a Modifier Key for a of their keyboard commands. This is normally the caps lock or insert key, but on a Mac:

    Use Karabiner Elements

    I tried a few options like Sharp Keys for getting a modifier key to pass through to Parallels, but couldn’t get the set-up right.

    What did work for me was creating a new keybinding for the init key using right option key using Karabiner Elements. To see how to best do that, use this guide from Deque and read the Option 3: Software – Karabiner Elements section.

    Other Helpful Settings

    A couple of these are also from the Deque guide, here for my own reference 🙂 All of them are optional!

    • Focus Highlight addon: Adds a focus-indicator for where NVDA is on the screen, similar to VoiceOver.
    • Speech Viewer: Similar to VoiceOver’s gray box transcript of what is being announced. (NVDA + n to bring up the NVDA menu) NVDA Menu > Tools > Speech Viewer
    • Turn off mouse tracking: NVDA announces whatever your cursor is on. If you’re using a mouse a lot still, then it ends up being a lot of announcements, and will continue after you switch back to your MacOS desktop. Turn it off with (NVDA + n) NVDA Menu > Preferences > Settings > Mouse > Enable Mouse Tracking (uncheck).

    Now you’re ready to learn some ways to use the modifier NVDA key. I’d also recommend downloading Firefox, as it pairs well with NVDA, similar to how VoiceOver works best with Safari.

  • If It Looks Like a Duck: A Cautionary Tale

    “If it looks like a duck, swims like a duck, and quacks like a duck, then it’s probably a duck.”

    I recently worked on putting a plan together for improving the accessibility of a search component on WordPress.com. The existing interaction worked like a combobox where the focus was kept on the search input and you could navigate through the results with the down/up arrows.

    Search input with focus and the up and down arrows pressed to move between selecting search results/
    The WordPress.com search suggestions component.

    If It Looks Like a Duck, Swims Like a Duck, […], It’s Probably a Duck.

    I looked at this input focus with arrow keyboard navigation and thought this should be marked up as a combobox.

    A combobox is a semantically linked input with a list of options within a listbox

    An expanded combobox with DOM focus on the input and virtual focus on the dropdown listbox.
    See this combobox in action.

    The interaction for a combobox is very similar to the interaction of the WordPress.com search suggestion component.

    • Focus remains on the input at all times
    • UP and DOWN arrows navigate between items
    • ENTER selects the item

    As I considered it more, there were a couple differences in the behaviors:

    1. A combobox should fill out the input with that text. So, selecting “Durian” from the options should fill out the input with “Durian.” In contrast, the WordPress.com search item selection would open a modal or go to a new page.
    2. A listbox cannot contain interactive items. The WordPress.com search items were interactive <a> or <button> elements to open a modal or bring you to a new page.

    In essence, it looked like a duck and it swam like duck, so I initially jumped to calling it duck. But, it didn’t quack like a duck. I incorrectly relied on a visual model to impact how I labelled it, instead of looking at its core purpose.

    HTML Markup Should Not Rely On The Visual Representation Alone

    I know this. I’ve written about it. But I initially didn’t take the extra time to take a step back and really consider what the core purpose of this component was and how it should be communicated via HTML. This was me, with as many good intentions as possible, being influenced by my own ableist, sighted-centric lens.

    If I had implemented a combobox to improve the accessibility, I would have felt good since I had done so much work, while simultaneously not making a difference (or potentially making it worse) for assistive technology users.

    Note
    I would have caught that it was a bad implementation for ATs, as I do test regularly with VoiceOver and/or NVDA while working. But I may not have caught it until after getting it to a working state and then needed to backtrack.

    This Duck is a Search with Dynamic Results

    The WordPress.com search suggestions component isn’t a combobox. It’s a miniature search with a <ul> list of dynamic results. The current plan on how to fix this is to:

    • Add a role="search" with an aria-label to the search form. This will reveal it as a landmark to ATs (Assistive Technologies).
    • Use speak() to announce when there are newly loaded results, loading, and error states.
    • Markup the search results as a <ul> with a heading when appropriate.
    • At times, there will be multiple <ul>s to group results. These results will be wrapped in a <div aria-label="Search Results"> in order to communicate the entire section as a group of results connected to the search input.
    • Remove the input DOM focus arrow key navigation. Search results will be TAB‘d to like normal links.

    In the end, by considering what the component is and not how it looks, we are able to:

    • Significantly simplify the code
    • Reduce the weight of the JS
    • Communicate the search component appropriately to ATs
    • Save time over implementing a far more complicated (and not as successful) combobox

    Remember to Keep Yourself in Check

    If you are an able-bodied individual, it’s important to do the work to keep your perspective in check. Don’t say, “It looks like a duck, it’s probably a duck.” Take the time to consider a component’s purpose and how it will be communicated before moving forwards.

    You’ll make mistakes (I certainly do). It’s OK. Keep listening, learning, and fighting the good fight. ♥️

    Major props to Diego Haz for his help working through the best markup and interactions on the search component.

  • Podcast Player block: Behind-the-Scenes Accessibility

    Podcast Player block: Behind-the-Scenes Accessibility

    On my team at Automattic, we built the new Podcast Player block released in Jetpack 8.5 and on WordPress.com. This post is intended to give you a behind-the-scenes style look at all the little details that went into attempting to provide a good, accessible experience for everyone.

    I’ll be focusing a lot on Screen Reader-specific considerations, using plenty of VoiceOver gifs and images.

    To get started, here’s the block in action:

    Episode 29: Dylan Field, Figma Co-founder, Talks Design, Digital Economy, and Remote Culture with Host Connie Yang Distributed, with Matt Mullenweg

    The latest episode of the Distributed podcast pairs Dylan Field, Figma’s CEO and Co-founder, and guest host Connie Yang, Head of Payments Design at Stripe. Join a discussion on design, instilling remote culture, and the digital economy, including Field's perspective on the role of design in technology. “We’ve gone from a physical economy to a digital economy. I don’t think these are new trends or new things that happen but now, all of a sudden it happened all at once, and accelerated massively,” he says.
    1. Episode 29: Dylan Field, Figma Co-founder, Talks Design, Digital Economy, and Remote Culture with Host Connie Yang
    2. Episode 28: Erica Pandey of Axios on Returning to Work
    3. Distributed by Default: Matt Mullenweg on The Knowledge Project
    4. Episode 27: Leading with Values: Sid Sijbrandij joins Matt Mullenweg to talk about GitLab, Transparency and Growing a Distributed Company
    5. Hiring For Distributed Companies & Angel Investing: This Week in Startups with Jason Calacanis

    I’ll break down each decision made related to accessibility:

    • Titles
    • Description
    • Playlist Markup
    • Communicating State
    • Feedback on Actions

    One Title or Two?

    At the top of the player we have two titles:

    1. Track Title: 396 – This Day in Esoteric Political History
    2. Podcast Title: 99% Invisible

    Screen readers can navigate by headings. We could mark these up as two separate titles, but one heading would be immediately followed by another. Grouping them provides a heading that accurately describes the podcast player’s state: “[track title] – [podcast title]”

    Headings link rotor displaying the headings on the page.
    The link rotor on the Headings section provides a one-heading label to navigate to the player.

    Positioning the Description

    Although the description is visually placed underneath the player, it’s contextually related to the heading. A screen reader will follow the DOM, so this would end up being read as:

    • Player Title
    • Audio controls (play, slider, etc)
    • Track description

    Semantically, it makes more sense for this to be arranged as:

    • Player Title
    • Track description
    • Audio controls (play, slider, etc)

    So that’s how I structured the DOM. I write the HTML as the ideal semantic flow, then use CSS to match the design.

    In this case, we’re using display: flex; with an order: 99; on the description to reposition it visually after the player. This isn’t ideal, as it can be bad to rearrange the visual part of the DOM when it’s related to focus order. In this case, I think it’ll be OK since the description isn’t focusable.

    Playlist Context

    The playlist is an <ol> with a list of <a role="button">s. Don’t worry, we used <a> with role="button" to provide a progressively enhanced player and implemented a SPACEBAR press to activate the button.

    However, a list of buttons doesn’t provide a lot of context as to what those buttons are for. To address this, we’ve added a hidden <h3>Playlist: [podcast title]</h3> and paragraph description of the playlist and attached this as an aria-labelledby and aria-describedby on the <ol>.

    Playlist with current track highlighted and "[track title], current item, button, [podcast title], group" in the screen reader area.
    Providing context to the playlist via `aria-labelledby`. Note the “Playlist: 99% Invisible, group”

    Now when you enter the playlist, you’ll be told that you’re on a button in the context of “Playlist: [podcast title], group.”

    Communicating State

    I had originally marked up the track list as role="menu" with role="menuitemradio" to communicate the currently selected track. After I built and tested this, it turned out this was a bad idea.™

    Basically, VoiceOver assumes that the menu is close-able, so it announces some extra information like, “Press escape to close this menu,” which isn’t accurate in our case. While the role="menu" and role="menuitemradio" seemed like a good choice according to WAI-ARIA specs, it wasn’t a good choice in practice.

    After using the aria-labelledby and aria-describedby on the playlist <ol> to designate the list as a group, we can use aria-current to signify which item is currently selected.

    Screen readers are supposed to announce the aria-current value, so aria-current-"track" should announce “[track title], current track, button.” In VoiceOver, it announces “[track title], current item, button.” Still pretty good.

    Playlist with current track highlighted and "[track title], current item, button, [podcast title], group" in the screen reader area.
    Note the “current item” text in the gray box.

    Playing: [Track title]

    When the track is playing (not just selected), it will visually have a playing icon next to it.

    Navigating the buttons with the screen reader to see that the current track displays "Playing: [track title]"
    Using an icon to indicate that the track is playing.

    These icons did not have a title before, so even though there was an additional visual cue for the current track state, this was not accessible to a screen reader.

    To address this, we added a visually hidden label so it will announce, “Playing: [track title], current item, button.”

    It can be argued that this label is unnecessary since if it’s playing, you should be able to hear that the track is playing. But, what if you have your speakers off? What if you muted the player? By providing this additional label, we can make sure we’re doing all we can to communicate the current state of the player.

    What just happened? Providing Feedback on Actions.

    Loading

    Screen reader showing "Loading: [track title] [track description]" when a new track is selected.

    When a new track is selected, we use WordPress’s speak() function to immediately announce, “Loading: [track title] [track description].”

    Before this, it would not give any kind of immediate feedback when you pressed a track button. Thus, if it took a long time for the track to load, you’d be sitting with silence not knowing if anything had happened.

    Now, there’s immediate feedback that:

    1. The track is loading
    2. What track is loading
    3. The track description (as it’s new content on the screen and would not be read otherwise)

    Note: VoiceOver users can press ctrl to silence the message if they don’t want to hear the full description.

    Playback Error

    The visual error message has a link in it that says “Open in a new tab.” Screen readers can use the rotor to navigate links. When doing this, you are presented with an “Open in a new tab” link that doesn’t provide any context to what you’re opening in a new tab.

    Link rotor showing "Open in a new tab" link that has no context.

    We’ve added a visually hidden podcast title in the link so it will show as “[podcast title]: Open in a new tab.” You can see this in the gif below in the bottom left gray box when the screen reader focuses the “Open in a new tab” link.

    focusing the "open in a new tab" link prepends the visually hidden track title.
    Open what in a new tab? “[track title]: Open in a new tab” provides context. The error is immediately announced as well.

    Also, when an error occurs from not being able to load the track, we use speak() to immediately announce an assertive error message to inform the user an error has occurred. Without using speak() there would have been no feedback that an error had occurred.

    Paused

    While this one may not be 100% needed since there’s feedback from the track no longer playing, when I tested this out I felt like it was helpful to be overt about what just happened.

    Button press announces "Paused"
    When pressing a button on a track that is currently playing, it will announce that the track is paused.

    This uses speak() to announce “Paused” when the currently playing track button is pressed.

    Final thoughts

    • Before I went down too many aria rabbit holes, I should have tried building a few sample markups and then tested them with a screen reader.
    • While writing this, I kept catching myself referring to these implementations as screen reader “enhancements,” but providing a good baseline experience for the way people interact with a website shouldn’t be an “enhancement.”
    • My brilliant co-worker, Haz Diego, mentioned that role="grid" would have worked well here in order to use the roving tabindex method (where you can tab to the list of tracks, but use arrow keys to navigate them) while still providing a generic grouped state for the playlist. I agree that this could have been a great option for this.

    This implementation likely still has some issues, but I can promise that we did our best. If you have thoughts on how we could improve this, let me know in the comments or by opening an issue at the Jetpack Github repo.

  • The 5 Minute Accessibility Audit

    The 5 Minute Accessibility Audit

    Being great at something takes a lot of dedication and practice. But, you can often be OK at something without too much difficulty.

    This article is to help you with the latter part. Knowing just enough to be able to make an educated guess on the accessibility of a site or component/plugin.

    Can you use the site with a keyboard?

    When using a keyboard, you need to know where you’re at on the page. A focus indicator is a visible outline to show you what element you’re interacting with.

    Solid focus ring moving around on Twitter's desktop view sidebar menu.
    Focus indicator on Twitter’s Navigation

    To test the keyboard interactions:

    1. Load a page
    2. Press the tab key.
    3. Can you see a focus indicator to let you know where you are on the page?
      • If yes, then keep on pressing tab!
      • If no, then it fails. 😥You can be pretty confident that the developers did not consider accessibility when building the site.

    Note: Sometimes you use the arrow keys to interact with things as well, like on radio buttons or settings menus.

    If you can see the focus when tabbing and then you can’t access something, try the arrow keys to see if the focus moves where you want to go.

    Being able to use a keyboard for everything on the site is the biggest, quick indicator that the site has been built with accessibility in mind.

    Skip to Content Links

    When you navigate with a keyboard, you may see a “Skip to Content” link pop up. This is a good thing, and when you press it, it will move your focus to the main content of the page.

    Pressing the "Skip to the content" link on this site to move focus to the top of the Accessibility 101 for Content Creators article.
    Skip to Content links are great to avoid tabbing so much before reaching the content.

    This is really helpful, as it allows you to skip all the navigation links usually found in the header of a site, and, as the name indicates, skip you to the content.

    Zoom, Zoom!

    Zooming in several levels to show the text getting better and the content reflowing to fit the space.
    Zooming in on The A11Y Project keyboard navigation article.

    When you zoom in on a page, the text should get larger and the site should reflow to fit the available space.

    On a Mac, you can zoom with ⌘ Command and +. Press ⌘ Command and 0 to reset the zoom.

    Most sites built with Responsive Web Design (RWD) in mind should allow for this. RWD is when a site is built to accommodate any screen size and still look good.

    Evaluate the Color Contrast

    If you see light gray text on a white background (or another difficult-to-read color combination), it’s likely that the people building the site did not consider (or, worse, actively dismissed) accessibility. If it’s hard to read for you, it probably doesn’t have enough color contrast.

    Form Inputs Should be Labelled

    56% of the 3.4 million form inputs identified were unlabeled.

    Jared Smith, WebAIM Million – One Year Update

    A label tells you what the field is for. Take these two sign-up forms from WordPress.com and Spotify.

    WordPress.com new account form. Each input is labelled clearly: Your email address, Choose a username, Choose a password.
    Each field/input is labelled clearly.
    Sign-up form using light gray placeholder text for each input. There are no visible labels.
    Spotify’s new account form does not have visible labels. A placeholder is not a label, since it disappears after you start typing.

    The WordPress.com one is great. Each field is labelled clearly.

    The Spotify one seems like it’s labelled. You can see the “Email,” “Confirm email,” etc, but those are actually placeholders. A placeholder isn’t a label for two reasons:

    1. It disappears after you start typing. You might not remember what you were supposed to put there.
    2. A placeholder is supposed to show you an example of what you should put in the field. So, for an email field, an appropriate placeholder would be “example@gmail.com,” not “Email.”
    Spotify sign-up form with one of the fields focused with the text "What was this field for again?" There is no label on the input, so there's no way to know.
    Do you remember what that field was for? If it had a label, you wouldn’t have needed to remember. 🙂

    A label being visible doesn’t mean it’s fully accessible, but there’s a good chance it is. If you want to dive a little deeper, you can learn how to label an input in HTML.

    For this quick accessibility audit, check if all fields have a visible label. If they are, awesome. 🙌

    Note: One common exception to this is search fields.

    A field does not need to have a visible label if the context makes it obvious that it’s a search (like having a big button called “search” next to it).

    5 Minute Accessibility Audit Checklist

    • Can you navigate/use it with a keyboard? The focus indicator should always be visible. A Skip to Content link is a bonus.
    • Does the zoom work? Zooming in on the site should increase the size of the text, and the site should still work correctly.
    • Does the text have sufficient color contrast? Everything should be easy to read.
    • Do all form inputs have labels? Not placeholders, but labels. The label should be visible even after entering text. A search field is an exception.

    Doing this audit has served me well when I need to quickly evaluate a site, theme or plugin for baseline accessibility. It’s not perfect, but it allows you to make an educated guess on if accessibility was considered or not.

  • Learning via Terrible Ideas: Replacing Text on Click, Part 2

    Learning via Terrible Ideas: Replacing Text on Click, Part 2

    In Part 1 of Learning via Terrible Ideas, we learned how to:

    • Open the Console
    • Set a variable
    • Add a Click Listener

    But adding a click listener doesn’t make it accessible to people who use a keyboard or different kind of assistive technology.

    To make our example accessible, we’ll need to:

    • Give a “focus indicator” to everything. A focus indicator is the little glowing outline to show you where you are on the page. Press the TAB key now, and you’ll get moved to the next “focusable element.”
    • Make everything that is clickable via a mouse be able to be “clicked” with a Spacebar or Enter keypress.

    Making Everything Focusable

    Entering code and tabbing through the elements to show the focus ring moving.

    To make this Terrible Idea™️ accessible, we’ll need to give everything an attribute of tabindex="0". This adds it to the “focus order” which makes it able to be focused.

    Note: It is common for websites to not have any focus indicators. If you TAB through a site and it doesn’t show you where the focus is, then that is Bad.™️

    To give everything a tabindex attribute, we need to:

    1. Get all of the elements on the page.
    2. Loop through each of the elements.
    3. Add the tabindex attribute to each element.

    Open your Console like we did in Part 1 (right click on the page -> Inspect -> Console tab). Now enter these lines in the console:

    // Get all of the elements on the page.
    var elements = document.querySelectorAll( 'body *' )
    
    // Give each element a tabindex of 0. 
    elements.forEach( e => e.tabIndex = 0 )
    

    Note: Lines starting with // are comments to help you out. You don’t need to type them. You can, but you don’t need to.

    Now move focus back to the page (a “click” anywhere on this post will do). Press the TAB key a few times. You should have the focus moving between elements now.

    Add a keydown Listener

    Adding code in the console, then clicking to the page and tabbing to elements. Each keypress changes the focused element's text to "Daddy eats fart popsicles."

    In Part 1, we added a click listener. This made something happen each time we clicked on the page. We can “listen” for things other than click events as well.

    To make something happen on a keypress, we add a keydown listener. As soon as a key is pressed, it will run our code.

    // Set our phrase from Part 1
    var phrase = 'Daddy eats fart popsicles'
    
    // Add the Keydown Listener.
    document.addEventListener( 'keydown', e => {
      // if our keypress is a Space or Enter key, change the phrase
      if( e.code === 'Space' || e.code === 'Enter' ) {
        e.preventDefault()
        e.target.innerHTML = phrase
      }
    })
    

    Play Around!

    Now if you press TAB you should see the focus move to the next element. You can use Shift + TAB to move focus backwards. The highlighted focus indicator will show you the element you’re on.

    Each time you press Enter or Space, your element should get its text changed to whatever the phrase equals.

    What’s Next

    Part 3 is coming up. We’ll go over two things that bring a ton of power to JavaScript: arrays and functions.

    Be sure to follow me on Twitter or sign up to my email newsletter to find out when Part 3 is finished.