<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Oliwia Połeć</title>
    <description>The latest articles on DEV Community by Oliwia Połeć (@oliwiapolec).</description>
    <link>https://dev.to/oliwiapolec</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F584173%2F76274a73-f8ac-4880-8c62-ba020fd59ac6.png</url>
      <title>DEV Community: Oliwia Połeć</title>
      <link>https://dev.to/oliwiapolec</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/oliwiapolec"/>
    <language>en</language>
    <item>
      <title>Build an App and Enjoy a 0% Commission Fee</title>
      <dc:creator>Oliwia Połeć</dc:creator>
      <pubDate>Mon, 27 Nov 2023 14:04:28 +0000</pubDate>
      <link>https://dev.to/text/build-an-app-and-enjoy-a-0-commission-fee-hlj</link>
      <guid>https://dev.to/text/build-an-app-and-enjoy-a-0-commission-fee-hlj</guid>
      <description>&lt;p&gt;After your application goes live, the initial weeks are crucial for building momentum and capturing the attention of your prospective customers. It's a time when your app is fresh and exciting, allowing users to test it and see how they like it.&lt;/p&gt;

&lt;p&gt;This period presents a unique opportunity. You earn customer trust and loyalty, and show your commitment to their satisfaction by acting on feedback and providing assistance.&lt;/p&gt;

&lt;p&gt;To support your efforts, dedication, and hard work, we’re delighted to offer you an exceptional opportunity. Publish your &lt;a href="https://platform.text.com/"&gt;Text Platform&lt;/a&gt; app before January 31, 2024, and enjoy a completely waived commission fee for &lt;strong&gt;60 days&lt;/strong&gt; from publication. This means you can focus on what matters most and enjoy 100% of the revenue earned from your installations.&lt;/p&gt;

&lt;p&gt;But that’s not all! There are various other benefits —  and they’re just as attractive. Take a look at what we have in store for you:&lt;/p&gt;

&lt;h3&gt;
  
  
  🎫 Free promotional space
&lt;/h3&gt;

&lt;p&gt;Take advantage of the opportunity to get your app featured on the Marketplace homepage or in the LiveChat App, improving your visibility and increasing prospects for installations.&lt;/p&gt;

&lt;h3&gt;
  
  
  🧑‍💻 Premium support through Discord
&lt;/h3&gt;

&lt;p&gt;Experience the benefits of priority support through our dedicated Discord server. Our team of product experts is ready to provide you with top-notch assistance and guidance on any development questions.&lt;/p&gt;

&lt;h3&gt;
  
  
  💲 Discounts on future fees
&lt;/h3&gt;

&lt;p&gt;As you reach pre-set milestones, you can unlock discounts on commission fees beyond the initial 60 days. Check out the benefits of the following milestones:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;First 10 sales&lt;/strong&gt;: An additional 14 days of zero commission fees upon reaching the first 10 sales of your app.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Three 5-star reviews&lt;/strong&gt;: An additional one month of zero commission fees if the application receives at least three 5-star reviews before the end of your app’s zero commission fee period.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;First 25 sales&lt;/strong&gt;: An additional one month of zero commission fees.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Publishing a second application&lt;/strong&gt;: If you publish a second application before the end of the initial zero commission fee period for the first application, the second application will be eligible for 30 days of zero commission fees.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  📚 Training and webinars
&lt;/h3&gt;

&lt;p&gt;First time developing in the Developer Program? Access our video and text materials on application development to kickstart your journey and gain expert insight.&lt;/p&gt;

&lt;h3&gt;
  
  
  🧑‍🎓 Mentorship
&lt;/h3&gt;

&lt;p&gt;Receive personalized answers and mentorship from Text’s developers and gain first-hand insights on app development.&lt;/p&gt;




&lt;h2&gt;
  
  
  Don't have an idea for your app? 🤷
&lt;/h2&gt;

&lt;p&gt;Grab our three app ideas suitable for beginners that would make great additions to the &lt;a href="https://www.text.com/marketplace/"&gt;Text Marketplace&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[LiveChat] Please hold on 🕐&lt;/strong&gt;&lt;br&gt;
Send an automatic customizable message to a chatting customer if the chat is idle for a certain period of time.&lt;/p&gt;

&lt;p&gt;💻 Development Kit:&lt;br&gt;
&lt;a href="https://platform.text.com/docs/messaging/agent-chat-api"&gt;Agent Chat API&lt;/a&gt;&lt;br&gt;
&lt;a href="https://platform.text.com/docs/authorization/sign-in-with-livechat"&gt;Accounts SDK&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[HelpDesk] Integration with Messenger 💬&lt;/strong&gt;&lt;br&gt;
Create HelpDesk tickets directly from Messenger messages, providing a new channel for communication with coworkers and external recipients.&lt;/p&gt;

&lt;p&gt;💻 Development Kit:&lt;br&gt;
&lt;a href="https://platform.text.com/docs/getting-started/helpdesk-apps/helpdesk-api"&gt;HelpDesk API&lt;/a&gt;&lt;br&gt;
&lt;a href="https://platform.text.com/docs/extending-agent-app/products-sdk/helpdesk-sdk"&gt;HelpDesk SDK&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[LiveChat] Simplified tag editing 🗂️&lt;/strong&gt;&lt;br&gt;
Automatically replace existing chat tags with new tags in all the chats they were already added to.&lt;/p&gt;

&lt;p&gt;💻 Development Kit:&lt;br&gt;
&lt;a href="https://platform.text.com/docs/management/configuration-api"&gt;Configuration API&lt;/a&gt;&lt;br&gt;
&lt;a href="https://platform.text.com/docs/authorization/sign-in-with-livechat"&gt;Accounts SDK&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And if these don't hit the spot, have a look at &lt;a href="https://platform.text.com/app-ideas"&gt;the entire list of available app ideas&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;If you find the idea intriguing and would like to participate, &lt;a href="https://platform.text.com/zero-commission"&gt;visit the campaign’s landing page&lt;/a&gt; to find additional details. &lt;/p&gt;

&lt;p&gt;And... Happy coding!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>beginners</category>
      <category>codenewbie</category>
    </item>
    <item>
      <title>Exciting New Development Options in the Developer Console</title>
      <dc:creator>Oliwia Połeć</dc:creator>
      <pubDate>Mon, 05 Jun 2023 11:02:35 +0000</pubDate>
      <link>https://dev.to/text/exciting-new-development-options-in-the-developer-console-58j7</link>
      <guid>https://dev.to/text/exciting-new-development-options-in-the-developer-console-58j7</guid>
      <description>&lt;p&gt;The world is going the way of Artificial Intelligence and automation. With hectic schedules and more and more tasks to complete, people are looking for ways to make their work more accessible and efficient in the shortest amount of time possible.&lt;/p&gt;

&lt;p&gt;To address these needs, &lt;a href="https://platform.text.com/console/"&gt;the Developer Console&lt;/a&gt; has taken the lead by introducing exciting new development possibilities. You now have the option to effortlessly connect your GitHub repository to your Developer Console app, seamlessly integrating it with deployment services like Netlify or Vercel — all to simplify and smooth out your deployment workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  So what’s the fuss all about?
&lt;/h2&gt;

&lt;p&gt;Until now, you had to go through the steps of setting up your own repository in GitHub and working on your app using the code editor on your local machine to create your application in the Console. You also needed to manually set up a deployment on your end, or even rely on your own servers.&lt;/p&gt;

&lt;p&gt;Right now you can both create repositories and complete the deployment straight from the Developer Console, staying in the same context and streamlining your workflow. You can also manage your application’s code through Visual Studio, and — you guessed it — you can access it directly from the Console.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5gmzkJ2i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v7f6g05ngbsyr5sy1n3f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5gmzkJ2i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v7f6g05ngbsyr5sy1n3f.png" alt="LiveChat Dev Console Repository Block" width="800" height="378"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now you know that the Developer Console can optimize and automate a great deal of your work. In fact, you can manage almost your entire development process from the Developer Console’s application view. If you’d like to know more technical details on this process, &lt;a href="https://platform.text.com/docs/getting-started/app-guides/integrations"&gt;have a look at our docs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And what if you’re not a Developer Console user? What can I say — stop wasting time and sign up! It’s a superb place with multiple opportunities to create a passive income stream by building applications. &lt;a href="https://platform.text.com/"&gt;Check out our Developer Program &amp;gt;&amp;gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>announcement</category>
      <category>productivity</category>
      <category>github</category>
    </item>
    <item>
      <title>Automated Accessibility Testing</title>
      <dc:creator>Oliwia Połeć</dc:creator>
      <pubDate>Tue, 21 Sep 2021 13:24:48 +0000</pubDate>
      <link>https://dev.to/text/automated-accessibility-testing-2j8f</link>
      <guid>https://dev.to/text/automated-accessibility-testing-2j8f</guid>
      <description>&lt;p&gt;As described in our &lt;a href="https://developers.livechat.com/updates/all?category=accessibility" rel="noopener noreferrer"&gt;recent series of blog posts&lt;/a&gt;, our team has been working on improving the accessibility of the Chat Widget. While making the improvements, we wanted to maintain top-notch quality and ensure that while introducing new changes, there was no drop in standards. We use &lt;a href="https://www.cypress.io/" rel="noopener noreferrer"&gt;Cypress&lt;/a&gt; for all our automated testing, and so we decided to extend the existing testing suite by adding automated accessibility tests. In this article, I’d like to share with you what we’ve learned and how you can do this yourself!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu97qkhdsi091ux501l1z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu97qkhdsi091ux501l1z.png" alt="LiveChat Automated Accessibility Testing"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Example app overview
&lt;/h2&gt;

&lt;p&gt;In order to make it easier for you to follow, I’ve created a simple app that allows the user to submit a dummy form. You can find the repository &lt;a href="https://github.com/klarzynskik/cypress-a11y-testing" rel="noopener noreferrer"&gt;here&lt;/a&gt;. Don’t worry, the data you submit in the app is not sent anywhere, so you can play around with it as much as you want.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh3om04alhld7x1kze0rn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh3om04alhld7x1kze0rn.png" alt="Simple form with two three inputs and two buttons"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It’s created using the &lt;a href="https://reactjs.org/docs/create-a-new-react-app.html#create-react-app" rel="noopener noreferrer"&gt;Create React App&lt;/a&gt; scripts and using &lt;code&gt;yarn&lt;/code&gt; as a dependency manager (&lt;a href="https://classic.yarnpkg.com/en/docs/install/" rel="noopener noreferrer"&gt;installation instructions&lt;/a&gt;). After cloning the repository, all you need to do is install the dependencies by simply typing &lt;code&gt;yarn&lt;/code&gt; (or &lt;code&gt;npm install&lt;/code&gt; if you'll choose to do it without &lt;code&gt;yarn&lt;/code&gt;) in the console. Then, with &lt;code&gt;yarn start&lt;/code&gt; (or &lt;code&gt;npm start&lt;/code&gt;), you can run the app, and it will be available at &lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt;. Each step described in the article is reflected on the corresponding git branch.&lt;/p&gt;

