{"id":18791,"date":"2018-12-05T17:39:38","date_gmt":"2018-12-05T17:39:38","guid":{"rendered":"https:\/\/www.intercom.com\/blog\/?p=18791"},"modified":"2020-07-30T12:54:47","modified_gmt":"2020-07-30T11:54:47","slug":"messenger-accessibility","status":"publish","type":"post","link":"https:\/\/www.intercom.com\/blog\/messenger-accessibility\/","title":{"rendered":"Building for everyone: How we made the Intercom Messenger accessible"},"content":{"rendered":"<p>Here at Intercom, our mission is to make internet business personal. But in order for an internet business to be personal, it must also be <em>possible<\/em> for everyone to access.<\/p>\n<p>More than one billion people worldwide live with a disability \u2013 that\u2019s more than <a href=\"https:\/\/www.audioeye.com\/resources\/accessibility-essentials\/\" target=\"_blank\" rel=\"noopener noreferrer\">15% of the global population<\/a>. Without assistive technologies like screen readers, the web is inaccessible or hard for them to use. Think of it this way: it\u2019s like entering your neighborhood coffee shop and if you\u2019re in a wheelchair, discovering that the counter is too tall for you to reach.<\/p>\n<p class=\"quote\">&#8220;We believe internet businesses should be able to communicate with everyone, regardless of how their visitors interact with the web&#8221;<\/p>\n<p>We believe businesses should be able to communicate with everyone on their website, regardless of how their visitors interact with the web. This isn\u2019t just a company philosophy; it\u2019s also an engineering commitment. To prioritize accessibility in <a href=\"https:\/\/www.intercom.com\/blog\/messenger\" target=\"_blank\" rel=\"noopener noreferrer\">our Messenger<\/a>, we took a hard look at the technical improvements we needed to make and turned what were often fuzzy requirements into real, meaningful solutions.<\/p>\n<p>What we achieved is making our web Messenger accessible and compliant with the <a href=\"https:\/\/www.w3.org\/TR\/UNDERSTANDING-WCAG20\/conformance.html#uc-conformance-requirements-head\" target=\"_blank\" rel=\"noopener noreferrer\">Web Content Accessibility Guidelines 2.0 Level AA<\/a>.<\/p>\n<h2 id=\"a-shared-framework-for-web-accessibility\">A shared framework for web accessibility<\/h2>\n<p>The <a href=\"https:\/\/www.w3.org\/WAI\/standards-guidelines\/wcag\/\" target=\"_blank\" rel=\"noopener noreferrer\">Web Content Accessibility Guidelines (WCAG)<\/a> are a shared set of technical standards that explain how to make web content accessible to people with disabilities. Its 12 guidelines are organized around four main principles, which provide the foundation for web accessibility:<\/p>\n<ul>\n<li><strong>Perceivable<\/strong>: Users must be able to perceive the content in some way, using one or more of their senses. For instance, images that convey meaningful information should have alternative text provided.<\/li>\n<li><strong>Operable<\/strong>: Users must be able to control UI elements. For example, all functionality like buttons and form elements should be accessible using keyboard controls.<\/li>\n<li><strong>Understandable<\/strong>: The content must be understandable to its users. That means things like the language of the page should be detectable in the code.<\/li>\n<li><strong>Robust<\/strong>: The content must be developed using well-known and adopted web standards. In other words, your code should be easily parsed and interpreted by different browsers and user agents like screen readers.<\/li>\n<\/ul>\n<p>Our engineering work started by exploring the WCAG guidelines and then identifying all the areas in our web Messenger that needed improvement. As we quickly learned, turning these four principles into real solutions was simpler on paper than in practice.<\/p>\n<h2 id=\"turning-fuzzy-requirements-into-real-solutions\">Turning fuzzy requirements into real solutions<\/h2>\n<p>The WCAG guidelines are extensive \u2013 across the four principles, there are nearly 100 sections \u2013 and some areas are quite fuzzy. Requirements like \u201cmeaningful sequence\u201d and \u201cfocus order\u201d are very broad in scope, especially for applications like ours that get embedded in many different environments.<\/p>\n<p class=\"quote\">&#8220;There wasn\u2019t always a direct or obvious correlation between the accessibility guidelines and what we needed to build&#8221;<\/p>\n<p>These fuzzy requirements meant there wasn\u2019t always a direct or obvious correlation between the WCAG guidelines and what we needed to build. We encountered issues that didn\u2019t have clear answers online, leaving it up to us to come up with the right technical solutions.<\/p>\n<p>In the end, we identified three main areas of focus for accessibility in our web Messenger:<\/p>\n<ul>\n<li><a href=\"#keyboard-nav\">Keyboard navigation<\/a><\/li>\n<li><a href=\"#screen-reader\">Screen reader support<\/a><\/li>\n<li><a href=\"#color-contrast\">Color contrast<\/a><\/li>\n<\/ul>\n<p><a id=\"keyboard-nav\"><\/a>I\u2019ll walk you through each of these areas, what we learned and the solutions we shipped.<\/p>\n<h2 id=\"improving-keyboard-navigation\">Improving keyboard navigation<\/h2>\n<p>Keyboard navigation is a very important part of making your app accessible. When visually or auditory impaired people use web browsers, they often rely on keyboard navigation to tab into fields and then have their screen reader read what action could be performed.<\/p>\n<p>Our work on keyboard navigation can be broken down into three main changes:<\/p>\n<ol>\n<li>Making elements clickable by keyboard<\/li>\n<li>Setting proper focus states<\/li>\n<li>Designing intentional focus traps<\/li>\n<\/ol>\n<h3>1. Making elements clickable by keyboard<\/h3>\n<p>The Intercom web Messenger is <a href=\"https:\/\/reactjs.org\/\" target=\"_blank\" rel=\"noopener noreferrer\">a React app<\/a>. If we want keyboard navigation to work with the Messenger, every <code>onClick<\/code> handler that is added to an element, <a href=\"http:\/\/websiteaccessibility.donaldevans.com\/2011\/06\/30\/when-does-onclick-work-with-the-keyboard-enter-key\" target=\"_blank\" rel=\"noopener noreferrer\">except the elements that browsers support natively<\/a>, also needs <code>onKeyDown<\/code> that checks if the enter or space keys were pressed and execute the same function as the <code>onClick<\/code> handler.<\/p>\n<p>Let\u2019s imagine a scenario where our component looks like this (These examples include React components using JSX. <a href=\"https:\/\/reactjs.org\/docs\/introducing-jsx.html\" target=\"_blank\" rel=\"noopener noreferrer\">You can learn more about JSX here<\/a>.):<\/p>\n<p><code class=\" language-jsx\" style=\"line-height: 1;\"><span class=\"token keyword\">export<\/span> <span class=\"token keyword\">default<\/span> <span class=\"token keyword\">function<\/span><span class=\"token punctuation\">(<\/span>props<span class=\"token punctuation\">)<\/span> <span class=\"token punctuation\">{<\/span><br \/>\n<span class=\"token keyword\">return<\/span> <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>div<\/span> <span class=\"token attr-name\">onClick<\/span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=<\/span><span class=\"token punctuation\">{<\/span>props<span class=\"token punctuation\">.<\/span>onClick<span class=\"token punctuation\">}<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span><span class=\"token plain-text\">Open modal<\/span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>div<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><span class=\"token punctuation\">;<\/span><br \/>\n<span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">;<\/span><\/code><\/p>\n<p>In order to make this component keyboard accessible, we can convert it to a button:<\/p>\n<p><code class=\" language-jsx\" style=\"line-height: 1;\"><span class=\"token keyword\">export<\/span> <span class=\"token keyword\">default<\/span> <span class=\"token keyword\">function<\/span><span class=\"token punctuation\">(<\/span>props<span class=\"token punctuation\">)<\/span> <span class=\"token punctuation\">{<\/span><br \/>\n<span class=\"token keyword\">return<\/span> <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>button<\/span> <span class=\"token attr-name\">onClick<\/span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=<\/span><span class=\"token punctuation\">{<\/span>props<span class=\"token punctuation\">.<\/span>onClick<span class=\"token punctuation\">}<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span><span class=\"token plain-text\">Open modal<\/span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>button<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><span class=\"token punctuation\">;<\/span><br \/>\n<span class=\"token punctuation\">}<\/span><\/code><\/p>\n<p>This might not always be easy because your component might be quite complex \u2013 for instance, you probably don\u2019t want to wrap your whole app in a <code>&lt;button&gt;<\/code> element \u2013 and buttons have specific styling.<\/p>\n<p>Another approach to make this component accessible is to add <code>onKeyDown<\/code>, <code>tabIndex<\/code> and <code>role<\/code> attributes to it:<\/p>\n<p><code class=\" language-jsx\" style=\"line-height: 1;\"><span class=\"token keyword\">export<\/span> <span class=\"token keyword\">default<\/span> <span class=\"token keyword\">function<\/span><span class=\"token punctuation\">(<\/span>props<span class=\"token punctuation\">)<\/span> <span class=\"token punctuation\">{<\/span><br \/>\n<span class=\"token keyword\">return<\/span> <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>div<\/span><br \/>\n<span class=\"token attr-name\">onClick<\/span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=<\/span><span class=\"token punctuation\">{<\/span>props<span class=\"token punctuation\">.<\/span>onClick<span class=\"token punctuation\">}<\/span><\/span><br \/>\n<span class=\"token attr-name\">onKeyDown<\/span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=<\/span><span class=\"token punctuation\">{<\/span><span class=\"token punctuation\">(<\/span>e<span class=\"token punctuation\">)<\/span> <span class=\"token operator\">=&gt;<\/span> <span class=\"token punctuation\">(<\/span>e<span class=\"token punctuation\">.<\/span>keyCode <span class=\"token operator\">===<\/span> <span class=\"token number\">13<\/span> <span class=\"token operator\">||<\/span> e<span class=\"token punctuation\">.<\/span>keyCode <span class=\"token operator\">===<\/span> <span class=\"token number\">32<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&amp;&amp;<\/span> props<span class=\"token punctuation\">.<\/span><span class=\"token function\">onClick<\/span><span class=\"token punctuation\">(<\/span>e<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">}<\/span><\/span><br \/>\n<span class=\"token attr-name\">tabIndex<\/span><span class=\"token attr-value\"><span class=\"token punctuation\">=<\/span>\u201d0\u201d<\/span><br \/>\n<span class=\"token attr-name\">role<\/span><span class=\"token attr-value\"><span class=\"token punctuation\">=<\/span>\u201dbutton\u201d<\/span><br \/>\n<span class=\"token punctuation\">&gt;<\/span><\/span><span class=\"token plain-text\">Open modal<\/span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>div<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><span class=\"token punctuation\">;<\/span><br \/>\n<span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">;<\/span><\/code><\/p>\n<p>The problem is that adding these three attributes to every clickable element in your app is quite a lot of work, and it\u2019s easy for engineers adding new functionality to forget to add these attributes or use the\u00a0<code>&lt;button&gt;<\/code> element instead.<\/p>\n<h4>Building an automated solution<\/h4>\n<p>To make keyboard accessibility the default condition, we wrote <a href=\"https:\/\/github.com\/danielhusar\/babel-plugin-react-add-a11y-props\" target=\"_blank\" rel=\"noopener noreferrer\">a custom babel plugin<\/a> that automatically adds <code>onKeyDown<\/code>, <code>tabIndex<\/code> and <code>role<\/code> attributes to all elements where:<\/p>\n<ol>\n<li>Browsers do not natively support tabNavigation.<\/li>\n<li>Browsers do not natively trigger <code>onClick<\/code> handlers when a user hits the enter or space keys.<\/li>\n<\/ol>\n<p>Since babel transforms JSX into regular JavaScript function calls, it\u2019s easy to statically determine components that need to have keyboard events added to them. Our custom babel plugin now handles the majority of our keyboard navigation issues.<\/p>\n<p>Here\u2019s an example of using <code>babel-plugin-react-add-a11y-props<\/code> within a React app:<\/p>\n<p><iframe style=\"width: 100%; height: 500px; border: 0; border-radius: 4px; overflow: hidden;\" src=\"https:\/\/codesandbox.io\/embed\/0426x9l46n?autoresize=1\" sandbox=\"allow-modals allow-forms allow-popups allow-scripts allow-same-origin\"><\/iframe><br \/>\nFor the folks wondering about the performance implications of having an arrow function in the render method, <a href=\"https:\/\/cdb.reacttraining.com\/react-inline-functions-and-performance-bdff784f5578\" target=\"_blank\" rel=\"noopener noreferrer\">it really is fine<\/a>, but since your mileage may vary, you should always measure your performance before you optimize.<\/p>\n<p>While this plugin will add keyboard navigation to all elements with onClick, if something behaves like a button, the <a href=\"https:\/\/twitter.com\/ryanflorence\/status\/1061440057213575168\" target=\"_blank\" rel=\"noopener noreferrer\">best solution<\/a> is still to change it to an actual button element.<\/p>\n<h3>2. Setting proper focus states<\/h3>\n<p>In order for your app to be navigable by keyboard, you need proper focus states. Focus states help users and their screen readers understand where they are in the app and what elements are being selected.<\/p>\n<p>A good rule of thumb is, if a user is relying on keyboard navigation, there should be a visual indicator to highlight which element currently has focus. In our case, we\u2019ve designed our visual indicators to show only if we detect you are using keyboard navigation. That way, we minimize visual noise for our mouse users. You can use <code><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/CSS\/:focus-visible\" target=\"_blank\" rel=\"noopener noreferrer\">focus-visible<\/a><\/code> to provide a different focus indicator based on the user\u2019s input modality, keyboard or mouse.<\/p>\n<p>Here is our Messenger with the focus indicator turned on:<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter\" src=\"https:\/\/www.intercom.com\/blog\/wp-content\/uploads\/2018\/12\/Messenger-Focus-Indicator.png\" alt=\"Intercom Messenger focus indicator\" width=\"243\" height=\"500\" \/><\/p>\n<h3>3. Designing intentional focus traps<\/h3>\n<p>For keyboard navigation to work, you may need to set intentional focus traps. Focus traps refer to times when a user hits the tab key or shift + tab keys, and they\u2019re placed in a <a href=\"https:\/\/www.w3.org\/TR\/wai-aria-practices-1.1\/#dialog_modal\" target=\"_blank\" rel=\"noopener noreferrer\">certain cycle of focusable elements<\/a>. The most common example where you would want to set up a focus trap is a modal.<\/p>\n<p>In our case, while the Messenger is open, we\u2019ve set a focus trap so users are not able to tab outside of it. That way, users are able to navigate all of the elements in the Messenger without having to navigate through the entire webpage. Here is our Messenger\u2019s focus trap in action:<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter\" src=\"https:\/\/www.intercom.com\/blog\/wp-content\/uploads\/2018\/12\/Messenger-Focus-Trap.gif\" alt=\"Messenger accessibility - Focus trap\" width=\"246\" height=\"500\" \/><\/p>\n<p>Setting a focus trap is usually a complex task. Focus from last element should jump to the first one and when going backwards, the focus should jump from the first one to the last one. For that to work, you need to calculate all the focusable elements, set up proper event listeners and have it flexible enough that you can override those rules.<\/p>\n<p>We have created <a href=\"https:\/\/github.com\/danielhusar\/focus-trap\" target=\"_blank\" rel=\"noopener noreferrer\">an open-source library<\/a> to quickly and easily create focus traps. This library provides a high-level API that will handle the focus traps. A simple example is to pass the dom element in which the focus should be trapped:<\/p>\n<p><code class=\" language-js\"><span class=\"token keyword\">const<\/span> trap <span class=\"token operator\">=<\/span> <span class=\"token keyword\">new<\/span> <span class=\"token class-name\">FocusTrap<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">{<\/span><br \/>\nnode<span class=\"token punctuation\">:<\/span> document<br \/>\n<span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><\/code><\/p>\n<p>You can check out the focus traps in action here:<\/p>\n<p><iframe style=\"width: 100%; height: 500px; border: 0; border-radius: 4px; overflow: hidden;\" src=\"https:\/\/codesandbox.io\/embed\/4rn8vm4nv0?autoresize=1\" sandbox=\"allow-modals allow-forms allow-popups allow-scripts allow-same-origin\"><\/iframe><br \/>\nJust as it\u2019s important to set intentional focus traps, you should always provide a way for keyboard users to exit those focus traps. You can see that in the example below. We\u2019ve also designed it so that after the modal is closed, the focus returns back to the element that originally opened the modal. Here it is in our Messenger:<\/p>\n<p><img decoding=\"async\" class=\"small\" src=\"https:\/\/www.intercom.com\/blog\/wp-content\/uploads\/2018\/12\/modal2.gif\" alt=\"Modal in Messenger\" \/><a id=\"screen-reader\"><\/a><\/p>\n<h2 id=\"supporting-screen-readers\">Supporting screen readers<\/h2>\n<p>Screen readers are software applications that allow visually impaired users to read text that is displayed on their computers. Together with keyboard navigation, providing full support to screen readers was crucial to making our Messenger accessible.<\/p>\n<p>Our work on supporting screen readers can be broken down into four main changes:<\/p>\n<ol>\n<li>Making text content readable and navigable<\/li>\n<li>Defining states and properties with ARIA attributes<\/li>\n<li>Adding visually hidden text<\/li>\n<li>Removing mouse hover states<\/li>\n<\/ol>\n<h3>1. Making text content readable and navigable<\/h3>\n<p>The first thing we did was set the language attribute on HTML elements. Screen readers use this attribute to determine the language of the page and read the text in its intended way.<\/p>\n<p>The second thing we did was add semantic markup to our Messenger. Since our Messenger is a single page app that you embed, SEO doesn\u2019t apply to it and semantic markup hadn\u2019t been a priority. To support screen readers, we updated our code to include semantic elements like headings, paragraphs and labels.<\/p>\n<h3>2. Defining states and properties with ARIA attributes<\/h3>\n<p>To fully support screen readers in our web Messenger, we used WAI-ARIA attributes. <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/Accessibility\/ARIA\" target=\"_blank\" rel=\"noopener noreferrer\">Accessible Rich Internet Applications (ARIA)<\/a> are a set of attributes that supplement HTML so screen readers can handle common interactions like forms hints and error messages, live content updates and more.<\/p>\n<h4>Establishing non-text elements with aria-label<\/h4>\n<p>We have added the <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/Accessibility\/ARIA\/ARIA_Techniques\/Using_the_aria-label_attribute\" target=\"_blank\" rel=\"noopener noreferrer\"><code>aria-label<\/code> attribute<\/a> to all elements that have <code>onClick<\/code> handler but it\u2019s not clear to screen readers what the intended functionality is. The most common scenario is when elements have decoration styles without any text. The screen reader will read the <code>aria-label<\/code> when keyboard is focused on that element. The \u201cclose\u201d button is good example:<br \/>\n<img decoding=\"async\" class=\"aligncenter\" src=\"https:\/\/www.intercom.com\/blog\/wp-content\/uploads\/2018\/12\/close-button.png\" alt=\"Close button that needs aria-label\" width=\"300\" \/><\/p>\n<p>We also support an <a href=\"https:\/\/www.intercom.com\/blog\/app-store\/\" target=\"_blank\" rel=\"noopener noreferrer\">ecosystem of apps<\/a> that are built on top of our Messenger. Previously it was was not possible to make Messenger apps accessible. Now we have extended our framework with <code>aria-label<\/code> attributes so every Messenger app can be fully accessible. For instance, the <a href=\"https:\/\/www.intercom.com\/blog\/app-store\/?app_package_code=article-search&amp;search=article\" target=\"_blank\" rel=\"noopener noreferrer\">Article Search app<\/a> is accessible with <code>aria-label<\/code> attributes for the input field and submit button:<br \/>\n<img decoding=\"async\" class=\"aligncenter\" src=\"https:\/\/www.intercom.com\/blog\/wp-content\/uploads\/2018\/12\/article-search-app.png\" alt=\"Messenger app for Article Search now accessible\" width=\"300\" \/><\/p>\n<h4>Announcing dynamic changes with aria-live<\/h4>\n<p>Our Messenger behaves like a single page app. To support dynamic changes to our content without page reload, we added <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/Accessibility\/ARIA\/ARIA_Live_Regions\" target=\"_blank\" rel=\"noopener noreferrer\"><code>aria-live<\/code> attributes<\/a> to our app.<\/p>\n<p>Our <code>aria-live<\/code> attributes tell screen readers to watch for changes in selected dom elements, and any dom mutation inside of it will be announced. We\u2019ve wrapped our whole app with this attribute as all changes that are made need to be presented to users. We\u2019ve also wrapped various parts like our conversation view in an <code>aria-live<\/code> attribute so when a new message is received, the screen reader will announce it first. You can see how it works:<\/p>\n<div class=\"oembed-wrapper oembed--youtube\"><iframe loading=\"lazy\" title=\"Supporting screen readers\" width=\"500\" height=\"281\" src=\"https:\/\/www.youtube.com\/embed\/DXd6I8kYhvQ?feature=oembed&#038;enablejsapi=1\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe><\/div>\n<h4>Indicating error states with aria-invalid<\/h4>\n<p>All error states need to be properly announced to screen readers. Previously, error states on the input would be represented only with CSS classes. To make those error states visible to screen readers, we\u2019ve added <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/Accessibility\/ARIA\/ARIA_Techniques\/Using_the_aria-invalid_attribute\" target=\"_blank\" rel=\"noopener noreferrer\"><code>aria-invalid<\/code> attributes<\/a> to inputs with errors and <code>role=\"alert\"<\/code> to the error messages. Here is the error state for the <a href=\"https:\/\/www.intercom.com\/blog\/app-store\/?app_package_code=mailchimp&amp;search=mailchimp\" target=\"_blank\" rel=\"noopener noreferrer\">Mailchimp app<\/a> in our Messenger:<br \/>\n<img decoding=\"async\" class=\"aligncenter\" src=\"https:\/\/www.intercom.com\/blog\/wp-content\/uploads\/2018\/12\/Mailchimp-app.png\" alt=\"Error state for Mailchimp app\" width=\"300\" \/><\/p>\n<h3>3. Adding visually hidden text<\/h3>\n<p>There are some scenarios where it\u2019s only visually clear what components do. Without the visual indicators, these elements are meaningless or confusing. In these cases, we\u2019ve added visually hidden text to help screen readers interpret what\u2019s happening.<\/p>\n<p>The typing bubble in our Messenger is good example of this:<br \/>\n<img decoding=\"async\" class=\"aligncenter\" src=\"https:\/\/www.intercom.com\/blog\/wp-content\/uploads\/2018\/12\/typing-bubble.gif\" alt=\"Typing bubble in Intercom Messenger\" width=\"145\" \/><br \/>\nWhile this is visually clear somebody is typing, screen readers have no way of processing or communicating that. We\u2019ve added hidden text inside of the speech bubble for screen readers to reference. You can visually hide text with this CSS snippet:<\/p>\n<p><code class=\" language-js\" style=\"line-height: 1;\"><span class=\"token punctuation\">.<\/span>visually<span class=\"token operator\">-<\/span>hidden <span class=\"token punctuation\">{<\/span><br \/>\nposition<span class=\"token punctuation\">:<\/span> absolute <span class=\"token operator\">!<\/span>important<span class=\"token punctuation\">;<\/span><br \/>\nclip<span class=\"token punctuation\">:<\/span> <span class=\"token function\">rect<\/span><span class=\"token punctuation\">(<\/span><span class=\"token number\">1<\/span>px<span class=\"token punctuation\">,<\/span> <span class=\"token number\">1<\/span>px<span class=\"token punctuation\">,<\/span> <span class=\"token number\">1<\/span>px<span class=\"token punctuation\">,<\/span> <span class=\"token number\">1<\/span>px<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><br \/>\n<span class=\"token punctuation\">}<\/span><\/code><\/p>\n<p>The HTML might look like this:<\/p>\n<p><code class=\" language-jsx\" style=\"line-height: 1;\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>div<\/span> <span class=\"token attr-name\">class<\/span><span class=\"token attr-value\"><span class=\"token punctuation\">=<\/span><span class=\"token punctuation\">\"<\/span>typing-admin-bubble<span class=\"token punctuation\">\"<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span><span class=\"token plain-text\"><br \/>\n<\/span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>div<\/span> <span class=\"token attr-name\">class<\/span><span class=\"token attr-value\"><span class=\"token punctuation\">=<\/span><span class=\"token punctuation\">\"<\/span>typing-admin-dot-1<span class=\"token punctuation\">\"<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>div<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><span class=\"token plain-text\"><br \/>\n<\/span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>div<\/span> <span class=\"token attr-name\">class<\/span><span class=\"token attr-value\"><span class=\"token punctuation\">=<\/span><span class=\"token punctuation\">\"<\/span>typing-admin-dot-2<span class=\"token punctuation\">\"<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>div<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><span class=\"token plain-text\"><br \/>\n<\/span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>div<\/span> <span class=\"token attr-name\">class<\/span><span class=\"token attr-value\"><span class=\"token punctuation\">=<\/span><span class=\"token punctuation\">\"<\/span>typing-admin-dot-3<span class=\"token punctuation\">\"<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>div<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><span class=\"token plain-text\"><br \/>\n<\/span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>div<\/span> <span class=\"token attr-name\">class<\/span><span class=\"token attr-value\"><span class=\"token punctuation\">=<\/span><span class=\"token punctuation\">\"<\/span>visually-hidden<span class=\"token punctuation\">\"<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span><span class=\"token plain-text\">Is typing.<\/span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>div<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><span class=\"token plain-text\"><br \/>\n<\/span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>div<\/span><span class=\"token punctuation\">&gt;<\/span><\/span><\/code><\/p>\n<h3>4. Removing mouse hover states<\/h3>\n<p>Any functionality that is available just on mouse hover, such as tooltips, should be accessible to screen readers too. In our case, we display timestamps in conversations when you hover over the specific message:<br \/>\n<img decoding=\"async\" class=\"aligncenter\" src=\"https:\/\/www.intercom.com\/blog\/wp-content\/uploads\/2018\/12\/Timestamp-on-hover.png\" alt=\"Timestamp in Messenger on mouse hover\" width=\"300\" \/><br \/>\nSince timestamps are very useful information for screen readers, we have opted to show timestamps all the time for screen readers:<br \/>\n<a id=\"color-contrast\"><\/a><img decoding=\"async\" class=\"aligncenter\" src=\"https:\/\/www.intercom.com\/blog\/wp-content\/uploads\/2018\/12\/timestamp-screen-reader.png\" alt=\"Timestamps in Messenger for screen readers\" width=\"300\" \/><\/p>\n<h2 id=\"optimizing-color-contrast\">Optimizing color contrast<\/h2>\n<p>For users with visual impairments like color blindness, high contrast between colors make it easier to read text content. The recommended contrast ratio for accessible content is 4:5:1 between the text and background colors.<\/p>\n<p>We split our color contrast work into three buckets:<\/p>\n<ol>\n<li>Issues caused by customizable colors<\/li>\n<li>Issues caused by non-customizable colors<\/li>\n<li>Supporting high contrast mode in Windows 10<\/li>\n<\/ol>\n<h3>1. Issues caused by customizable colors<\/h3>\n<p>These are issues caused by customers who customize the Messenger and choose colors that don\u2019t match the recommended contrast ratio. For example, teammates can choose the background and action colors of the Messenger:<br \/>\n<img decoding=\"async\" class=\"aligncenter\" src=\"https:\/\/www.intercom.com\/blog\/wp-content\/uploads\/2018\/12\/customizable-colors-Messenger.png\" alt=\"customizable colors in the Messenger\" width=\"500\" \/><br \/>\nTo help, we\u2019ve published <a href=\"https:\/\/www.intercom.com\/blog\/help\/faqs-and-troubleshooting\/the-intercom-messenger\/is-the-intercom-messenger-accessible\" target=\"_blank\" rel=\"noopener noreferrer\">public documentation<\/a> on how to choose colors for your Messenger while maintaining accessibility.<\/p>\n<h3>2. Issues caused by non-customizable colors<\/h3>\n<p>These are issues caused by the colors that are hardcoded in our codebase. We have inspected all the hardcoded colors we have in the Messenger. After we identified all the colors that had to change, our designers prepared alternative colors that matched the contrast ratio. You can see the before and after here:<br \/>\n<img decoding=\"async\" class=\"aligncenter\" src=\"https:\/\/www.intercom.com\/blog\/wp-content\/uploads\/2018\/12\/color-contrast-Messenger.png\" alt=\"Color contrast in the Messenger\" width=\"500\" \/><br \/>\nOn the left is the Messenger before we made the update. On the right is the Messenger with colors matching the 4:5:1 contrast ratio.<\/p>\n<h3>3. Supporting high contrast mode in Windows 10<\/h3>\n<p>We\u2019ve even added support for <a href=\"https:\/\/blogs.windows.com\/msedgedev\/2016\/04\/20\/building-a-more-accessible-web-platform\/#CbZGC2hMXdTKis4k.97\" target=\"_blank\" rel=\"noopener noreferrer\">high contrast mode in Microsoft Windows 10<\/a>. High contrast mode is specifically designed for visually impaired people to consume content more easily.<br \/>\n<img decoding=\"async\" class=\"aligncenter\" src=\"https:\/\/www.intercom.com\/blog\/wp-content\/uploads\/2018\/12\/Windows-10-high-contrast-mode.png\" alt=\"Messenger support for Windows 10 high contrast mode\" height=\"500\" \/><\/p>\n<h2 id=\"ensuring-the-future-accessibility-of-our-messenger\">Ensuring the future accessibility of our Messenger<\/h2>\n<p>We offer many customizations in our Messenger. While we want our customers to be able to customize the Messenger to fit their brand, it\u2019s not always easy to keep accessibility in mind. That\u2019s why we\u2019ve published a <a href=\"https:\/\/www.intercom.com\/blog\/help\/faqs-and-troubleshooting\/the-intercom-messenger\/is-the-intercom-messenger-accessible\" target=\"_blank\" rel=\"noopener noreferrer\">set of guidelines<\/a> on how to customize the Messenger to be accessible. Guidelines include what colors to pick, which Messenger apps to use, how to send media content and attachments in conversations and more.<\/p>\n<p>We\u2019ve also put automated tooling in place to prevent any regressions in the code. We\u2019ve implemented two main tools: Eslint and React-a11y. <a href=\"https:\/\/github.com\/evcohen\/eslint-plugin-jsx-a11y\" target=\"_blank\" rel=\"noopener noreferrer\">Eslint<\/a> helps us statically check our codebase for any accessibility issues. <a href=\"https:\/\/github.com\/reactjs\/react-a11y\" target=\"_blank\" rel=\"noopener noreferrer\">React-a11y<\/a> is a runtime validator that works in our integrations tests and will validate accessibility before we ship any changes to production.<\/p>\n<h2 id=\"making-internet-business-personal-and-possible\">Making internet business personal <em>and<\/em> possible<\/h2>\n<p>Everyday thousands of businesses use Intercom to talk to their customers. That\u2019s hundreds of thousands of people, or more, who communicate with each other using our Messenger. And while not everyone experiences web content in the same way, using the Messenger should always feel personal and just as important, be possible.<\/p>\n<p>Making our web Messenger accessible \u2013 the engineering work and changes \u2013 ended up being a small technical commitment compared to its huge and ongoing impact. At the end of the day, we want the Messenger to be the kind of space online that feels like walking into your neighborhood coffee shop and knowing it\u2019s designed to accommodate you.<\/p>\n\n","protected":false},"excerpt":{"rendered":"<p>We believe internet businesses should be able to communicate with everyone, regardless of how their visitors interact with the web. Here\u2019s a behind-the-scenes look at how made our web Messenger accessible. <\/p>\n","protected":false},"author":111,"featured_media":18815,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"category":[12898,4],"tags":[],"coauthors":[351],"class_list":["post-18791","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-engineering","category-news"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v27.3 (Yoast SEO v27.3) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Building for Everyone: How We Made the Intercom Messenger Accessible<\/title>\n<meta name=\"description\" content=\"We believe internet business should be personal and possible \u2013 for everyone. Here\u2019s an inside look at how we engineered our Messenger for web accessibility.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.intercom.com\/blog\/messenger-accessibility\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Building for everyone: How we made the Intercom Messenger accessible\" \/>\n<meta property=\"og:description\" content=\"We believe internet business should be personal and possible \u2013 for everyone. Here\u2019s an inside look at how we engineered our Messenger for web accessibility.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.intercom.com\/blog\/messenger-accessibility\/\" \/>\n<meta property=\"og:site_name\" content=\"The Intercom Blog\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/intercominc\" \/>\n<meta property=\"article:published_time\" content=\"2018-12-05T17:39:38+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2020-07-30T11:54:47+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.intercom.com\/blog\/wp-content\/uploads\/2018\/12\/Messenger-Accessibility-Hero.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1968\" \/>\n\t<meta property=\"og:image:height\" content=\"932\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Daniel Husar\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@danohusar\" \/>\n<meta name=\"twitter:site\" content=\"@intercom\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Daniel Husar\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"14 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.intercom.com\\\/blog\\\/messenger-accessibility\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.intercom.com\\\/blog\\\/messenger-accessibility\\\/\"},\"author\":{\"name\":\"Daniel Husar\",\"@id\":\"https:\\\/\\\/www.intercom.com\\\/blog\\\/#\\\/schema\\\/person\\\/bfac1d1bb09e5daf34e2df1e9b2ed2cb\"},\"headline\":\"Building for everyone: How we made the Intercom Messenger accessible\",\"datePublished\":\"2018-12-05T17:39:38+00:00\",\"dateModified\":\"2020-07-30T11:54:47+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.intercom.com\\\/blog\\\/messenger-accessibility\\\/\"},\"wordCount\":2570,\"publisher\":{\"@id\":\"https:\\\/\\\/www.intercom.com\\\/blog\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/www.intercom.com\\\/blog\\\/messenger-accessibility\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.intercom.com\\\/blog\\\/wp-content\\\/uploads\\\/2018\\\/12\\\/Messenger-Accessibility-Hero.png\",\"articleSection\":[\"Engineering\",\"News &amp; Updates\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.intercom.com\\\/blog\\\/messenger-accessibility\\\/\",\"url\":\"https:\\\/\\\/www.intercom.com\\\/blog\\\/messenger-accessibility\\\/\",\"name\":\"Building for Everyone: How We Made the Intercom Messenger Accessible\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.intercom.com\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.intercom.com\\\/blog\\\/messenger-accessibility\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.intercom.com\\\/blog\\\/messenger-accessibility\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.intercom.com\\\/blog\\\/wp-content\\\/uploads\\\/2018\\\/12\\\/Messenger-Accessibility-Hero.png\",\"datePublished\":\"2018-12-05T17:39:38+00:00\",\"dateModified\":\"2020-07-30T11:54:47+00:00\",\"description\":\"We believe internet business should be personal and possible \u2013 for everyone. Here\u2019s an inside look at how we engineered our Messenger for web accessibility.\",\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.intercom.com\\\/blog\\\/messenger-accessibility\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.intercom.com\\\/blog\\\/messenger-accessibility\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.intercom.com\\\/blog\\\/wp-content\\\/uploads\\\/2018\\\/12\\\/Messenger-Accessibility-Hero.png\",\"contentUrl\":\"https:\\\/\\\/www.intercom.com\\\/blog\\\/wp-content\\\/uploads\\\/2018\\\/12\\\/Messenger-Accessibility-Hero.png\",\"width\":1968,\"height\":932,\"caption\":\"Messenger Accessibility\"},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.intercom.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.intercom.com\\\/blog\\\/\",\"name\":\"The Intercom Blog\",\"description\":\"Articles and Podcasts on Customer Service, AI and Automation, Product, and more\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.intercom.com\\\/blog\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.intercom.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.intercom.com\\\/blog\\\/#organization\",\"name\":\"The Intercom Blog\",\"url\":\"https:\\\/\\\/www.intercom.com\\\/blog\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.intercom.com\\\/blog\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/www.intercom.com\\\/blog\\\/wp-content\\\/uploads\\\/2019\\\/08\\\/Intercom-logo-sq-black-trans.png\",\"contentUrl\":\"https:\\\/\\\/www.intercom.com\\\/blog\\\/wp-content\\\/uploads\\\/2019\\\/08\\\/Intercom-logo-sq-black-trans.png\",\"width\":1000,\"height\":1000,\"caption\":\"The Intercom Blog\"},\"image\":{\"@id\":\"https:\\\/\\\/www.intercom.com\\\/blog\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/intercominc\",\"https:\\\/\\\/x.com\\\/intercom\",\"https:\\\/\\\/www.instagram.com\\\/intercom\\\/\",\"https:\\\/\\\/www.linkedin.com\\\/company\\\/2491343\",\"https:\\\/\\\/www.pinterest.ie\\\/intercom\\\/\",\"https:\\\/\\\/www.youtube.com\\\/channel\\\/UCJG0MvLP03kyzzAkD-w98aQ\",\"https:\\\/\\\/en.wikipedia.org\\\/wiki\\\/Intercom_(company)\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.intercom.com\\\/blog\\\/#\\\/schema\\\/person\\\/bfac1d1bb09e5daf34e2df1e9b2ed2cb\",\"name\":\"Daniel Husar\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/8b0e7e7d491c88f41c15fedb50677b5b87972aaf603c239746f1835e678f3e7d?s=96&d=mm&r=pg16b36698b3c2523f72d50e1c610ccc8d\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/8b0e7e7d491c88f41c15fedb50677b5b87972aaf603c239746f1835e678f3e7d?s=96&d=mm&r=pg\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/8b0e7e7d491c88f41c15fedb50677b5b87972aaf603c239746f1835e678f3e7d?s=96&d=mm&r=pg\",\"caption\":\"Daniel Husar\"},\"sameAs\":[\"https:\\\/\\\/x.com\\\/danohusar\"],\"url\":\"https:\\\/\\\/www.intercom.com\\\/blog\\\/author\\\/daniel\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Building for Everyone: How We Made the Intercom Messenger Accessible","description":"We believe internet business should be personal and possible \u2013 for everyone. Here\u2019s an inside look at how we engineered our Messenger for web accessibility.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.intercom.com\/blog\/messenger-accessibility\/","og_locale":"en_US","og_type":"article","og_title":"Building for everyone: How we made the Intercom Messenger accessible","og_description":"We believe internet business should be personal and possible \u2013 for everyone. Here\u2019s an inside look at how we engineered our Messenger for web accessibility.","og_url":"https:\/\/www.intercom.com\/blog\/messenger-accessibility\/","og_site_name":"The Intercom Blog","article_publisher":"https:\/\/www.facebook.com\/intercominc","article_published_time":"2018-12-05T17:39:38+00:00","article_modified_time":"2020-07-30T11:54:47+00:00","og_image":[{"width":1968,"height":932,"url":"https:\/\/www.intercom.com\/blog\/wp-content\/uploads\/2018\/12\/Messenger-Accessibility-Hero.png","type":"image\/png"}],"author":"Daniel Husar","twitter_card":"summary_large_image","twitter_creator":"@danohusar","twitter_site":"@intercom","twitter_misc":{"Written by":"Daniel Husar","Est. reading time":"14 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.intercom.com\/blog\/messenger-accessibility\/#article","isPartOf":{"@id":"https:\/\/www.intercom.com\/blog\/messenger-accessibility\/"},"author":{"name":"Daniel Husar","@id":"https:\/\/www.intercom.com\/blog\/#\/schema\/person\/bfac1d1bb09e5daf34e2df1e9b2ed2cb"},"headline":"Building for everyone: How we made the Intercom Messenger accessible","datePublished":"2018-12-05T17:39:38+00:00","dateModified":"2020-07-30T11:54:47+00:00","mainEntityOfPage":{"@id":"https:\/\/www.intercom.com\/blog\/messenger-accessibility\/"},"wordCount":2570,"publisher":{"@id":"https:\/\/www.intercom.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.intercom.com\/blog\/messenger-accessibility\/#primaryimage"},"thumbnailUrl":"https:\/\/www.intercom.com\/blog\/wp-content\/uploads\/2018\/12\/Messenger-Accessibility-Hero.png","articleSection":["Engineering","News &amp; Updates"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/www.intercom.com\/blog\/messenger-accessibility\/","url":"https:\/\/www.intercom.com\/blog\/messenger-accessibility\/","name":"Building for Everyone: How We Made the Intercom Messenger Accessible","isPartOf":{"@id":"https:\/\/www.intercom.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.intercom.com\/blog\/messenger-accessibility\/#primaryimage"},"image":{"@id":"https:\/\/www.intercom.com\/blog\/messenger-accessibility\/#primaryimage"},"thumbnailUrl":"https:\/\/www.intercom.com\/blog\/wp-content\/uploads\/2018\/12\/Messenger-Accessibility-Hero.png","datePublished":"2018-12-05T17:39:38+00:00","dateModified":"2020-07-30T11:54:47+00:00","description":"We believe internet business should be personal and possible \u2013 for everyone. Here\u2019s an inside look at how we engineered our Messenger for web accessibility.","inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.intercom.com\/blog\/messenger-accessibility\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.intercom.com\/blog\/messenger-accessibility\/#primaryimage","url":"https:\/\/www.intercom.com\/blog\/wp-content\/uploads\/2018\/12\/Messenger-Accessibility-Hero.png","contentUrl":"https:\/\/www.intercom.com\/blog\/wp-content\/uploads\/2018\/12\/Messenger-Accessibility-Hero.png","width":1968,"height":932,"caption":"Messenger Accessibility"},{"@type":"WebSite","@id":"https:\/\/www.intercom.com\/blog\/#website","url":"https:\/\/www.intercom.com\/blog\/","name":"The Intercom Blog","description":"Articles and Podcasts on Customer Service, AI and Automation, Product, and more","publisher":{"@id":"https:\/\/www.intercom.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.intercom.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.intercom.com\/blog\/#organization","name":"The Intercom Blog","url":"https:\/\/www.intercom.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.intercom.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/www.intercom.com\/blog\/wp-content\/uploads\/2019\/08\/Intercom-logo-sq-black-trans.png","contentUrl":"https:\/\/www.intercom.com\/blog\/wp-content\/uploads\/2019\/08\/Intercom-logo-sq-black-trans.png","width":1000,"height":1000,"caption":"The Intercom Blog"},"image":{"@id":"https:\/\/www.intercom.com\/blog\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/intercominc","https:\/\/x.com\/intercom","https:\/\/www.instagram.com\/intercom\/","https:\/\/www.linkedin.com\/company\/2491343","https:\/\/www.pinterest.ie\/intercom\/","https:\/\/www.youtube.com\/channel\/UCJG0MvLP03kyzzAkD-w98aQ","https:\/\/en.wikipedia.org\/wiki\/Intercom_(company)"]},{"@type":"Person","@id":"https:\/\/www.intercom.com\/blog\/#\/schema\/person\/bfac1d1bb09e5daf34e2df1e9b2ed2cb","name":"Daniel Husar","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/8b0e7e7d491c88f41c15fedb50677b5b87972aaf603c239746f1835e678f3e7d?s=96&d=mm&r=pg16b36698b3c2523f72d50e1c610ccc8d","url":"https:\/\/secure.gravatar.com\/avatar\/8b0e7e7d491c88f41c15fedb50677b5b87972aaf603c239746f1835e678f3e7d?s=96&d=mm&r=pg","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/8b0e7e7d491c88f41c15fedb50677b5b87972aaf603c239746f1835e678f3e7d?s=96&d=mm&r=pg","caption":"Daniel Husar"},"sameAs":["https:\/\/x.com\/danohusar"],"url":"https:\/\/www.intercom.com\/blog\/author\/daniel\/"}]}},"jetpack_featured_media_url":"https:\/\/www.intercom.com\/blog\/wp-content\/uploads\/2018\/12\/Messenger-Accessibility-Hero.png","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.intercom.com\/blog\/wp-json\/wp\/v2\/posts\/18791","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.intercom.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.intercom.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.intercom.com\/blog\/wp-json\/wp\/v2\/users\/111"}],"replies":[{"embeddable":true,"href":"https:\/\/www.intercom.com\/blog\/wp-json\/wp\/v2\/comments?post=18791"}],"version-history":[{"count":0,"href":"https:\/\/www.intercom.com\/blog\/wp-json\/wp\/v2\/posts\/18791\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.intercom.com\/blog\/wp-json\/wp\/v2\/media\/18815"}],"wp:attachment":[{"href":"https:\/\/www.intercom.com\/blog\/wp-json\/wp\/v2\/media?parent=18791"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.intercom.com\/blog\/wp-json\/wp\/v2\/category?post=18791"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.intercom.com\/blog\/wp-json\/wp\/v2\/tags?post=18791"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.intercom.com\/blog\/wp-json\/wp\/v2\/coauthors?post=18791"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}