The next big jump in Basecamp accessibility!

How we made the Basecamp 3 Jump Menu accessible

The Basecamp 3 Jump Menu

Earlier this year I wrote about How we stopped making excuses and started improving Basecamp’s accessibility. Accessibility improvements in Basecamp 3 have come in two ways: All new features we’ve shipped over the past year and a half have been designed and tested to meet WCAG AA guidelines (The Web Content Accessibility Guidelines, or WCAG, provides a shared standard that web developers can follow to make sure their products are accessible).

At the same time, we’ve gone back and retrofitted existing features and interactions for better accessibility. Today I’m excited to announce that we just completed some significant improvements to the Basecamp 3 Jump Menu!

The jump menu has always been the quickest way for getting to a person, project, recently visited page, and My assignments/bookmarks/schedule /drafts/latest activity. Here’s a look at it in action:

Note the small-ish “Press ⌘+J to show the menu” label

In setting out to make the jump menu more accessible we identified a few specific areas in need of help.

1. Provide an alternate way to trigger the menu

The ⌘/Ctrl + J shortcut for opening the jump menu isn’t communicated in a non-visual way, and initiating multi-key commands can be difficult for people who have motor function challenges.

To improve this, we added a button-based trigger, implemented as an invisible button that appears when someone first presses their tab key after loading up Basecamp. This technique is very similar to the common “Skip Navigation” link technique used around the web (we added one to Basecamp at the end of last year).

The Show Jump Menu button. We used the opportunity to reinforce the keyboard shortcut for those who prefer using it to open the menu.

2. Clear non-visual instructions for how to interact with it

As a visual user it’s fairly obvious how the jump menu works: We show the placeholder “Jump to project, person, or recently visited page…” with a blinking cursor, and a list of entries below it that filters down as you type.

To clarify this interaction for customers using a screen reader, we created a visually hidden <span> element with more verbose instructions, “Type to filter and use the up and down arrow keys to navigate this list of people, projects, and recently visited pages.”

3. Announcing the selected item and number of results as you filter

If you’re using a screen reader to filter through a list, how do you to know how many items are listed as your search term increases? And which item is selected as you arrow up/down or tab to navigate through the list of results?

This required the use of some specific HTML markup and JavaScript to convey this information to the Accessible Technology (such as screen reader software) that I’ll go into below.


The first step in making a complex element like this one accessible is doing some research. We look for examples of similar elements from around the web for inspiration and guidance on the proper markup to use. The W3C WAI-ARIA examples site (get ready for a long one! “World Wide Web Consortium’s Web Accessibility Initiative (for) Accessible Rich Internet Applications”) is a great place to start. The second example on their Combobox with Listbox Popup Examples page, “List Autocomplete with Automatic Selection,” seemed most similar to the behavior of our Basecamp jump menu.

Authoritative as this site may seem, it’s worth testing the examples on real screen readers. There’s an abundance of quirks across screen reader + web browser combos that means these examples often don’t work quite as expected. When that happens, additional code is often required to get screen reader announcements to fire in the way you’d like. Expect lots of trial and error 😊

The implementation we settled on uses the aria-activedescendant property. This technique provides a way to keep DOM focus on the <input> while updating your selection as you move through the list of results. This is the key that allows the screen reader software to understand what’s happening on the screen. Here’s a look at the final product in action, followed by all of the dynamic and static attributes we used to get this working. For further reading about these attributes check out the W3C article linked above where many of the following definitions are borrowed from.



  1. On the combobox container <div>, our <bc-content-filter> element:
  • role="combobox": This identifies the element as a combobox.
  • aria-haspopup="listbox": This indicates that the combobox is associated with a pop up list of suggested values.
  • aria-owns="jump-menu__results": This associates the combobox with the results container.
  • aria-expanded="true": This indicates that the associated results listbox popup element is displayed. Since in our case the list of results is always shown when the jump menu is shown, we don’t need to toggle this attribute. If it only appeared after some text was entered, we would need to toggle the attribute between this and aria-expanded="false".

2. On the text box <input>:

  • aria-autocomplete="list: Indicates that the autocomplete behavior of the string that’s entered is to suggest a list of possible values in a popup.
  • aria-labelledby="a-jump-menu__description": A sort of backup label for instructions on how to use the jump menu.
  • aria-controls="jump-menu__results": Points to the popup element that lists the suggested values.
  • Dynamic attribute: As up/down arrow keys or tab are used to navigate the list of results JavaScript is used to update the value of aria-activedescendant="IDREF" with the ID of the focused item.

3. A non-visible status <span> to communicate the number of results (e.g. “Home, 1 of 14”). Making it an aria live region with role=”status” and aria-live=”assertive” ensures that the screen reader will immediately speak any new text content that gets pushed into it. Just make sure the <span> is present in the DOM before pushing text into it, or it won’t work!

  • id=”a-jump-menu__status”
  • role=”status”: A type of aria live region used for conveying advisory information.
  • aria-live=”assertive”: This makes sure that when the selection changes, announcing it takes priority over anything else the screen reader might be saying.
  • Dynamic attribute: When the jump menu is first rendered we inject the name of the auto-selected first item in the list followed by the directions for using the widget (“Type to filter and use the up and down arrow keys to navigate this list of people, projects, and recently visited pages”). As you arrow/tab through the list of entries, we use a helper to update the contents of the span to again communicate the current selection, followed by your current location in the list, for example “Management team project – Match 2 of 3”.

4. Another hidden description <span>, referenced by aria-labelledby, provides a better description for how to use the jump menu than the visual placeholder:

  • id=”a-jump-menu__description”
  • Text content: “Type to filter and use the up and down arrow keys to navigate this list of people, projects, and recently visited pages”