&lt;p&gt;The repository also contains a simple integration test created with Cypress, located in the &lt;code&gt;functional.spec.js&lt;/code&gt; file.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;cypress-axe&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;In the previous article describing our &lt;a href="https://developers.livechat.com/updates/livechat-testing-chat-widget-accessibility" rel="noopener noreferrer"&gt;journey with accessibility testing&lt;/a&gt;, I mentioned the &lt;a href="https://www.deque.com/axe/browser-extensions/" rel="noopener noreferrer"&gt;axe DevTools&lt;/a&gt; browser extension. It allows the user to perform audits on the website, so that any accessibility issues can be discovered. This extension is based on the &lt;a href="https://github.com/dequelabs/axe-core" rel="noopener noreferrer"&gt;axe-core&lt;/a&gt; engine — a testing tool, validating against different types of rules and best practices.&lt;/p&gt;

&lt;p&gt;The same engine can be used with Cypress, thanks to the &lt;a href="https://github.com/component-driven/cypress-axe" rel="noopener noreferrer"&gt;cypress-axe&lt;/a&gt; package. It adds several custom commands to the Cypress API, which utilizes “axe-core” under the hood. It makes it possible to perform a11y audits directly while testing.&lt;/p&gt;

&lt;p&gt;Let’s, then, add the required dependencies to the project — we need the &lt;code&gt;cypress-axe&lt;/code&gt; and &lt;code&gt;axe-core&lt;/code&gt; (with the &lt;code&gt;--dev&lt;/code&gt; flag, so that these are added as developer dependencies):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add cypress-axe axe-core &lt;span class="nt"&gt;--dev&lt;/span&gt;
&lt;span class="c"&gt;# or&lt;/span&gt;
npm &lt;span class="nb"&gt;install &lt;/span&gt;cypress-axe axe-core &lt;span class="nt"&gt;--save-dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we need to let Cypress know that we have extended the list of commands. Therefore, we should add the following import statement in &lt;code&gt;cypress/support/index.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="err"&gt;​​&lt;/span&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cypress-axe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Great, with that in place, we can start using the library.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running audits
&lt;/h2&gt;

&lt;p&gt;The first command we’re going to use is &lt;code&gt;injectAxe&lt;/code&gt;. Basically, it inserts the &lt;code&gt;axe-core&lt;/code&gt; code into the application under test. Therefore, it needs to be run after the &lt;code&gt;visit&lt;/code&gt; call (and after each reload) to make sure the runtime is available on the website.&lt;/p&gt;

