As a developer working on a chat API, I naturally want to make sure the chat is accessible for as many users as possible. I also have a personal interest in accessibility, because I‘m visually impaired, and often use the web with a screen reader, especially on mobile.

And chat apps can be quite challenging beasts, even in the world of rich web applications. You’ve got people writing messages, sending voice notes, quoting and replying, giving emoji reactions—often in multiple channels and with several conversations going on at the same time. Chat is dynamic and interactive. All of which makes it comparatively quite a bit harder to get accessibility right for chat.

In this article, I’d like to share how, at TalkJS, we approach chat accessibility in a small team of developers. While I’ll mainly focus on screen reader accessibility and keyboard navigation, we'd be happy to hear any accessibility feedback you might have in any areas that matter to you.

Gaps in accessibility guidelines

When you’re working on anything to do with accessibility on the web, you’ll encounter plenty of guidelines on how to get things right. Think of the Web Content Accessibility Guidelines or initiatives from the A11Y project.

What you’ll also learn is that these accessibility guidelines are (mostly) made for websites that serve (mostly) static content. Many of the standard checklists for accessibility are heavily document-focused. They might get you to check things such as whether all elements have sufficient contrast, or whether all images have alt attributes. But a chat app is a way richer type of application. When people are sending each other messages and files across a dozen conversations, you don’t just have static text to work with, or even a bunch of menus and buttons. You have a lot of moving parts, and things continuously change.

As a result, many accessibility checkers and guidelines don't translate particularly well to applications. Take the Accessible Rich Internet Applications (ARIA) specification, which defines a standard for making web content and web apps accessible. Much of the ARIA specification centers around standard UI elements. But how would, for example, the list of conversations next to a TalkJS chat inbox even map to one of these UI types?

When you work on rich, dynamic applications, you run into a gap between the focus of many accessibility guidelines and the reality of what you are building. If I were to run one of these accessibility checks on our TalkJS chat app, we could probably work on getting full compliance to that specification. Yet … that still would not mean that we are properly accessible.

That gap between guidelines and reality means that if you want to ensure that your app is actually accessible, you’ll have to dig a bit deeper and think through a lot of points yourself.

Developer tools and expert forums

As a small team of developers (just 18 people at the moment), we're no Microsoft with a massive research department. So what do we do? A common strategy to figure out what works and what doesn’t, is to see how others solve your issue. Such research will likely involve a lot of searching, inspecting various technical implementations, as well as talking to people in forums with subject matter experts.

For example, I’ve recently been focusing on the accessibility of the conversation list of the inbox widget of our TalkJS chat, which is the list of conversations that a chat user is part of at any time.

Overview of a conversation list in the inbox of a TalkJS chat. On the left a frame with at the top a toggle with ‘Desktop Notifications’, below which there is a list with four conversations related to job applications. A second, larger frame on the right shows the contents of one selected conversation, relating to an application for a full stack web developer position.
A conversation list in the inbox of a TalkJS chat

To get the conversation list right, I've investigated other apps that also give you a list of conversations, such as WhatsApp, Facebook Messenger, or direct messages on X (formerly known as Twitter). You can learn quite a bit just from looking at how their screen reader or keyboard navigation support is implemented. For example, personally I found Twitter DMs quite hard to navigate with a screen reader. Whereas Facebook Messenger will give you some quite nice UX, showing you small popovers for the keyboard actions you can perform. For instance, it gives you a popover with ‘Chat information’, for more information about the selected chat, ‘Enter’ to enter a conversation, as well as ‘Reply’, ‘React’, or ‘More’ for further actions.

Browser inspector tools can be a huge help when investigating solutions and best practices. For instance, Firefox’s Accessibility Inspector gives you an easy-to-find accessibility tree, with information related to accessibility for most HTML elements. And Chrome DevTools has a very nice accessibility tree that will give you the interface for a screen reader, which indicates which attributes the screen reader will pick up on, such as where there’s a button, or what label will be announced. I’ve looked at many, many chat applications using these developer tools, to figure out how they structure things.

Ask people, don’t make assumptions

Plus, another thing that anyone working in a small dev team can do is to ask questions in online forums where people with various disabilities hang out. There are many places where you can find people with various ways of using applications and various user needs. So far, I've asked a bunch of questions in r/Blind, the Reddit community for blind and visually impaired people, as well as on Mastodon and Twitter using the #a11y hashtag, or in a Discord server specifically for visually impaired users.

The most important thing is not to make assumptions about what might or might not be helpful without asking someone. Just go out and talk to people. If you’re entering a community of blind and visually impaired people as a sighted person who wants to learn or gather feedback to make something more accessible, then do make that clear. The r/Blind subreddit has an FAQ for sighted readers and a README for people wanting to make assistive devices software, both of which may already answer your question. So be respectful of people's time.

Conversation lists and typing indicators

In my recent work on accessibility improvements to our TalkJS chat, I have focused on several things. By far the biggest part of my work has been the chat conversation list. Take, for example, keyboard navigation. With keyboard navigation, you want to be able to navigate around the user interface with your keyboard, without having to rely on screen taps or mouse clicks. (Incidentally, I’ve noticed that more tech savvy users tend to be more likely to use keyboard navigation, even when they wouldn’t strictly need it for accessibility purposes.)