5. On the listbox results container <div>:

  • id=”jump-menu__results”: Used as a reference by the combobox element.
  • role=”listbox”: Defines it as a container for the list of results.

6. On each <article> element in the list of results:

  • A unique id for each result in the list.
  • role=”option”: This defines the element as a listbox option.
  • Dynamic attribute: Using JavaScript we set aria-selected=”true” as you move through results. This correlates with when the item is referenced by aria-activedescendant on the <input>.

We also use some additional JavaScript to generate and set the “Match X of Y” status text:

I hope this walkthrough was helpful! I would have loved to see more examples like this one as we were building the feature out. If you have any questions, please let us know!

How we stopped making excuses and started improving Basecamp’s accessibility

In 2017 we made web accessibility a priority at Basecamp. It was long overdue.

Over the past year, I made it a personal mission to make Basecamp 3 more accessible for people with disabilities that affect how they use the web. It’s something we’d been meaning to focus on at Basecamp for a while. But as with many unfamiliar and seemingly immense tasks it was just too easy to put off! Which is exactly what we did, for years.

In the end, it took the mix of a personal search for meaning, the reward of learning something new, and a bit too much downtime to finally make some progress.

Excuses had been easy to find. “Why spend time improving something that only a seemingly small subset of our customers would benefit from?” After all, we’ve always found it important to say no to feature requests that could bloat the product or be useful to only a slice of our customers.

Making Basecamp accessible was different, though I didn’t realize it at first. Back in early 2017, I was about to hit my eight year anniversary with Basecamp and the itch for a new challenge was real. I needed to find something I could learn and grow around, and at that, a project which possessed some inherent meaning. Not to discount the value of the quality assurance (QA) work that I’d been doing at Basecamp for the last five or so years — I know these efforts have a real impact on a tool that lots of people use to run their projects. But there’s just enough of a separation between me and them to dilute the potential energy of that truth. I needed to find something with more resonance.

I had recently experienced firsthand the compromising effects of losing one’s eyesight, and learned about some of the assistive technologies available to help. My grandmother, an avid reader throughout her life, was suffering from macular degeneration. It became impossible for her to pick up a book or newspaper as she’d done for so many years. But with the aid of a digital talking book player provided by the National Library Service and an enlarger acquired through The Chicago Lighthouse, she was able to retain her independence and connection to the outside world.

Our QA process at Basecamp could be described as a “black box” or exploratory affair. QA doesn’t generally participate until a feature has been built-out to the point where it can be used like a customer would. Only then do I storm in with my fellow QA’er Ann Goliak to hammer on what the development team has been cooking up. We search for bugs and evaluate the new feature from the perspective of a customer. Our fresh eyes can often spot things the deeply embedded development team cannot.

Then, since we work on a schedule of six-week development cycles, the feature ships, a new cycle begins, and our bug-hunting frenzy is often followed by a whole lot of downtime for team QA. It was during one such lull back in early 2017 that I finally gave in, flipped on VoiceOver (Apple’s screen reader built into macOS) and started pressing tab on my keyboard to navigate though Basecamp. And then I cringed listening to the confusing way each item on the page was being described by the screen reader 😬

As I found things that didn’t seem right during that initial run through I started making to-dos in our “Basecamp 3: Bugs” project in Basecamp, like we do for all bug reports. But back then I didn’t actually know how a given element, like a simple button, was best described to someone using a screen reader, nor which keyboard interactions were expected to go along with it. I quickly realized that if I couldn’t clearly communicate to my colleagues what specifically needed to be tweaked, the likelihood anyone would pick up these bug reports was slim. No one likes being assigned a research project!

So I took on the necessary research to understand what the Web Content Accessibility Guidelines (WCAG) defined as the proper and expected way that any given thing on a web page should look and behave in order to be accessible. I opened up my code editor, made some tweaks, and tested locally to see if I was on the right track. I was actually implementing these fixes! And they actually worked! I had dabbled in a couple of Rails and other programming courses over the years, though never with much traction. Now I finally understood the satisfaction that comes from writing software code – and I was hooked.

Incorporating feedback about web accessibility into our existing QA process is in large part why we we’ve been able to build traction. During new feature development, we treat accessibility concerns just like any other type of bug. Over time, these bits of technique help to inform our designers and developers how to build with a focus on accessibility from the start.

Several years back during an all company meet-up one of our designers, Jason Zimdars, played a recording that a customer had made to demonstrate using Basecamp with a screen reader. It was both enlightening and incredibly embarrassing that this aspect of product quality had completely escaped us. A few years later, one of our interns Nathan Petts conducted a general screen reader evaluation, once again highlighting many areas where we were coming up short. Both would spark the conversation about accessibility improvements, but each time the result quickly became a huge pile of problems with no clear place to start. We would make a few tweaks, then shelve the topic for another couple of years.

In contrast, over the past year all new features we’ve shipped have been designed and tested to be accessible!

I’ve started making screen reader walkthroughs to show my colleagues the accessibility issues with our existing features and elements. I share these demos as pitches, like this one for accessible autocomplete elements.

We still have a ways to go before Basecamp 3 can be declared fully accessible. But I can say with certainty that everyone at the company agrees how important it is that we make time for these improvements.

I have gratitude for being with a company like Basecamp that values the space and autonomy for ongoing learning and growth. This made it possible for me to jump from customer support to QA back in 2011, and now it’s created the circumstances for this new undertaking in web accessibility.

In future posts, I’ll share some of the specific tweaks we’ve made to make Basecamp 3 more accessible, and the techniques we used to get there.

If you have specific questions, or want to hear about something related that I didn’t cover, add a comment and I’ll be happy to share more details down there or in a future post. Thanks for reading!