&lt;p&gt;Let’s create a separate &lt;code&gt;accessibility.spec.js&lt;/code&gt; test suite and utilize it in there:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should not report any errors during the accessibility audit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;injectAxe&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can run the tests now. To get more feedback while developing, we’ll run it in Cypress Test Runner with a full GUI. This can be done via the &lt;code&gt;open&lt;/code&gt; command (keep in mind to start the app earlier with &lt;code&gt;yarn start&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn run cypress open
&lt;span class="c"&gt;# or&lt;/span&gt;
npx cypress open
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And in the runner, we select &lt;code&gt;accessibility.spec.js&lt;/code&gt; to run it:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuiq7g6wbvv0ujglfkr4c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuiq7g6wbvv0ujglfkr4c.png" alt="Cypress GUI with two specs: accessibility and functional"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So far, so good — the test runs without any errors. After opening the developer tools and switching the console context to our app, we should have access to the &lt;code&gt;axe&lt;/code&gt; object, which indicates that it was indeed correctly injected:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8wc78l9ya1bv2t78uvqt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8wc78l9ya1bv2t78uvqt.png" alt="Cypress Test Runner with developers console opened and AXE object logged there"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It’s worth noting that the library also adds a &lt;code&gt;configureAxe&lt;/code&gt; command. This corresponds to &lt;code&gt;axe.configure&lt;/code&gt; from &lt;code&gt;axe-core&lt;/code&gt;, described &lt;a href="https://www.deque.com/axe/core-documentation/api-documentation/#api-name-axeconfigure" rel="noopener noreferrer"&gt;here&lt;/a&gt;. Using it is not needed in most cases but might be useful.&lt;/p&gt;

&lt;p&gt;We can now run the audit. This is done with the &lt;code&gt;checkA11y&lt;/code&gt; command. It can be run with the following parameters, all optional:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;context&lt;/code&gt; — a selector to a DOM element that should be analyzed.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;options&lt;/code&gt; — overrides for the global axe configuration whenever you want to set custom rules or checks for just that particular audit.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;violationCallback&lt;/code&gt; — custom handler for reported errors.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;skipFailures&lt;/code&gt; — allows you to prevent the test from failing on error and instead only log the error to the console.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s add it to the test and run it (on branch: &lt;code&gt;step-1&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should not report any errors during the accessibility audit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;injectAxe&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;checkA11y&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The app fails a test, informing the user about the violations. Upon clicking on each of the violations, the console logs more details, and the element causing the violation in each case is highlighted:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhs3pq78ph1du2i25tbgv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhs3pq78ph1du2i25tbgv.png" alt="Cypress Test Runner with failing accessibility audit"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The log for each violation contains the following set of information:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;command&lt;/code&gt; — informing us whether a violation is an error, warning, etc.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;id&lt;/code&gt; — identifier of the violated rule, for example, &lt;code&gt;button-name&lt;/code&gt; or &lt;code&gt;color-contrast.&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;impact&lt;/code&gt; — defining the severity of the violation.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tags&lt;/code&gt; — making it easier to identify which rulesets were violated (e.g., &lt;code&gt;wcag2a&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;description&lt;/code&gt; — brief details about the rule.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;help&lt;/code&gt; — information on how to fix the issue.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;helpurl&lt;/code&gt; — link to more details about the issue.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;nodes&lt;/code&gt; — affected elements.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Fixing the bugs
&lt;/h2&gt;

&lt;p&gt;In the example, we had three bugs reported. The first one was about the “clear the form” button missing “&lt;a href="https://dequeuniversity.com/rules/axe/4.3/button-name?application=axeAPI" rel="noopener noreferrer"&gt;discernible text&lt;/a&gt;.” As you can see, it’s an “icon button.” This means that screen reader users won’t be able to identify what it does! One way of fixing that is by adding an &lt;code&gt;aria-label&lt;/code&gt; attribute to the button.&lt;/p&gt;

&lt;p&gt;The second issue reported is informing us that the color contrast on the submit button is incorrect. Using “inspect” from the browser’s dev tools, indeed we can see that the contrast is 1.41, while &lt;a href="https://dequeuniversity.com/rules/axe/4.3/color-contrast" rel="noopener noreferrer"&gt;the rule&lt;/a&gt; requires at least 4.5 for smaller texts:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F27p4562f5fpco7u7my0i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F27p4562f5fpco7u7my0i.png" alt="Browser inspect on "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It can be easily fixed, for example by changing the text colors on the buttons to “black” instead of “white”:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw1uvpi3a4nm9ag08yo6a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw1uvpi3a4nm9ag08yo6a.png" alt="Browser inspect on "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The last error is caused by the form input missing a label, and &lt;a href="https://dequeuniversity.com/rules/axe/4.3/label" rel="noopener noreferrer"&gt;each one of them should have it&lt;/a&gt; so that screen reader users can easily navigate around. This can be fixed by either setting a &lt;code&gt;for&lt;/code&gt; attribute to the &lt;code&gt;id&lt;/code&gt; of the given &lt;code&gt;input&lt;/code&gt; for the &lt;code&gt;label&lt;/code&gt;, or if a &lt;code&gt;label&lt;/code&gt; is not present, by adding a corresponding &lt;code&gt;aria-&lt;/code&gt; attribute.&lt;/p&gt;

&lt;p&gt;Let’s apply all of the fixes (branch: &lt;code&gt;step-2&lt;/code&gt;) and re-run the tests:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnu89cy935l2ywar07l40.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnu89cy935l2ywar07l40.png" alt="Cypress Test Runner with passing accessibility audit"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nice! The app has passed the test, meaning that there were no accessibility violations found during the audit. With that test included in the pipeline, we can make sure we have not introduced any regressions in that area.&lt;/p&gt;

&lt;h2&gt;
  
  
  Audits are not all there is
&lt;/h2&gt;

&lt;p&gt;Audits are a powerful way of verifying accessibility violations; however, these are not always enough. The application might pass all of the automated audits, yet still not be accessible.&lt;/p&gt;

&lt;p&gt;One of the additional layers you can add to make sure you are building a good, accessible app, is to use  “accessible queries” for elements you interact with in the tests. In other words, you find elements by text, labels, roles, aria-attributes, etc., rather than using the IDs or data-test attributes. This applies to all layers of testing. There is a very useful project called &lt;a href="https://testing-library.com/" rel="noopener noreferrer"&gt;Testing Library&lt;/a&gt;, which provides you with UI-centric queries out of the box. It has a separate package for many different testing methods and libraries, including the Cypress one: &lt;a href="https://github.com/testing-library/cypress-testing-library" rel="noopener noreferrer"&gt;Cypress Testing Library&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let’s take a look at the test we initially had in the repository (file: &lt;code&gt;functional.spec.js&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should allow submitting data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[id=name]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Dummy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[id=last-name]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Tester&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[id=books]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[type=submit]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Thanks for submitting the form!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;should&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;be.visible&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It heavily relies on the IDs — these don’t matter much for the end-user since they rarely browse the web with the developer tools opened. They care much more about the labels we mentioned before, so let’s try to rewrite that test with that in mind.&lt;/p&gt;

&lt;p&gt;First, we need to install the dependency:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add @testing-library/cypress &lt;span class="nt"&gt;--dev&lt;/span&gt;
&lt;span class="c"&gt;# or&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; @testing-library/cypress &lt;span class="nt"&gt;--save-dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we add an appropriate import statement in &lt;code&gt;cypress/support/index.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;library&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;cypress&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;commands&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s it — we can make use of all the &lt;a href="https://testing-library.com/docs/queries/about/" rel="noopener noreferrer"&gt;queries&lt;/a&gt;! Let’s apply that to the test (branch: &lt;code&gt;step-3&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should allow submitting data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findByLabelText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Name:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Dummy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findByLabelText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Last Name:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Tester&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findByLabelText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Books&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findByText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Submit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findByText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Thanks for submitting the form!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;should&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;be.visible&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After running the test, it still passes:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvu0w1k74hu3ozpes0wjd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvu0w1k74hu3ozpes0wjd.png" alt="Cypress Test Runner with passing test after introducing queries from Testing Library"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Using the &lt;code&gt;findByLabelText&lt;/code&gt; command, we would have found the bug reported by the audit much sooner. Even if you were to decide not to use that package, referring to the &lt;a href="https://testing-library.com/docs/queries/about/#priority" rel="noopener noreferrer"&gt;priority&lt;/a&gt; of the queries description in the Testing Library docs would be beneficial for your users, and the quality of your tests.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keyboard navigation
&lt;/h2&gt;

&lt;p&gt;Additionally, you can test the flow of your app for just keyboard navigation. A lot of users use just the keyboard to browse the web, and it’s important that the whole application flow can be completed without using the mouse. You can read more about its importance in the &lt;a href="https://developers.livechat.com/updates/livechat-accessibility-keyboard-navigation" rel="noopener noreferrer"&gt;“Keyboard navigation”&lt;/a&gt; article.&lt;/p&gt;

&lt;p&gt;The way Cypress is built does not allow simulating “real” user actions out of the box. All of the actions there are triggered via JavaScript. Usually, this is not a problem; however, in terms of keyboard navigation, it is — &lt;a href="https://docs.cypress.io/api/commands/type#Tabbing" rel="noopener noreferrer"&gt;we won’t be able to use a “Tab” key&lt;/a&gt;, which is necessary to simulate how the user would navigate around. Luckily, the &lt;a href="https://github.com/dmtrKovalenko/cypress-real-events" rel="noopener noreferrer"&gt;Cypress Real Events&lt;/a&gt; package comes in handy (or its alternatives, e.g. &lt;a href="https://github.com/Bkucera/cypress-plugin-tab" rel="noopener noreferrer"&gt;Cypress Plugin Tab&lt;/a&gt;). It uses the &lt;a href="https://chromedevtools.github.io/devtools-protocol/" rel="noopener noreferrer"&gt;Chrome DevTools Protocol&lt;/a&gt; (so it only works in Chrome) in order to fire actual system events. Still, it has its downsides, though — you won’t be able to interact with certain system elements like default selects. If you were to determine that this is an important part of your app, other testing frameworks might be necessary.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a simple test for keyboard navigation
&lt;/h2&gt;

&lt;p&gt;Let’s create a simple test for the keyboard flow. Let’s add the package to our project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add cypress-real-events &lt;span class="nt"&gt;--dev&lt;/span&gt;
&lt;span class="c"&gt;# or&lt;/span&gt;
npm &lt;span class="nb"&gt;install &lt;/span&gt;cypress-real-events &lt;span class="nt"&gt;--save-dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And, as previously, import it in the &lt;code&gt;cypress/support/index.js&lt;/code&gt; to let Cypress know about the new goodies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cypress-real-events/support&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we should have access to all of the additional &lt;a href="https://github.com/dmtrKovalenko/cypress-real-events#api" rel="noopener noreferrer"&gt;API commands&lt;/a&gt;. What interests us most are &lt;code&gt;realPress&lt;/code&gt; (for single key presses) and &lt;code&gt;realType&lt;/code&gt; (for typing).&lt;/p&gt;

&lt;p&gt;Let’s add another simple test case, then, in the &lt;code&gt;accesibility.spec.js&lt;/code&gt; suite. We must use only the keyboard to navigate around and fill in all of the inputs in the form.&lt;/p&gt;

&lt;p&gt;Based on the application overview, after visiting the page, the first &lt;code&gt;Tab&lt;/code&gt; stroke should focus us on the "Name" field within the form. Let’s check that, then, using both the &lt;code&gt;realPress&lt;/code&gt; command from &lt;code&gt;cypress-real-events&lt;/code&gt; and the &lt;code&gt;focused&lt;/code&gt; one (&lt;a href="https://docs.cypress.io/api/commands/focused" rel="noopener noreferrer"&gt;from Cypress&lt;/a&gt;). The latter is from the Cypress API and gets the currently focused DOM element. However, since Cypress wraps the Application Under Test (AUT) in its own, separate iframe, and the events are fired using the CDP, we would need an extra click somewhere in the AUT. This would make sure the events are correctly fired for the AUT and not the Cypress runner.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should allow submitting with just keyboard&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findByText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Dummy form&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;should&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;be.visible&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;realClick&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;realPress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Tab&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So far so good. We would need an assertion to make sure that the focused element indeed has the “Name:” label. Let’s add a custom assertion for that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;assertFocusedInputLabel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;expectedLabel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;focused&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;$el&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`label[for="&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;$el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;"]`&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;should&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;have.text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;expectedLabel&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let’s add that to the test, along with the typing action:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should allow submitting with just keyboard&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findByText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Dummy form&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;should&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;be.visible&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;realClick&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;realPress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Tab&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;assertFocusedInputLabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Name:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;realType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Dummy&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now, let’s run it!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgvmey3uvxjsjzwmdeg5s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgvmey3uvxjsjzwmdeg5s.png" alt="Cypress Test Runner with passing test after introducing simple keyboard navigation"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The test passes, hooray! We can now do the same for other form elements, and finally, submit a form using the &lt;code&gt;Enter&lt;/code&gt; key (branch: &lt;code&gt;step-4&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;should allow submitting with just keyboard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findByText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Dummy form&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;should&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;be.visible&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;realClick&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;realPress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Tab&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;assertFocusedInputLabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Name:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;realType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Dummy&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;realPress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Tab&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;assertFocusedInputLabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Last Name:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;realType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;User&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;realPress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Tab&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;assertFocusedInputLabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Books&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;realPress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Space&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;realPress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Enter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findByText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Thanks for submitting the form!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;should&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;be.visible&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s run the test and see how it does:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwc3u2vnjigwcharbrjdh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwc3u2vnjigwcharbrjdh.png" alt="Cypress Test Runner with failing test after introducing keyboard navigation"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Oh no, a failure! Upon investigation, it seems that someone has added a &lt;code&gt;tabindex=-1&lt;/code&gt; attribute to the “Last name” field. That attribute will make the element “not tabbable” and as a result hide it from keyboard users. Let’s remove it (branch: &lt;code&gt;step-5&lt;/code&gt;) and re-run the tests:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqpg92yao3its4fn34uvp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqpg92yao3its4fn34uvp.png" alt="Cypress Test Runner with passing test after introducing keyboard navigation"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Perfect, we can see that it would find a bug in such a case. As you can see, the audit has passed, as this attribute is not disallowed. This is why having an additional layer for that would be highly beneficial in the long run.&lt;/p&gt;

&lt;h2&gt;
  
  
  Static analysis
&lt;/h2&gt;

&lt;p&gt;The other things — apart from automated tests — you can add to prevent accessibility mistakes, are accessible plugins for the linters. In the same way they let you know about missing semicolons, they can warn you whenever necessary attributes are missing, or any other violations are made.&lt;/p&gt;

&lt;p&gt;A good example of such a tool is the &lt;a href="https://marketplace.visualstudio.com/items?itemName=deque-systems.vscode-axe-linter" rel="noopener noreferrer"&gt;axe Accessibility Linter&lt;/a&gt; VS code plugin. With the same &lt;code&gt;axe-core&lt;/code&gt; rules engine, the plugin will inform you whenever an accessibility bug appears.&lt;/p&gt;

&lt;p&gt;The other example is an accessibility eslint plugin for JSX elements: &lt;a href="https://www.npmjs.com/package/eslint-plugin-jsx-a11y" rel="noopener noreferrer"&gt;eslint-plugin-jsx-a11y&lt;/a&gt;. Although it would not inform you about all of the errors, it would for sure prevent you from making the most basic mistakes. The eslint plugin has a big advantage over any editor plugins — it can be run as a &lt;a href="https://gist.github.com/estorgio/e8bcaa8e87d0fcdcf85fdf598956e34c" rel="noopener noreferrer"&gt;pre-commit hook&lt;/a&gt; or on the CI before the build process. Thanks to that, the verification can be forced within the project configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap-up
&lt;/h2&gt;

&lt;p&gt;Making our Chat Widget accessible has been really enlightening for us, in many areas. It was also hard work, requiring a lot of learning. We believe in the value automated tests bring, and since accessibility is one of our biggest priorities, we want to make sure that it’s being thoroughly tested. We hope that with this description of our test setup, you’ll try it yourself.&lt;/p&gt;

&lt;p&gt;Be sure to let us know if you have any questions!&lt;/p&gt;

</description>
      <category>testing</category>
      <category>showdev</category>
      <category>a11y</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Screen readers: hearing the unseen</title>
      <dc:creator>Oliwia Połeć</dc:creator>
      <pubDate>Wed, 30 Jun 2021 12:20:14 +0000</pubDate>
      <link>https://dev.to/text/screen-readers-hearing-the-unseen-55nb</link>
      <guid>https://dev.to/text/screen-readers-hearing-the-unseen-55nb</guid>
      <description>&lt;p&gt;A screen reader is software which forms part of a group of Assistive Technologies and renders graphical user interface content in the form of speech or braille output. This kind of software is essential for people that are blind or have any visual impairments as it allows them to interact with a computer or mobile devices in much the same way as the screen allows it for sighted people. In order to properly describe the particular parts of the user interface, the software needs the context and/or additional metadata provided by the application developer in order to properly present the content using a text description.&lt;/p&gt;

&lt;p&gt;There is a variety of screen reader software to choose from, and there are multiple ways of feeding them with data used for content descriptions. In this article, we will dive into this topic and show how this &lt;strong&gt;remarkable software makes it possible to use a computer or mobile devices without the need for visual references.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Examples of available screen readers
&lt;/h2&gt;

&lt;p&gt;There are quite a lot of different screen reader applications to choose from. They can be implemented in the form of native operating system support, like VoiceOver by Apple Inc. They can also be implemented as downloadable third-party software, like JAWS, which requires a paid license, or NVDA, which is built as an open-source solution and is free to use. Screen readers can even be found in the form of add-ons to software already being used by the user. For example, ChromeVox, which is available as a web browser add-on for Google Chrome. Despite their abundance, they all share the same purpose and basic functionality, but there are many differences in the way they handle their features. Some of them are more obvious, like ones in the customization interface or available options.&lt;/p&gt;

&lt;p&gt;There are also differences in the keyboard shortcuts, which adds a barrier for the user if he/she ever wants to change their screen reader of choice. It is also good to keep in mind that screen readers can differ in the way they recognize application content, so it is also good to verify your application on more than one of them, just as you would when testing on different devices or web browsers. Analyzing all available solutions on the market would definitely require a separate article, but we can briefly check the most commonly used options, which according to &lt;a href="https://webaim.org/projects/screenreadersurvey8/#used" rel="noopener noreferrer"&gt;the screen reader survey&lt;/a&gt;, are NVDA (72.4%), JAWS (61.7%), and VoiceOver (47.1%).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnbkz7ynv3kfe7jygmvwc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnbkz7ynv3kfe7jygmvwc.png" alt="LiveChat screen readers graph"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;NVDA, which stands for NonVisual Desktop Access, is free, open-source screen reader software which works on the Microsoft Windows operating system. It was released in 2006 and is available in 48 languages. It also supports braille displays.&lt;/p&gt;

&lt;p&gt;JAWS, which stands for Job Access With Speech, is paid screen reader software which works on the Microsoft Windows operating system. It was released in 1995 and was originally created for the MS-DOS operating system, and a fun fact is that this version is still available as JDOS and is free to use. It supports 10 languages. Its unique feature is the JAWS Scripting Language, which allows the user to add an accessibility layer for programs that were not designed with accessibility in mind.&lt;/p&gt;

&lt;p&gt;VoiceOver is free-to-use screen reader software built into the operating systems created by Apple Inc. As it is available both on the desktop and mobile operating systems, it supports touch and keyboard navigation. It was released in 2005 together with Mac OS X 10.4. Its main strong point is its native support for the operating systems as they were both built by the same company. A unique feature is its support for multitouch gestures, not only on mobile devices but also on desktop trackpads utilizing the rich trackpad support in Mac OS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Screen reader customization
&lt;/h2&gt;

&lt;p&gt;Most screen readers allow the user to customize their experience of using this software. The precise set of available options differs among the various types of screen readers, but there are a couple of features that are most commonly used and supported.&lt;/p&gt;

&lt;p&gt;First of all, the user can specify the language in which the content should be read. Most screen readers support more than one language depending on the support of a particular program.&lt;/p&gt;

&lt;p&gt;Another common setting is the level of verbosity. This allows the user to specify how much speech feedback is needed. It depends mainly on the level of visual impairment and so, for example, users who have partial vision can use less verbose speech and focus mainly on the content itself and not the metadata. On the other hand, blind users could need the full verbosity level, including all additional descriptions of content and placement of, for example, current interactive elements in the scope of the application. This is one of the reasons why the developer must provide all available content metadata as it is the user who should decide which of them is needed for uninterrupted usage of the application.&lt;/p&gt;

&lt;p&gt;One more popular setting for screen readers is the reading speed. This is pretty self-explanatory — it specifies how fast the lector should read the text. It is usually specified in a words-per-minute unit. In English, the typical read speed ranges between 120 to 150 words per minute, where advanced and fast screen reader users can understand content being read at a speed of even &lt;a href="https://www.vincit.fi/en/software-development-450-words-per-minute/" rel="noopener noreferrer"&gt;450 words per minute&lt;/a&gt;. Even if most screen reader users don't require such high speed, it is still common for them to use higher rates than that of typical spoken language. It is important to keep in mind that the first impression that long-to-read content slows down the user can be deceptive as when set at high reading speed rates, it is being read blazingly fast. Remember, don't worry too much about long descriptions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Screen reader usage and the Web
&lt;/h2&gt;

&lt;p&gt;Each HTML document begins with an &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt; tag, and this is the first place for an appropriate accessibility setting. Using the &lt;code&gt;lang&lt;/code&gt; attribute, it is possible to specify the language for the whole document, which the screen reader will use in order to determine which language to use for speech. The second element close to the beginning of the HTML document is the &lt;code&gt;&amp;lt;title&amp;gt;&lt;/code&gt; tag, which contains the title of the current document. It is read by the screen reader when first loading the webpage.&lt;/p&gt;

&lt;p&gt;Web document content is always presented in a linear way when using a screen reader. This is a totally different approach for content layout than typical graphical user interfaces, which are commonly multidimensional. One of the best representations of these differences in perception of the layout is the automated telephone menu system. The webpage content is being unveiled to the screen reader user one step at a time. This implies that the structure of user interfaces needs to take into account the complexity and also the order of the interactive elements and main page content. One common issue associated with this perception difference is the top navigation menu. In most cases, it is the first set of interactive elements in the navigation order. The screen reader needs to go through all of them in order to access the main page content, which is not the case for graphical interface users. As a solution to this problem there is the common technique of implementing a “skip to main content” button, being the first interactive element on the page, and it allows for quick access to the main page content.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftpv3fmxo5thbbyc0p2tw.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftpv3fmxo5thbbyc0p2tw.gif" alt="LiveChat accessibility screen reader navigation"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Navigation through webpages using screen readers is possible in various ways. Some of them provide users with an option to navigate content quickly, despite the linear nature of audio interfaces. The most basic navigation consists of moving one step forward by pressing the &lt;code&gt;[Tab]&lt;/code&gt; key or one step backward by pressing the &lt;code&gt;[Shift+Tab]&lt;/code&gt; key combination. Each step made like this will focus on the next or previous interactive element, like links, buttons, form controls, etc. The screen reader will then announce the currently focused element using its node type and additional metadata.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmfo16pxdue4j9xslfhqb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmfo16pxdue4j9xslfhqb.png" alt="LiveChat accessibility headings navigation"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The second type of navigation available in screen readers is heading navigation. The screen reader, via a dedicated shortcut, allows the user to present a webpage map of available headings (in the form of a list), which he/she can then use to navigate directly between. This is a very commonly used technique as it allows quick access to the interesting parts of the document and makes it easy to skip those parts that are not of interest to the user. Because of this technique, it is very important to maintain a logical order in heading structure. For example, nesting an H2 element inside an H5 element should be avoided.&lt;/p&gt;

&lt;p&gt;The third common type of navigation using screen readers is ARIA landmark navigation. It is similar to headings navigation, but instead of presenting a map of the heading elements, it allows navigation through the meta structure of the webpage using HTML5 semantic elements like &lt;code&gt;&amp;lt;main&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;nav&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;header&amp;gt;&lt;/code&gt;. And also, as with heading navigation, this technique allows quicker access to the desired parts of the page while also allowing quick skipping of unwanted content. With this type of navigation, it is important to utilize the available native HTML5 elements with their semantic meaning while structuring the document instead of using &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; elements everywhere.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fza0zp4ko2nnxzqk05i4o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fza0zp4ko2nnxzqk05i4o.png" alt="LiveChat accessibility landmark navigation"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Regarding the chosen navigation technique, the screen reader user will rely on the information being provided by the content of the webpage to understand and use this content. Apart from the previously mentioned possibilities to provide understandable document structure, there are other smaller things that can be done to increase the accessibility of the content. For example, because screen reader users will go through each paragraph one after another and can skip one, it is good to place distinguished information of a paragraph in the first sentence. Additionally, screen reader users can also navigate by tables, lists, forms, etc.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2nicrhc2gufup1qyoywj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2nicrhc2gufup1qyoywj.png" alt="LiveChat accessibility form graph"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Last but not least, the webpage developer can (and should) use ARIA attributes to attach additional metadata for various elements on the page. There are quite a lot of them, and they serve different purposes. The most common is &lt;code&gt;aria-label&lt;/code&gt;, which directly attaches the text content to the element that should be used for this element description. For example, when you have an icon button (hamburger menu) it will not have natural text content available.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhkun7kdeu2b52r9ynq81.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhkun7kdeu2b52r9ynq81.png" alt="LiveChat accessibility aria label"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The second most often used attributes are combinations of &lt;code&gt;id&lt;/code&gt; and &lt;code&gt;aria-describedby&lt;/code&gt;, which together creates a relation where one element's content describes the other element. Another commonly used attribute, &lt;code&gt;role&lt;/code&gt;, makes it possible to specify for the screen reader the functional purpose of that element. There is also one common but yet special attribute, &lt;code&gt;aria-hidden&lt;/code&gt;, which instead of adding information to the screen reader, removes it and all its children in the HTML tree. This serves the purpose of hiding elements that do not provide valuable information.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing accessibility support using a screen reader
&lt;/h2&gt;

&lt;p&gt;There is a lot of knowledge to be learned when it comes to building accessible applications and webpages. There is also a ton of experience to be gained just trying to do everything right. To help yourself with making sure that your webpage or application is properly accessible, it is really useful to utilize the screen reader in the workflow. The same way as we test our code locally on different devices and web browsers in order to verify if the content is laid out properly and if it works functionally, we could and should verify if it is accessible.&lt;/p&gt;

&lt;p&gt;Of course, screen readers are not automated tools for detecting accessibility issues, but by learning how to use them, especially with the application you’re working on, it is an insightful experience. This experience allows us to interact with created applications or documents in different, but very important ways, by listening to the content being read. And because we’re listening to the content, it is easier to catch potential issues with navigation order, meaningful descriptions of images, verbosity level of the interface, and more. Thanks to free-to-use solutions like open-sourced NVDA for Microsoft Windows and the natively supported VoiceOver for macOS, it is possible to just start using it without the need for any investments.&lt;/p&gt;

&lt;p&gt;An interesting outcome of testing applications with screen readers is that they can provide feedback as to the overall application design, which can improve the accessibility of the page for all kinds of visual disabilities or even increase the ease of use for sighted users.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap-up
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F30mo2ytmp3dyzodmr4p6.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F30mo2ytmp3dyzodmr4p6.gif" alt="LiveChat accessibility screen readers"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One part of making applications accessible is allowing the users to interact with them easily through screen reader software. This software is a fundamental player when it comes to possible user inputs and should be treated on a par with pointer or touch interactions. &lt;strong&gt;We, as responsible developers, need to treat the accessibility of our applications the same way we treat the visual attractiveness and usefulness of the graphical user interfaces we build.&lt;/strong&gt; The amount of possibilities in terms of different navigation techniques in screen readers can be intimidating, but it is only a matter of practice to feel more comfortable using it. If you ever feel lost you can easily check the guidelines, like the ones for &lt;a href="https://dequeuniversity.com/screenreaders/nvda-keyboard-shortcuts" rel="noopener noreferrer"&gt;NVDA&lt;/a&gt; or &lt;a href="https://dequeuniversity.com/screenreaders/voiceover-keyboard-shortcuts" rel="noopener noreferrer"&gt;VoiceOver&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>a11y</category>
      <category>showdev</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Keyboard navigation</title>
      <dc:creator>Oliwia Połeć</dc:creator>
      <pubDate>Mon, 28 Jun 2021 12:20:51 +0000</pubDate>
      <link>https://dev.to/text/keyboard-navigation-e7p</link>
      <guid>https://dev.to/text/keyboard-navigation-e7p</guid>
      <description>&lt;p&gt;It should be possible to control any desktop application using just a keyboard. There are certain keys and key combinations that are de facto standard for most applications, and users should be able to expect them to work.&lt;/p&gt;

&lt;p&gt;This is a vastly important topic from the accessibility point of view. For a large group of people, a keyboard might be one of the primary ways of interacting with a computer. Pointer devices, while being commonly used by most, just don't work at all for people with visual disabilities, for example.&lt;/p&gt;

&lt;p&gt;It's a humane thing to design and put work into implementing an application with these concerns in mind. For example, all interactive elements should be reachable using the keyboard alone, and the navigation should happen in a logical sequence. In addition to that, a visual affordance such as a focus ring should &lt;strong&gt;always&lt;/strong&gt; be available for sighted (or partially sighted) users.&lt;/p&gt;

&lt;p&gt;In fact, this is a very important thing, and not only for people with disabilities. It's often crucial when it comes to supporting power users of your application. Using a keyboard can be much more effective than a mouse in some cases. However, it usually requires some manual skills and muscle memory to become really effective at this.&lt;/p&gt;

&lt;p&gt;Even if you are not a power user, you probably do some simple tasks using just a keyboard. There are things that we have all internalized and take for granted, but probably we don't appreciate them very much. They already feel natural to us, and it would feel weird if we were to ever find ourselves in a situation where they didn’t work. Can you imagine a chat application which doesn't send a message when hitting the Enter key? Or which wouldn't allow you to change the cursor position using the arrow keys? I can't either. This is just something so simple that we all take for granted. I can't even imagine how it would be to rely on the keyboard heavily, for everything, and having to deal with a plethora of applications with varying support for proper keyboard navigation.&lt;/p&gt;

&lt;p&gt;If those things don't work, the application in question doesn't work properly. It's not a matter of choice, priorities, or anything else. Luckily, people are becoming more and more aware of the subject of accessibility, and we can see a great uplift in concern about this.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F19676y7az52lwl29cgfl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F19676y7az52lwl29cgfl.png" alt="LiveChat focus management"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Focus management
&lt;/h2&gt;

&lt;p&gt;When using the keyboard to navigate an application, it's important to always display a focus indicator, most commonly known as a focus ring, on the currently active element. The browser’s built-in styles, which historically have not been compatible with many website designs, were a reason for developers to disable them altogether. This is a serious accessibility concern; such actions should never be taken unconditionally. To accommodate the design of a site, a custom focus ring can be implemented that will be a better fit for the site.&lt;/p&gt;

&lt;p&gt;It's OK to hide these visual cues when the user is using a pointer device to navigate the site, but they should be visible as soon as the user switches to keyboard navigation. Usually, this behavior can be implemented by using &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible" rel="noopener noreferrer"&gt;&lt;code&gt;:focus-visible&lt;/code&gt; selector&lt;/a&gt;, but keep in mind that &lt;a href="https://caniuse.com/css-focus-visible" rel="noopener noreferrer"&gt;it’s not yet supported by all the browsers&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The topic of focus management is broader than just displaying a focus ring correctly, and for most patterns required for robust and correct keyboard navigation/focus management, a JavaScript-based solution is required.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxz16u2f1zidq9v4gwpuv.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxz16u2f1zidq9v4gwpuv.gif" alt="LiveChat accessibility modal navigation"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  tabindex
&lt;/h2&gt;

&lt;p&gt;Let’s recap what a tabindex is and what its different values mean for the browser.&lt;/p&gt;

&lt;p&gt;A value of 0 means that the element is focusable and participates in the tab sequence, whereas a value of -1 means that the element can be focused programmatically, but it doesn’t participate in the tab sequence.&lt;/p&gt;

&lt;p&gt;Other numeric values can, technically, be used as well. Positive ones actually change the order of the tab sequence; so it’s possible to move an element to the front of that sequence by providing a value higher than all others. This is, however, discouraged by all experts, and a consensus has been reached in the community that this should never be used as it creates a mismatch between the tab sequence and the visual order.&lt;/p&gt;

&lt;h2&gt;
  
  
  Basis patterns
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Tabbing
&lt;/h3&gt;

&lt;p&gt;This is something that usually comes for free if we use proper HTML structure. When pressing the Tab key, the focus should be switched to the very next &lt;strong&gt;interactive&lt;/strong&gt; element. When pressing Shift+Tab we should be switched to the previous element. When going forwards and backwards using those key combinations, we should cycle between the same elements. If we leave an element, we should be able to easily get back to it unless there is a strong reason why this shouldn't be possible (for example when the previous element was associated with some expirable content when the expiration would be properly announced to the user).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4l57lsyb8f6todneu036.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4l57lsyb8f6todneu036.gif" alt="LiveChat accessibility tabbing"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;An important thing to remember is that all interactive elements should be reachable using a keyboard. So for example, if we have an element that appears when hovering over another element with a pointer device, then we should also display it when navigating using a keyboard.&lt;/p&gt;

&lt;h3&gt;
  
  
  Arrow navigation in menus
&lt;/h3&gt;

&lt;p&gt;When it comes to navigation through menus, there are two options — one based on the &lt;code&gt;aria-activedescendant&lt;/code&gt; attribute, and the other one based on &lt;code&gt;tabindex&lt;/code&gt; manipulations. It's a matter of choice which one gets used. However, from the user experience perspective, both are equivalent — the up and down arrows can be used to go through the menu items, and Enter/Space keys can be used to select the currently active item (and thus also close the menu).&lt;/p&gt;

&lt;p&gt;The first option is to leave the focus on the menu button (the element which triggers the menu to be opened) and only &lt;strong&gt;highlight&lt;/strong&gt; visually the "active" list element by juggling the values of the &lt;code&gt;aria-activedescendant&lt;/code&gt; attribute in such a way that it points to the highlighted menu item using the global ID value of that active menu item.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdfaabce2d28wswbx7zwv.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdfaabce2d28wswbx7zwv.gif" alt="LiveChat accessibility focus management"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The alternative to that is to exclude all menu items (apart from the active one) and the menu button itself from the tab sequence by setting &lt;code&gt;tabindex="-1"&lt;/code&gt; on them. The currently active menu item should have its tabindex set to &lt;code&gt;0&lt;/code&gt;. When navigating through menu items using arrows, the previous menu item should be excluded from the tab sequence and the next item should be included in it by properly manipulating the &lt;code&gt;tabindex&lt;/code&gt; attribute. To actually move the focus to the next menu item, it is also required that its &lt;code&gt;focus&lt;/code&gt; method be called.&lt;/p&gt;

&lt;p&gt;Note that, usually, pressing Tab or Shift+Tab while navigating through a menu should bring the user to the next (or previous) element outside of the menu (and its menu button). When using the second way of implementing arrow navigation, it might be required to bring back &lt;code&gt;tabindex="0"&lt;/code&gt; on the menu button so it can be navigated back to.&lt;/p&gt;

&lt;h3&gt;
  
  
  Closing with Escape
&lt;/h3&gt;

&lt;p&gt;When any element pops out to the user — be it a menu, tooltip, modal, or an emoji picker — then it should be closeable by pressing Escape. There are cases when it is permitted to not implement this pattern — for example, when an opened modal can't be reopened again, but not implementing this interaction should be a conscious design decision.&lt;/p&gt;

&lt;p&gt;To implement this it is often required to add a global &lt;code&gt;keydown&lt;/code&gt; listener on the &lt;code&gt;document&lt;/code&gt; element. The listener should check if the Escape key has been pressed, and if yes, then it should close the open element in response to that.&lt;/p&gt;

&lt;p&gt;If you are dealing with nested modals (or a tooltip within a modal, or any other cases that introduce this kind of nesting), then you should ensure that only the element that is open on the very top should be closed with a single Escape key. It would provide a bad user experience if, for example, both modals were to be closed at the same time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpkn5pcfffrfkp4f8korw.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpkn5pcfffrfkp4f8korw.gif" alt="LiveChat accessibility closing"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Item activation
&lt;/h3&gt;

&lt;p&gt;This is an easy one — most activatable elements should be activated by pressing Enter or Space. It's easy to forget one or the other when implementing custom buttons (which is sometimes the only way to satisfy the design/layout constraints) or when implementing custom input controls like checkboxes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Advanced patterns
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Focus trapping
&lt;/h3&gt;

&lt;p&gt;In a variety of scenarios, it is desirable to lock user navigation to a certain element. When pressing Tab on the very last interactive element within it, focus should be moved to the very first element in the enclosed group. This most commonly happens when a modal gets displayed to the user. In such a situation the background usually gets dimmed in one way or another; so it doesn't make sense to allow the user to navigate to any element outside the modal. They wouldn't see the active element then, or the modal would have to be closed.&lt;/p&gt;

&lt;p&gt;There is no HTML way to achieve this behavior, and a JavaScript-based solution is required to implement it. The idea behind popular solutions is to render additional sentinel elements (for example, empty spans) before and after the locked element. They can either be made focusable so, whenever they receive focus, the focus can be moved programmatically to the appropriate element within the trapped element, or the default action of pressing the Tab can be prevented, and the focus can be moved programmatically to the appropriate element.&lt;/p&gt;

&lt;h3&gt;
  
  
  Auto focus &amp;amp; focus restoration
&lt;/h3&gt;

&lt;p&gt;This pattern is important for most situations in which a new element that contains navigable elements gets opened in response to the user interaction or when an automatically opened element (like a modal) is meant to interrupt the user.&lt;/p&gt;

&lt;p&gt;Whenever we deal with such a situation, we need to move focus to the element that just got opened. Very often, the new element gets actually rendered to the body; so it isn't near the current navigation sequence anyway. If the element got opened in response to a user interaction, then it is a signal from the user that they want to interact with that element; so focus should not stay on the triggering element. By querying the DOM of the opened element, the focus should be placed on the first tabbable element in it, unless there is no such element, then the opened element itself should be focused.&lt;/p&gt;

&lt;p&gt;In a similar vein, it's desired that the focus should return to the triggering element when the opened element gets closed. It just makes the most sense as that's the last thing the user remembers. It brings the user to the same context that they previously left.&lt;/p&gt;

&lt;h3&gt;
  
  
  Grid pattern
&lt;/h3&gt;

&lt;p&gt;While the pattern is very useful for handling tabular content (like spreadsheets), it's not limited to those kinds of use cases. Actually, it can be used purely to create a sort of navigation depth.&lt;/p&gt;

&lt;p&gt;The idea is that the particular container should only make a single element within it focusable, so only that single element acts as a stopgap when tabbing through an application. To navigate to other elements (cells within a grid), arrow keys can be used. This requires the application to have strict layout constraints since the direction of the pressed arrow key should always move focus to the other cell in that direction, and this should always match the visual layout. It would be confusing for the user if pressing a down arrow were to move focus to the element displayed on the right, or things like that.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjpx8cfg34rkc9idzxewo.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjpx8cfg34rkc9idzxewo.gif" alt="LiveChat accessibility grid pattern"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This pattern is great for very long lists of repetitive elements, like, for example, a list of messages in a chat application. Without using it, the user would have to tab through the whole content of the chat (which grows with time) to get to the elements above or below that chat feed.&lt;/p&gt;

&lt;p&gt;In addition to that, certain cells can have interactive elements within them — a rich message card with interactive buttons can be a grid cell. One can enter such a grid cell by activating it using standard Enter/Space keys. While in the grid cell, the focus should be trapped within it; so pressing Tab repeatedly would not navigate the user to any element outside of this card, and to get back to the main grid navigation, one would press Escape. As you can see in this example, this combines many of the previously mentioned patterns to provide a very rich user experience.&lt;/p&gt;

&lt;p&gt;It’s worth noting that the last active element in the grid stays focusable when one tabs away from the grid. This makes coming back to the grid a better experience since the user is brought back to a familiar context.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ps90xyiwor92bfb6cru.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ps90xyiwor92bfb6cru.gif" alt="LiveChat accessibility keyboard navigation showcase"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;As we can see, implementing some of these patterns is quite involved. To do it right, we need to both understand the accessibility requirements and implement several JavaScript-based solutions that often require beyond-novice knowledge of the browser APIs. Doing that in a generic fashion for reusable components that can be rendered in a variety of scenarios is very hard.&lt;/p&gt;

&lt;p&gt;Luckily, there are packages that can help you with that, and we highly encourage using them. However, when combining several patterns like this for a single element, you might encounter some interoperability issues between packages. Our widget is implemented using React, and we have discovered that &lt;a href="https://react-spectrum.adobe.com/react-aria/" rel="noopener noreferrer"&gt;React Aria&lt;/a&gt; is a great project, focused on providing developers with a proper base for these and many more accessibility-oriented patterns while allowing developers to provide their own UI and styling solutions.&lt;/p&gt;

</description>
      <category>a11y</category>
      <category>showdev</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How we made the chat widget accessible for people with visual impairments</title>
      <dc:creator>Oliwia Połeć</dc:creator>
      <pubDate>Thu, 24 Jun 2021 12:48:58 +0000</pubDate>
      <link>https://dev.to/text/how-we-made-the-chat-widget-accessible-for-people-with-visual-impairments-41d0</link>
      <guid>https://dev.to/text/how-we-made-the-chat-widget-accessible-for-people-with-visual-impairments-41d0</guid>
      <description>&lt;p&gt;Matching colors to achieve the minimum WCAG contrast score might be perceived as a simple task. After all, there are plenty of free tools available — from websites like &lt;a href="https://colourcontrast.cc/" rel="nofollow noopener noreferrer"&gt;colourcontrast&lt;/a&gt; to design tool plugins for &lt;a href="https://www.figma.com/community/plugin/748533339900865323/Contrast" rel="nofollow noopener noreferrer"&gt;Figma&lt;/a&gt; or &lt;a href="https://cluse.cc/" rel="nofollow noopener noreferrer"&gt;Sketch&lt;/a&gt; — that can help you calculate the proper color contrast for your designs. In our case the challenge was to solve contrast problems when colors can be customized by the users. In this article we want to share what we have learned and how we build accessible color palettes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where to start?
&lt;/h2&gt;

&lt;p&gt;Start by doing an audit using Google Lighthouse, or you can find a tool that will fit your needs in this article. Gathering together issues related to low color contrast and grouping them into those which can be fixed quickly and those which will require special solutions was very helpful and speeded up the whole process. The low-hanging fruit was fixing the contrast between elements that don't inherit a primary color and also fixing the contrast between surfaces. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi7zp12yfg1v6ukkrm7d6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi7zp12yfg1v6ukkrm7d6.png" alt="LiveChat accessibility color issues"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;They were easy to resolve because we decided that some components will always have a set of fixed color values, and thanks to that we can easily predict the contrast in relation to the different surfaces. By doing an audit and refining each element individually, we recreated our new grayscale palette.&lt;/p&gt;

&lt;p&gt;Do an audit using specialized tools, and group issues based on their level of difficulty.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance over Preference
&lt;/h2&gt;

&lt;p&gt;Take a look at these two buttons:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmf9zahxml9xm2w8fd3cy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmf9zahxml9xm2w8fd3cy.png" alt="LiveChat accessibility buttons comparison"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Which one is more appealing to you?&lt;/p&gt;

&lt;p&gt;I assume that the button on the left might look more appealing to most respondents; however, working with accessibility in mind is not a matter of preferences — it’s simply down to performance. If I want to measure the button's performance, my question should be: Do you have a problem reading any of those buttons? Then filter out everyone who can read both and focus only on people who have a hard time reading any of the buttons. There is a thin line in matching colors for the button such that they fulfill WCAG guidelines and the button still looks the way most people expect to see it. Those expectations of specific color combinations might exist because people just get used to them, but changing the combinations to have a contrast score of at least 4:5:1 won't bother anyone that much, and it might help others to better perceive the interface. Our eyes and vision change over time, just like the rest of our bodies. Some people experience age-related vision changes that interfere with their ability to see clearly for reading and other close vision tasks. We don't know what the exact demographic of chat widget end-users is. However, the chats' scale is approximately 1.5 million per day; so there was a risk that a significant number of users might have problems when interacting with the LiveChat Widget.&lt;/p&gt;

&lt;p&gt;It's important not to rely solely on the WCAG math for calculating contrast. You can strive for the best score and readability by tweaking colors, but at the end of the day, testing it with real users or doing the accredited accessibility audit is a must.&lt;/p&gt;

&lt;p&gt;Eliminate your personal bias on preferred color combinations and remember that you are designing it for ALL users.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F544h5q01ey0ya331mown.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F544h5q01ey0ya331mown.png" alt="LiveChat accessibility improved buttons"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Framer + polished.js to the rescue
&lt;/h2&gt;

&lt;p&gt;Nowadays, design tools offer several ways to solve inaccessible color problems. You can install a plugin to your favorite design tool and test many color combinations one by one. However, it might be a time-consuming task, especially if you provide color customization in your app, so why not automate this process? Framer, a tool that combines both code and design, was a lifesaver when designing elements that inherit primary colors. The tool allows you to use mechanisms that function in the actual code environment. We've used one of those available mechanisms, from the polished.js package. Thanks to this package, we could test for accessible colors on many components simultaneously.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqgc3gz28jedp52p66umm.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqgc3gz28jedp52p66umm.gif" alt="LiveChat accessibility framer colors"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can see how the components and the contrast score changes when tweaking the primary color. It speeds up the whole process dramatically. The cool thing is that we have also implemented this package inside the Chat Widget code, so the design and production are based on the same environment. The important thing is that when the user customizes the primary color of the widget, the system relies on the polished.js mechanism. This matches whichever text or icon color (black or white) scores the highest. Because of this, users might even get black text on a blue button if white text would only achieve a minimum 4:5:1 contrast ratio for that particular blue background. The way we measure combination contrast is not perfect, because the WCAG guidelines, as the name suggests, are just recommendations, and I believe that the proper math for color calculation that mirrors human perception is yet to be invented. Still, we think it’s better to have this automation than always having white be the foreground to a primary color.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8p6kix9alsuf6cgbavol.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8p6kix9alsuf6cgbavol.gif" alt="LiveChat color changing in Agent App"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Do accessible colors have to be ugly?
&lt;/h2&gt;

&lt;p&gt;Statements about ugly accessible colors might be a consequence of the high contrast modes you may have seen over time on various websites.&lt;/p&gt;

&lt;p&gt;It's easy to make a false assumption about accessible colors if you're just starting with the topic and you've seen too many of those websites. Another thing is that perceiving color is a subjective matter. When we think about the color being beautiful, it only exists in our heads as a pleasant feeling. However, a fairly useful method would be to observe the most popular colors on the web. I think that for the sake of argument, we can call popular colors appealing. After all, they are popular for a reason. Gather and refine those colors by increasing or decreasing their lightness so they will have a minimum 4:5:1 foreground to background contrast ratio. For example, if you want to fix an inaccessible color, decide whether you want to darken the background and lighten the foreground or do the opposite — lighten the background and darken the foreground. Both ways are good; use whatever works for your design to achieve a good contrast score.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmbx2aks9y0nq9rxagtci.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmbx2aks9y0nq9rxagtci.png" alt="LiveChat accessibility high contrast mode"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We have decided to make the theme colors slightly darker so that all our predefined theme colors work well as a background to a white foreground. We didn't want to include colors with high luminance, like yellow or orange, in a predefined set of colors because combining them with white surfaces results in low contrast. Users still have a choice if none of those five colors meet their expectations. They can pick whatever color they want as a primary color, and we will adjust the text color on the messages and buttons. Achieving the proper text color is done automatically by the polished.js library. In short, whatever color you pick, polished will match the text color, white or black, depending on which combination contrast score is the highest.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fre5s7teko8v6xzznegr2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fre5s7teko8v6xzznegr2.png" alt="LiveChat accessibility predefined colors"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Two problems at once
&lt;/h2&gt;

&lt;p&gt;Working on accessible colors in LiveChat Widget was an excellent opportunity to tidy up the code and create a single source of truth for design tokens. The term “design tokens” refers to properties like colors, font sizes, spacings, and even transitions. The main premise of having organized design tokens, especially colors, is to maintain consistency within the application. Synchronizing colors between design and code will also help you keep the product palette accessible (automated checks) and predictable; so if you have the opportunity to do that, go for it!&lt;/p&gt;

&lt;h2&gt;
  
  
  Pay attention to :focus
&lt;/h2&gt;

&lt;p&gt;You are probably familiar with that blue border that appears from time to time when you scroll through websites. Those elements are called focus indicators. Some people don't like that browsers add them by default to components like inputs or buttons because it interferes with their website/app design, so they remove them in the CSS. If you want to build an inclusive product, you should not use &lt;code&gt;{ outline: none; }&lt;/code&gt; on focusable elements globally for the whole website or app. Instead of deleting the outline completely, you can show a focus indicator that originates from keyboard interaction but that is not present with pointer device interaction. Also, make sure that the color you use for the focus indicator properly contrasts with the backgrounds. It is also good to add a small gap between the focused element and the component using the &lt;code&gt;{ outline-offset }&lt;/code&gt; property for better visibility.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6ybaxksawk9c9pw3urir.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6ybaxksawk9c9pw3urir.png" alt="LiveChat accessibility buttons focus"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap-up
&lt;/h2&gt;

&lt;p&gt;You may be overwhelmed by the number of color issues the audit can reveal; but don’t worry, very often the same color relations are repeated across the app. Like in any other case, planning is very important. Break down all issues into groups and categorize them based on similarity and difficulty. Choose your tools when it comes to design, development, and testing. There are plenty of tools and libraries which can speed up the whole process.&lt;/p&gt;

&lt;p&gt;Key takeaways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Start with an audit&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Eliminate personal bias toward preferred colors&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Don’t rely solely on the WCAG math for contrast calculations. Test the combinations with real users&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Accessible color palettes can be appealing&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Working on accessible colors is an opportunity to tidy up your design system&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a proper focus indicator and show it when needed&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>a11y</category>
      <category>showdev</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Introducing and testing accessibility in the LiveChat Chat Widget</title>
      <dc:creator>Oliwia Połeć</dc:creator>
      <pubDate>Tue, 22 Jun 2021 12:51:14 +0000</pubDate>
      <link>https://dev.to/text/introducing-and-testing-accessibility-in-the-livechat-chat-widget-42p9</link>
      <guid>https://dev.to/text/introducing-and-testing-accessibility-in-the-livechat-chat-widget-42p9</guid>
      <description>&lt;p&gt;For the last few months, we’ve been working on making our LiveChat Chat Widget accessible and ensuring it meets &lt;a href="https://www.w3.org/TR/WCAG21/" rel="noopener noreferrer"&gt;the WCAG requirements&lt;/a&gt;. We had to get acquainted with success criteria, translate them into specific technical tasks, then validate our solutions and introduce corrections.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcri4no2qgug18ogupter.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcri4no2qgug18ogupter.png" alt="LiveChat accessibility intro image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The whole project was very challenging, especially choosing between conflicting interpretations of the requirements and match. We repeatedly had to clarify a specification to match specific parts of the application that did not match the available examples. We want to share the knowledge gained during the project and explore how we adapted the LiveChat Chat Widget application to WCAG 2.1 level AA requirements. We decided to create a series of posts about the most complex technical aspects of making web applications accessible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Web Content Accessibility Guidelines
&lt;/h2&gt;

&lt;p&gt;As mentioned before, the LiveChat Chat Widget meets WCAG 2.1 requirements. What does this mean exactly? Web Content Accessibility Guidelines (WCAG) is a standard for web content accessibility provided by the World Wide Web Consortium (W3C). WCAG defines testable success criteria grouped into three conformance levels: A, AA, and AAA (the best). However, level AAA is usually not required for the entire content of a webpage because it is impossible to meet its success criteria for some parts of the content.&lt;/p&gt;

&lt;p&gt;Sample success criterion: text contrast. Level AA requires that the text must have at least a 4.5:1 contrast ratio in most cases, but level AAA requires a 7:1 contrast ratio.&lt;/p&gt;

&lt;p&gt;WCAG comes with an easy-to-navigate, detailed reference guide, along with techniques documented with examples, code, and descriptions of test procedures.&lt;/p&gt;

&lt;p&gt;Another important document is &lt;a href="https://www.w3.org/TR/wai-aria-practices-1.1/" rel="noopener noreferrer"&gt;Aria Practices&lt;/a&gt;, which provides developers with practical examples of how to implement specific solutions so that they are accessible to people with limitations.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flonrgoddelg50tqhvszc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flonrgoddelg50tqhvszc.png" alt="LiveChat accessibility graph"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why we should care about accessibility
&lt;/h2&gt;

&lt;p&gt;We understand accessibility as enabling people with limited abilities to use a website or web application. Taking care of accessibility should be done from the very beginning of every project — there are several reasons for this.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;According to the WHO’s "&lt;a href="https://www.who.int/publications/i/item/9789241564182" rel="noopener noreferrer"&gt;World report on disability&lt;/a&gt;" from 2011, 15% of the global population live with some form of disability. That translates to a massive number of visitors that benefit from improvements in this area. 2.2 billion people have a near or distance vision impairment. The issue of accessibility is often seen as a problem that affects only a negligible minority. We pay very little attention to these problems, and actions to improve the situation have been disproportionate to the actual scale of the problem.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Taking care of website accessibility brings profit to every user. Meeting color requirements is essential for people with severe vision impairments, but it's also helpful for those with impairments classified as "moderate" or "mild." Valid document semantic structure is useful for every tool that needs to better understand the content of your website. It can improve multiple other aspects, like SEO. Alternative image descriptions can be applicable in the case of bad network conditions or failure.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Many countries require a particular category of institutions to ensure website accessibility. In the USA, such requirements for public institutions and those cooperating with them are imposed by the American Disability Act (ADA). In the case of the European Union, similar requirements are imposed by the Web Accessibility Directive. The requirements of these documents are often specified at the level of state law in the United States or the countries of the European Union.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Taking care of accessibility should be part of caring for a responsible brand image.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In the case of LiveChat, in the document &lt;a href="https://investor.livechatinc.com/uploads/the-livechat-software-living-consitution-v1.0.pdf" rel="noopener noreferrer"&gt;"The LiveChat Software Living Constitution"&lt;/a&gt; we have a clearly defined vision: "Customer communication without barriers." Such a vision means that we have to treat accessibility as the most important topic we should be dealing with.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faecauw7ya9621m1iqp26.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faecauw7ya9621m1iqp26.png" alt="LiveChat accessibility buttons image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Work areas
&lt;/h2&gt;

&lt;p&gt;When thinking about people with limitations, we should take into account the needs of people with visual, hearing, mobility, and cognitive impairments. In the case of our application, the most demanding tasks can be grouped into three areas:&lt;/p&gt;

&lt;h3&gt;
  
  
  Keyboard navigation
&lt;/h3&gt;

&lt;p&gt;Making sure that the app interface can be fully used without the need for additional input devices like a mouse or trackpad. The user should know which item is currently focused; keyboard navigation should be logical and comfortable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Screen readers
&lt;/h3&gt;

&lt;p&gt;Content should have correct semantic structure; interactive elements should have proper aria tags, and all state changes should be announced to the user. Meaningful non-text content should have an alternative text description. This enables screen readers to work correctly with your website, together with other accessibility tools, for example, Voice Control on devices with iOS systems.&lt;/p&gt;

&lt;h3&gt;
  
  
  Visuals
&lt;/h3&gt;

&lt;p&gt;Colors should meet minimum contrast requirements and shouldn't be used as the only way to indicate app status.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;We'll cover each of these areas in detail in the following posts. Behind each of these points, there are many additional needs. In our posts, we will focus on the problems and requirements of the Chat Widget application; it is not a complete guide for any type of application.&lt;/p&gt;

&lt;p&gt;Besides this, we will describe how to start the process of customizing already running projects: how to test the compliance level of an application and how to use test automation to avoid regression in this area.&lt;/p&gt;

&lt;p&gt;We hope these articles will help developers and designers look closely at the topic of accessible web applications and provide practical tips. Unfortunately, despite the dynamic development of browsers, standards, and technologies, a lot of work in the area of accessibility still requires manual implementation. Commonly used interface elements, such as modal pop-ups, have well-defined requirements for keyboard navigation. Unfortunately, browsers do not provide built-in mechanisms for them. Had the native &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible" rel="noopener noreferrer"&gt;focus-visible pseudo-selector support&lt;/a&gt; been released earlier, we might have prevented the practice of disabling outline from being popularized for active elements. On the other hand, developers have more and more tools to test the accessibility of their websites, like the &lt;a href="https://developer.chrome.com/blog/new-in-devtools-83/#vision-deficiencies" rel="noopener noreferrer"&gt;Emulate vision deficiencies in Chrome DevTools&lt;/a&gt;, the &lt;a href="https://developer.mozilla.org/en-US/docs/Tools/Accessibility_inspector" rel="noopener noreferrer"&gt;Accessibility tab in the Firefox devtools&lt;/a&gt; and the &lt;a href="https://www.deque.com/axe/browser-extensions/" rel="noopener noreferrer"&gt;Axe browser extension&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Our journey with accessibility testing
&lt;/h1&gt;

&lt;p&gt;The past few months have been quite busy for our team. In LiveChat, we’re responsible for building the Chat Widget, one of the core components of our system that is used by end-users to communicate with support agents. As described &lt;a href="https://developers.livechat.com/updates/livechat-chat-widget-accessibility-introduction/" rel="noopener noreferrer"&gt;here&lt;/a&gt; and &lt;a href="https://investor.livechatinc.com/uploads/the-livechat-software-living-consitution-v1.0.pdf" rel="noopener noreferrer"&gt;in our constitution&lt;/a&gt;, one of our core values is to make "customer communication without barriers." For us, communication without barriers meant that we needed to put more focus on accessibility, so we made adjustments to the Chat Widget in order to meet WCAG requirements.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fev8rdmv9d0yug1qoi72k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fev8rdmv9d0yug1qoi72k.png" alt="LiveChat testing accessibility"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What does that even mean?
&lt;/h2&gt;

&lt;p&gt;“Being accessible” means providing a person with disabilities a way to use a product. It applies to different areas of everyday life. For example, consider stairs People using wheelchairs cannot use stairs, so an owner of the building has to provide an elevator. The same is for the web - different people use our Chat Widget, some of whom might be blind, deaf, or have different kinds of vision impairments. Just as the owner of the aforementioned building had to make accommodations, we should provide our customers with alternative ways of using our product. If that’s not convincing enough, maybe you should keep in mind that building an inaccessible website might even end with a lawsuit!&lt;/p&gt;

&lt;p&gt;So, what are those alternatives? Well, it depends on the disability being accommodated. Sometimes we need to avoid some patterns. For example, we shouldn’t make elements of our UI reachable only with a mouse, as some users might explicitly depend on keyboard navigation. On some occasions, it is about not using colors that might be indistinguishable for people with color blindness. Fortunately, we don’t have to spend a lifetime researching the topic before jumping into action. Web Content Accessibility Guidelines (WCAG) is the saviour here. It is a document published by the Web Accessibility Initiative that establishes a set of recommendations to follow to make websites more accessible.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffdvnz71eodwxkemnrws7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffdvnz71eodwxkemnrws7.png" alt="LiveChat accessibility axe DevTools"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Low-hanging fruit
&lt;/h2&gt;

&lt;p&gt;When we first started working on accessibility, it was a bit overwhelming. We had an already working application with thousands of customers, and accessibility was a completely new thing for us. Our initial question was not “how,” but actually “what” to start with? Before making any plans, our first task was to research how to test the web applications with accessibility in mind, and then to fix any flaws in our Chat Widget.&lt;/p&gt;

&lt;p&gt;We began with static analysis tools. These tools analyze the semantic structure of the HTML DOM tree in order to be able to find some downsides. A great example of such a tool is &lt;a href="https://chrome.google.com/webstore/detail/axe-devtools-web-accessib/lhdoppojpmngadmnindnejefpokejbdd" rel="noopener noreferrer"&gt;“axe DevTools”&lt;/a&gt; browser extension or a similar &lt;a href="https://wave.webaim.org/extension/" rel="noopener noreferrer"&gt;WAVE&lt;/a&gt; one. You use it to scan either all of your webpage, or it’s particular elements, after which  you will get the report listing all found issues.&lt;/p&gt;

&lt;p&gt;These checks are based on the WCAG requirements mentioned above, and include the severity of each issue.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1q42sjm9zn0kwn3e5dtf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1q42sjm9zn0kwn3e5dtf.png" alt="LiveChat accessibility inspect tools"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Other tools which you can use for such an analysis, if you are using Chrome or Firefox, are built in your browsers. In Chrome, you are able to run a similar automatic report using Lighthouse. Although it is certainly less specific,  it is a good start.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy5bx5j1yn0cl7wrgwni0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy5bx5j1yn0cl7wrgwni0.png" alt="LiveChat accessibility testing result"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The same is true for Firefox - when you open the developer tools, all you need to do is go to the “Accessibility” tab and select “Check for issues" with the option you favor. This will provide yet another report with all the information you need in order to start making the world a better place.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkhuy4vknrcbs7ee4ylod.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkhuy4vknrcbs7ee4ylod.png" alt="LiveChat accessibility check for issues"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Both of these browsers also provide additional information about the color contrasts, missing attributes, element semantics, and other important things.&lt;/p&gt;

&lt;h2&gt;
  
  
  With all that sorted, use your imagination!
&lt;/h2&gt;

&lt;p&gt;From the reported issues we created tasks to improve particular components, and we have gained a lot of insight into what to look for. Though it was a quick round of running the audits around different application states, we knew it was just the beginning. We have found that we can keep track of issues using different automated solutions during early phases, such as eslint rules (e.g. “eslint-plugin-jsx-a11y”) or cypress plugin (“cypress-axe”). That is a topic for another blogpost, though!&lt;/p&gt;

&lt;p&gt;The second, much more important thing we knew we had to do was to make use of our empathy. We already learned which things we should pay attention to, soit was now time to check the user experience. When manually testing user experience of the accommodations, it’s probably preferable to categorize and test different disabilities independently instead of trying to test everything at once.&lt;/p&gt;

&lt;p&gt;For example, we had to learn how the blind use the web. The answer is pretty simple - they use screen-readers and navigate around using just the keyboard. There are a variety of screen readers to use, some of which might be already in your system, such as VoiceOver, which is on MacOS. If that’s not the case, you can consider free browser extensions like &lt;a href="https://chrome.google.com/webstore/detail/screen-reader/kgejglhpjiefppelpmljglcjbhoiplfn?hl=en" rel="noopener noreferrer"&gt;ChromeVox&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In Warsaw, there is an exhibition called “Invisible Exhibition.” It’s an interactive tour “into the world of darkness,” and is meant to show visitors how the blind or visually impaired navigate around the world. For web browsing we basically did the same, and we were able to recreate the experience of using our widget as a blind or visually impaired person would in order to check it.&lt;/p&gt;

&lt;p&gt;Imagine you are using the web without being able to “see;” you can only  “hear.” Imagination can be tricky here, so you can try it blindfolded or with your eyes closed. We are used to certain patterns which are not at all accessible, and blindfolding yourself helps you to understand how wed we are to those patterns. For us, it was a game-changer. For starters, we made a run for critical and basic paths of our application, like:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Find the Chat Widget on the page.&lt;/li&gt;
&lt;li&gt;Open it, fill in the pre-chat, and start a chat.&lt;/li&gt;
&lt;li&gt;Chat with the Agent - are you able to “read” (hear?) their message? Are you able to answer or ask any questions?&lt;/li&gt;
&lt;li&gt;Close the chat.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It seems pretty easy now, but it turned out that it was almost impossible at the very beginning of our journey with accessibility. We weren’t even able to find our widget on the page, so new messages from the Agent were not being read, and the user was unable to navigate through them. We had to learn how to use the keyboard, how content is being read, and which bits and pieces are viable.&lt;/p&gt;

&lt;p&gt;This gave us more insights than any static analysis would to and made us actually realize how important it is to improve that situation. The same is for other disabilities, like color blindness. You can use various tools to simulate such a condition, learn, and then make your app better with all that knowledge.&lt;/p&gt;

&lt;h2&gt;
  
  
  Design with a11y in mind
&lt;/h2&gt;

&lt;p&gt;The experience of using our Chat Widget in the way a disabled person might made us realize how important it is to consider accessibility at a very early stage. We believe in the “test early, test often” approach, and as mentioned earlier, we have included automatic tools in our pipeline to ensure there is no regression around particular areas. But, before development, there is a design.&lt;/p&gt;

&lt;p&gt;As part of the changes we adopted, we had to completely rebuild some of our components, such as the file upload. Now it provides a way to add an “aria-label” to the uploaded images, explicitly informs users about the status of the upload, and makes all content easily reachable with the keyboard. The earlier version was not accessible at all with a keyboard, not to mention that it gave only the visual representation of upload status.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuxwvsd07v3l8vwyde5mc.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuxwvsd07v3l8vwyde5mc.gif" alt="LiveChat accessibility file upload"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We have read a lot of blogs and specifications, learnt from our experiences, as well as from books like “&lt;a href="https://inclusive-components.design/" rel="noopener noreferrer"&gt;Inclusive Components&lt;/a&gt;.” All of these made us realize what we needed, and now every new feature we design and plan to implement is done with accessibility in mind.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learn from the professionals
&lt;/h2&gt;

&lt;p&gt;Last but not least, there are companies like &lt;a href="http://deque.com" rel="noopener noreferrer"&gt;Deque&lt;/a&gt; which can help you with assessment and testing. They built the “axe DevTools”! They run training sessions, provide access to different testing tools, and perform audits and accessibility assessments. Their audits are based on their extensive knowledge in the area and will help you to determine which issues to address. The specifications and requirements can sometimes be confusing, and it might be quite hard to apply them or test them with your application. This is the part when even a simple chat with a professional in that area might be helpful.&lt;/p&gt;

&lt;p&gt;You can also use the solutions already made by professionals, such as &lt;a href="https://github.com/adobe/react-spectrum/" rel="noopener noreferrer"&gt;adobe/react-spectrum&lt;/a&gt;. There is a lot of useful knowledge there, as well as tips on what to look for while testing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Remember accessibility!
&lt;/h2&gt;

&lt;p&gt;Although often overlooked, the accessibility of your product is of the highest importance. There are a variety of tools to help you determine where you can improve, and it’s impossible to find an excuse why you shouldn’t. I hope that our journey will encourage you to care about all of your visitors and unleash the full potential of your product.&lt;/p&gt;

</description>
      <category>a11y</category>
      <category>showdev</category>
      <category>webdev</category>
    </item>
    <item>
      <title>After the live coding about web app authorization</title>
      <dc:creator>Oliwia Połeć</dc:creator>
      <pubDate>Thu, 01 Apr 2021 06:30:14 +0000</pubDate>
      <link>https://dev.to/text/after-the-live-coding-about-web-app-authorization-502o</link>
      <guid>https://dev.to/text/after-the-live-coding-about-web-app-authorization-502o</guid>
      <description>&lt;p&gt;As you may know, we recently organized a live coding event together with the LiveChat Developer Program team, where we taught web app authorization with our API. During the session, we also covered sending rich messages in the chat, as well as Accounts SDK. To get more details, &lt;a href="https://dev.to/livechat/announcing-a-live-coding-session-livechat-web-app-authorization-31gf"&gt;here's a link&lt;/a&gt; where you can find the event announcement.&lt;/p&gt;

&lt;p&gt;If you missed the live coding by any chance, we got you covered. Maybe you even enjoyed the session so much you wish to rewatch it? You can find a video recording of the whole event right below 👇&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/FDmLqEiCH60"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;If you like this video and want to participate in the future sessions we organize, join our &lt;a href="https://discord.com/invite/rFbJkYQFwp"&gt;Discord server&lt;/a&gt; and be up to date with LiveChat Platform news. You can also let us know if there are any LiveChat API topics you’d want us to cover in the future! We are reachable via email at &lt;a href="mailto:developers@livechat.com"&gt;developers@livechat.com&lt;/a&gt; or on the Discord server.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>sideprojects</category>
    </item>
  </channel>
</rss>