How would keyboard navigation work well on a conversation list? With a huge list of conversations, you don't want to have to tab through every single post within every single conversation before you get to the field where you can type your message. That would be totally cumbersome. To avoid this, I put the conversation list itself into a KeyboardNavigationList component. As with any other interactive element on a page, you can just press Tab to move into the keyboard navigation list, and use the up and down arrows to move the keyboard focus from one conversation item on the list to the next. To actually switch into another conversation, you just hit Enter.

Example of focus changes when using keyboard navigation to go through a channel and conversation list in the inbox of a TalkJS chat. A blue outline indicates which element is in focus. Initially the focus moves through the channels and direct messages in the inbox frame on the left. Next, the focus moves into a conversation, sends a message, and moves through the options to share your location, add a file, respond with an emoji reaction, or record a voice message.
Changing focus when using keyboard navigation in a channel and conversation list

In addition to keyboard navigation of conversations, I would also like to improve our screen reader announcements when new messages come in. And I definitely want to make sure that all of our icons are properly labeled.

One tricky point with labeling for chat is the typing indicator, which indicates that someone is typing a message before they’ve actually sent it. Visually, we indicate that someone is typing by displaying the person’s name with a little three-dots animation in the place where their message will show up. But of course visual animations won’t cut it for screen readers; they need a textual representation.

Currently our typing indicator does not have a label, which is a shitty experience for screen readers. But we cannot just stick any random label on there. For proper accessibility labeling, you also need to consider how your label translates into all the different languages that your app supports (the TalkJS interface currently supports 38 languages, and counting!). In certain languages a sentence such as ‘Chris is typing’ would be gendered. Yet within our UI we try to avoid gendered language as much as possible—I definitely don't want us to add any unnecessary gender property to user objects. One option we’re currently considering for the typing indicator label is to state something like: Typing: <LIST_OF_NAMES>, but I want to delve deeper to ensure that this solution also works well in translation.

Accessibility infrastructure

Over time, with for example the keyboard accessibility features that I've built, we get some primitives that we can reuse throughout the application. As we expand our internal knowledge of how to make applications like ours accessible, we can build more of these primitives.

Further, there’s a whole bunch of open components out there that explicitly work on accessibility, which takes a lot of work off our hands. So that's why, for example, we use Reach UI components for things like our drop-down menus. Reach has already done the work to make their menus accessible, which means that we don't have to do the work to figure out best practices. That basically gives us accessibility infrastructure.

Accessibility debt

Like so many other apps out there, we do still have what I consider ‘accessibility debt’. Accessibility debt is when features were built with less consideration for accessibility, but still form a core part of the application.

Currently accessibility questions come up in our development process once a feature is in some stage of development and is being reviewed. At that point I’ll go over it from an accessibility point of view, to see if it has labeled icons, or if we can add, remove, or change things to make it more accessible. Because I don't want any more accessibility debt to build up, I’ll check any new code to try to make sure that any big new feature ships with reasonable accessibility.

Our review process is quite informal, and at least for us at TalkJS this works well. I'm not too keen on having an elaborate formal process with detailed checklists. At some point we might add checks to confirm, before merging a feature, whether keyboard navigation and screen reader accessibility have been considered. But at this point we’re still small enough that I'm personally aware of most big features that are going to be merged. Rarely does a type of UI get built where there is just no way to make it accessible.

Plus, it helps that TalkJS has developers that are motivated to improve accessibility. I never hear anyone complain or say: ‘Hey don't spend time on this’ when I bring anything up.

Sensible defaults

One challenge you face when providing chat software as a service (SaaS) is that we want to make the chat accessible, while also keeping it extremely customizable. To provide users a great experience, our customers should both be able to use the chat UI directly out of the box, or be able to completely change the markup within our chat, to tailor it exactly to their specific needs. To accommodate both approaches, we want to ship with sensible, accessible defaults, so that customers don’t have to do additional work to remove accessibility barriers.

For example, we’ve recently implemented default focus styles, where we set an outline on each focusable element when it gets keyboard focus. Customers can configure and override the defaults if they choose to. But having these focus styles as a default means that even if customers don't explicitly specify focus styles, the element still clearly shows when it gets focus.

By setting up good accessibility defaults in our preset themes, we try to remove as many accessibility foot guns as possible, and we can guide customers into keeping these things accessible. We’re basically providing the infrastructure to make it as easy as possible for our customers to deliver accessible chat.

Even with a small team and for something as dynamic and interactive as chat, there are quite some steps you can take to move further on the journey of getting accessibility right.


Do you have any accessibility learnings that you’d like to share? Or any accessibility feedback for us at TalkJS? Get in touch as we’d love to hear from you!

This article was written in collaboration with Chris Meyns.

You’ve successfully subscribed to TalkJS
Welcome back! You’ve successfully signed in.
Great! You’ve successfully signed up.
Your link has expired
Success! Check your email for magic link to sign-in.