CINXE.COM
Accessibility in React - Learn web development | MDN
<!doctype html><html lang="en-US" prefix="og: https://ogp.me/ns#"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><link rel="icon" href="https://developer.mozilla.org/favicon-48x48.bc390275e955dacb2e65.png"/><link rel="apple-touch-icon" href="https://developer.mozilla.org/apple-touch-icon.528534bba673c38049c2.png"/><meta name="theme-color" content="#ffffff"/><link rel="manifest" href="https://developer.mozilla.org/manifest.f42880861b394dd4dc9b.json"/><link rel="search" type="application/opensearchdescription+xml" href="/opensearch.xml" title="MDN Web Docs"/><title>Accessibility in React - Learn web development | MDN</title><link rel="alternate" title="Barrierefreiheit in React" href="https://developer.mozilla.org/de/docs/Learn_web_development/Core/Frameworks_libraries/React_accessibility" hrefLang="de"/><link rel="alternate" title="React でのアクセシビリティ" href="https://developer.mozilla.org/ja/docs/Learn_web_development/Core/Frameworks_libraries/React_accessibility" hrefLang="ja"/><link rel="alternate" title="Accessibility in React" href="https://developer.mozilla.org/ko/docs/Learn_web_development/Core/Frameworks_libraries/React_accessibility" hrefLang="ko"/><link rel="alternate" title="Accessibility in React" href="https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Frameworks_libraries/React_accessibility" hrefLang="en"/><link rel="preload" as="font" type="font/woff2" href="/static/media/Inter.var.c2fe3cb2b7c746f7966a.woff2" crossorigin=""/><link rel="alternate" type="application/rss+xml" title="MDN Blog RSS Feed" href="https://developer.mozilla.org/en-US/blog/rss.xml" hrefLang="en"/><meta name="description" content="In our final tutorial article, we'll focus on (pun intended) accessibility, including focus management in React, which can improve usability and reduce confusion for both keyboard-only and screen reader users."/><meta property="og:url" content="https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Frameworks_libraries/React_accessibility"/><meta property="og:title" content="Accessibility in React - Learn web development | MDN"/><meta property="og:type" content="website"/><meta property="og:locale" content="en_US"/><meta property="og:description" content="In our final tutorial article, we'll focus on (pun intended) accessibility, including focus management in React, which can improve usability and reduce confusion for both keyboard-only and screen reader users."/><meta property="og:image" content="https://developer.mozilla.org/mdn-social-share.d893525a4fb5fb1f67a2.png"/><meta property="og:image:type" content="image/png"/><meta property="og:image:height" content="1080"/><meta property="og:image:width" content="1920"/><meta property="og:image:alt" content="The MDN Web Docs logo, featuring a blue accent color, displayed on a solid black background."/><meta property="og:site_name" content="MDN Web Docs"/><meta name="twitter:card" content="summary_large_image"/><meta name="twitter:creator" content="MozDevNet"/><link rel="canonical" href="https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Frameworks_libraries/React_accessibility"/><style media="print">.article-actions-container,.document-toc-container,.language-menu,.main-menu-toggle,.on-github,.page-footer,.place,.sidebar,.top-banner,.top-navigation-main,ul.prev-next{display:none!important}.main-page-content,.main-page-content pre{padding:2px}.main-page-content pre{border-left-width:2px}</style><script src="/static/js/gtag.js" defer=""></script><script defer="" src="/static/js/main.f565372a.js"></script><link href="/static/css/main.3d9e7a02.css" rel="stylesheet"/></head><body><script>if(document.body.addEventListener("load",(t=>{t.target.classList.contains("interactive")&&t.target.setAttribute("data-readystate","complete")}),{capture:!0}),window&&document.documentElement){const t={light:"#ffffff",dark:"#1b1b1b"};try{const e=window.localStorage.getItem("theme");e&&(document.documentElement.className=e,document.documentElement.style.backgroundColor=t[e]);const o=window.localStorage.getItem("nop");o&&(document.documentElement.dataset.nop=o)}catch(t){console.warn("Unable to read theme from localStorage",t)}}</script><div id="root"><ul id="nav-access" class="a11y-nav"><li><a id="skip-main" href="#content">Skip to main content</a></li><li><a id="skip-search" href="#top-nav-search-input">Skip to search</a></li><li><a id="skip-select-language" href="#languages-switcher-button">Skip to select language</a></li></ul><div class="page-wrapper category-javascript document-page"><div class="top-banner loading"><section class="place top container"></section></div><div class="sticky-header-container"><header class="top-navigation "><div class="container "><div class="top-navigation-wrap"><a href="/en-US/" class="logo" aria-label="MDN homepage"><svg id="mdn-docs-logo" xmlns="http://www.w3.org/2000/svg" x="0" y="0" viewBox="0 0 694.9 104.4" style="enable-background:new 0 0 694.9 104.4" xml:space="preserve" role="img"><title>MDN Web Docs</title><path d="M40.3 0 11.7 92.1H0L28.5 0h11.8zm10.4 0v92.1H40.3V0h10.4zM91 0 62.5 92.1H50.8L79.3 0H91zm10.4 0v92.1H91V0h10.4z" class="logo-m"></path><path d="M627.9 95.6h67v8.8h-67v-8.8z" class="logo-_"></path><path d="M367 42h-4l-10.7 30.8h-5.5l-10.8-26h-.4l-10.5 26h-5.2L308.7 42h-3.8v-5.6H323V42h-6.5l6.8 20.4h.4l10.3-26h4.7l11.2 26h.5l5.7-20.3h-6.2v-5.6H367V42zm34.9 20c-.4 3.2-2 5.9-4.7 8.2-2.8 2.3-6.5 3.4-11.3 3.4-5.4 0-9.7-1.6-13.1-4.7-3.3-3.2-5-7.7-5-13.7 0-5.7 1.6-10.3 4.7-14s7.4-5.5 12.9-5.5c5.1 0 9.1 1.6 11.9 4.7s4.3 6.9 4.3 11.3c0 1.5-.2 3-.5 4.7h-25.6c.3 7.7 4 11.6 10.9 11.6 2.9 0 5.1-.7 6.5-2 1.5-1.4 2.5-3 3-4.9l6 .9zM394 51.3c.2-2.4-.4-4.7-1.8-6.9s-3.8-3.3-7-3.3c-3.1 0-5.3 1-6.9 3-1.5 2-2.5 4.4-2.8 7.2H394zm51 2.4c0 5-1.3 9.5-4 13.7s-6.9 6.2-12.7 6.2c-6 0-10.3-2.2-12.7-6.7-.1.4-.2 1.4-.4 2.9s-.3 2.5-.4 2.9h-7.3c.3-1.7.6-3.5.8-5.3.3-1.8.4-3.7.4-5.5V22.3h-6v-5.6H416v27c1.1-2.2 2.7-4.1 4.7-5.7 2-1.6 4.8-2.4 8.4-2.4 4.6 0 8.4 1.6 11.4 4.7 3 3.2 4.5 7.6 4.5 13.4zm-7.7.6c0-4.2-1-7.4-3-9.5-2-2.2-4.4-3.3-7.4-3.3-3.4 0-6 1.2-8 3.7-1.9 2.4-2.9 5-3 7.7V57c0 3 1 5.6 3 7.7s4.5 3.1 7.6 3.1c3.6 0 6.3-1.3 8.1-3.9 1.8-2.7 2.7-5.9 2.7-9.6zm69.2 18.5h-13.2v-7.2c-1.2 2.2-2.8 4.1-4.9 5.6-2.1 1.6-4.8 2.4-8.3 2.4-4.8 0-8.7-1.6-11.6-4.9-2.9-3.2-4.3-7.7-4.3-13.3 0-5 1.3-9.6 4-13.7 2.6-4.1 6.9-6.2 12.8-6.2 5.7 0 9.8 2.2 12.3 6.5V22.3h-8.6v-5.6h15.8v50.6h6v5.5zM493.2 56v-4.4c-.1-3-1.2-5.5-3.2-7.3s-4.4-2.8-7.2-2.8c-3.6 0-6.3 1.3-8.2 3.9-1.9 2.6-2.8 5.8-2.8 9.6 0 4.1 1 7.3 3 9.5s4.5 3.3 7.4 3.3c3.2 0 5.8-1.3 7.8-3.8 2.1-2.6 3.1-5.3 3.2-8zm53.1-1.4c0 5.6-1.8 10.2-5.3 13.7s-8.2 5.3-13.9 5.3-10.1-1.7-13.4-5.1c-3.3-3.4-5-7.9-5-13.5 0-5.3 1.6-9.9 4.7-13.7 3.2-3.8 7.9-5.7 14.2-5.7s11 1.9 14.1 5.7c3 3.7 4.6 8.1 4.6 13.3zm-7.7-.2c0-4-1-7.2-3-9.5s-4.8-3.5-8.2-3.5c-3.6 0-6.4 1.2-8.3 3.7s-2.9 5.6-2.9 9.5c0 3.7.9 6.8 2.8 9.4 1.9 2.6 4.6 3.9 8.3 3.9 3.6 0 6.4-1.3 8.4-3.8 1.9-2.6 2.9-5.8 2.9-9.7zm45 5.8c-.4 3.2-1.9 6.3-4.4 9.1-2.5 2.9-6.4 4.3-11.8 4.3-5.2 0-9.4-1.6-12.6-4.8-3.2-3.2-4.8-7.7-4.8-13.7 0-5.5 1.6-10.1 4.7-13.9 3.2-3.8 7.6-5.7 13.2-5.7 2.3 0 4.6.3 6.7.8 2.2.5 4.2 1.5 6.2 2.9l1.5 9.5-5.9.7-1.3-6.1c-2.1-1.2-4.5-1.8-7.2-1.8-3.5 0-6.1 1.2-7.7 3.7-1.7 2.5-2.5 5.7-2.5 9.6 0 4.1.9 7.3 2.7 9.5 1.8 2.3 4.4 3.4 7.8 3.4 5.2 0 8.2-2.9 9.2-8.8l6.2 1.3zm34.7 1.9c0 3.6-1.5 6.5-4.6 8.5s-7 3-11.7 3c-5.7 0-10.6-1.2-14.6-3.6l1.2-8.8 5.7.6-.2 4.7c1.1.5 2.3.9 3.6 1.1s2.6.3 3.9.3c2.4 0 4.5-.4 6.5-1.3 1.9-.9 2.9-2.2 2.9-4.1 0-1.8-.8-3.1-2.3-3.8s-3.5-1.3-5.8-1.7-4.6-.9-6.9-1.4c-2.3-.6-4.2-1.6-5.7-2.9-1.6-1.4-2.3-3.5-2.3-6.3 0-4.1 1.5-6.9 4.6-8.5s6.4-2.4 9.9-2.4c2.6 0 5 .3 7.2.9 2.2.6 4.3 1.4 6.1 2.4l.8 8.8-5.8.7-.8-5.7c-2.3-1-4.7-1.6-7.2-1.6-2.1 0-3.7.4-5.1 1.1-1.3.8-2 2-2 3.8 0 1.7.8 2.9 2.3 3.6 1.5.7 3.4 1.2 5.7 1.6 2.2.4 4.5.8 6.7 1.4 2.2.6 4.1 1.6 5.7 3 1.4 1.6 2.2 3.7 2.2 6.6zM197.6 73.2h-17.1v-5.5h3.8V51.9c0-3.7-.7-6.3-2.1-7.9-1.4-1.6-3.3-2.3-5.7-2.3-3.2 0-5.6 1.1-7.2 3.4s-2.4 4.6-2.5 6.9v15.6h6v5.5h-17.1v-5.5h3.8V51.9c0-3.8-.7-6.4-2.1-7.9-1.4-1.5-3.3-2.3-5.6-2.3-3.2 0-5.5 1.1-7.2 3.3-1.6 2.2-2.4 4.5-2.5 6.9v15.8h6.9v5.5h-20.2v-5.5h6V42.4h-6.1v-5.6h13.4v6.4c1.2-2.1 2.7-3.8 4.7-5.2 2-1.3 4.4-2 7.3-2s5.3.7 7.5 2.1c2.2 1.4 3.7 3.5 4.5 6.4 1.1-2.5 2.7-4.5 4.9-6.1s4.8-2.4 7.9-2.4c3.5 0 6.5 1.1 8.9 3.3s3.7 5.6 3.7 10.2v18.2h6.1v5.5zm42.5 0h-13.2V66c-1.2 2.2-2.8 4.1-4.9 5.6-2.1 1.6-4.8 2.4-8.3 2.4-4.8 0-8.7-1.6-11.6-4.9-2.9-3.2-4.3-7.7-4.3-13.3 0-5 1.3-9.6 4-13.7 2.6-4.1 6.9-6.2 12.8-6.2s9.8 2.2 12.3 6.5V22.7h-8.6v-5.6h15.8v50.6h6v5.5zm-13.3-16.8V52c-.1-3-1.2-5.5-3.2-7.3s-4.4-2.8-7.2-2.8c-3.6 0-6.3 1.3-8.2 3.9-1.9 2.6-2.8 5.8-2.8 9.6 0 4.1 1 7.3 3 9.5s4.5 3.3 7.4 3.3c3.2 0 5.8-1.3 7.8-3.8 2.1-2.6 3.1-5.3 3.2-8zm61.5 16.8H269v-5.5h6V51.9c0-3.7-.7-6.3-2.2-7.9-1.4-1.6-3.4-2.3-5.7-2.3-3.1 0-5.6 1-7.4 3s-2.8 4.4-2.9 7v15.9h6v5.5h-19.3v-5.5h6V42.4h-6.2v-5.6h13.6V43c2.6-4.6 6.8-6.9 12.7-6.9 3.6 0 6.7 1.1 9.2 3.3s3.7 5.6 3.7 10.2v18.2h6v5.4h-.2z" class="logo-text"></path></svg></a><button title="Open main menu" type="button" class="button action has-icon main-menu-toggle" aria-haspopup="menu" aria-label="Open main menu" aria-expanded="false"><span class="button-wrap"><span class="icon icon-menu "></span><span class="visually-hidden">Open main menu</span></span></button></div><div class="top-navigation-main"><nav class="main-nav" aria-label="Main menu"><ul class="main-menu nojs"><li class="top-level-entry-container "><button type="button" id="references-button" class="top-level-entry menu-toggle" aria-controls="references-menu" aria-expanded="false">References</button><a href="/en-US/docs/Web" class="top-level-entry">References</a><ul id="references-menu" class="submenu references hidden inline-submenu-lg" aria-labelledby="references-button"><li class="apis-link-container mobile-only "><a href="/en-US/docs/Web" class="submenu-item "><div class="submenu-icon"></div><div class="submenu-content-container"><div class="submenu-item-heading">Overview / Web Technology</div><p class="submenu-item-description">Web technology reference for developers</p></div></a></li><li class="html-link-container "><a href="/en-US/docs/Web/HTML" class="submenu-item "><div class="submenu-icon html"></div><div class="submenu-content-container"><div class="submenu-item-heading">HTML</div><p class="submenu-item-description">Structure of content on the web</p></div></a></li><li class="css-link-container "><a href="/en-US/docs/Web/CSS" class="submenu-item "><div class="submenu-icon css"></div><div class="submenu-content-container"><div class="submenu-item-heading">CSS</div><p class="submenu-item-description">Code used to describe document style</p></div></a></li><li class="javascript-link-container "><a href="/en-US/docs/Web/JavaScript" class="submenu-item "><div class="submenu-icon javascript"></div><div class="submenu-content-container"><div class="submenu-item-heading">JavaScript</div><p class="submenu-item-description">General-purpose scripting language</p></div></a></li><li class="http-link-container "><a href="/en-US/docs/Web/HTTP" class="submenu-item "><div class="submenu-icon http"></div><div class="submenu-content-container"><div class="submenu-item-heading">HTTP</div><p class="submenu-item-description">Protocol for transmitting web resources</p></div></a></li><li class="apis-link-container "><a href="/en-US/docs/Web/API" class="submenu-item "><div class="submenu-icon apis"></div><div class="submenu-content-container"><div class="submenu-item-heading">Web APIs</div><p class="submenu-item-description">Interfaces for building web applications</p></div></a></li><li class="apis-link-container "><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions" class="submenu-item "><div class="submenu-icon"></div><div class="submenu-content-container"><div class="submenu-item-heading">Web Extensions</div><p class="submenu-item-description">Developing extensions for web browsers</p></div></a></li><li class=" "><a href="/en-US/docs/Web/Accessibility" class="submenu-item "><div class="submenu-icon"></div><div class="submenu-content-container"><div class="submenu-item-heading">Accessibility</div><p class="submenu-item-description">Build web projects usable for all</p></div></a></li><li class="apis-link-container desktop-only "><a href="/en-US/docs/Web" class="submenu-item "><div class="submenu-icon"></div><div class="submenu-content-container"><div class="submenu-item-heading">Web Technology</div><p class="submenu-item-description">Web technology reference for developers</p></div></a></li></ul></li><li class="top-level-entry-container active"><button type="button" id="learn-button" class="top-level-entry menu-toggle" aria-controls="learn-menu" aria-expanded="false">Learn</button><a href="/en-US/docs/Learn_web_development" class="top-level-entry">Learn</a><ul id="learn-menu" class="submenu learn hidden inline-submenu-lg" aria-labelledby="learn-button"><li class="apis-link-container mobile-only "><a href="/en-US/docs/Learn_web_development" class="submenu-item "><div class="submenu-icon learn"></div><div class="submenu-content-container"><div class="submenu-item-heading">Overview / MDN Learning Area</div><p class="submenu-item-description">Learn web development</p></div></a></li><li class="apis-link-container desktop-only "><a href="/en-US/docs/Learn_web_development" class="submenu-item "><div class="submenu-icon learn"></div><div class="submenu-content-container"><div class="submenu-item-heading">MDN Learning Area</div><p class="submenu-item-description">Learn web development</p></div></a></li><li class="html-link-container "><a href="/en-US/docs/Learn_web_development/Core/Structuring_content" class="submenu-item "><div class="submenu-icon html"></div><div class="submenu-content-container"><div class="submenu-item-heading">HTML</div><p class="submenu-item-description">Learn to structure web content with HTML</p></div></a></li><li class="css-link-container "><a href="/en-US/docs/Learn_web_development/Core/Styling_basics" class="submenu-item "><div class="submenu-icon css"></div><div class="submenu-content-container"><div class="submenu-item-heading">CSS</div><p class="submenu-item-description">Learn to style content using CSS</p></div></a></li><li class="javascript-link-container "><a href="/en-US/docs/Learn_web_development/Core/Scripting" class="submenu-item "><div class="submenu-icon javascript"></div><div class="submenu-content-container"><div class="submenu-item-heading">JavaScript</div><p class="submenu-item-description">Learn to run scripts in the browser</p></div></a></li><li class=" "><a href="/en-US/docs/Learn_web_development/Core/Accessibility" class="submenu-item "><div class="submenu-icon"></div><div class="submenu-content-container"><div class="submenu-item-heading">Accessibility</div><p class="submenu-item-description">Learn to make the web accessible to all</p></div></a></li></ul></li><li class="top-level-entry-container "><button type="button" id="mdn-plus-button" class="top-level-entry menu-toggle" aria-controls="mdn-plus-menu" aria-expanded="false">Plus</button><a href="/en-US/plus" class="top-level-entry">Plus</a><ul id="mdn-plus-menu" class="submenu mdn-plus hidden inline-submenu-lg" aria-labelledby="mdn-plus-button"><li class=" "><a href="/en-US/plus" class="submenu-item "><div class="submenu-icon"></div><div class="submenu-content-container"><div class="submenu-item-heading">Overview</div><p class="submenu-item-description">A customized MDN experience</p></div></a></li><li class=" "><a href="/en-US/plus/ai-help" class="submenu-item "><div class="submenu-icon"></div><div class="submenu-content-container"><div class="submenu-item-heading">AI Help</div><p class="submenu-item-description">Get real-time assistance and support</p></div></a></li><li class=" "><a href="/en-US/plus/updates" class="submenu-item "><div class="submenu-icon"></div><div class="submenu-content-container"><div class="submenu-item-heading">Updates</div><p class="submenu-item-description">All browser compatibility updates at a glance</p></div></a></li><li class=" "><a href="/en-US/plus/docs/features/overview" class="submenu-item "><div class="submenu-icon"></div><div class="submenu-content-container"><div class="submenu-item-heading">Documentation</div><p class="submenu-item-description">Learn how to use MDN Plus</p></div></a></li><li class=" "><a href="/en-US/plus/docs/faq" class="submenu-item "><div class="submenu-icon"></div><div class="submenu-content-container"><div class="submenu-item-heading">FAQ</div><p class="submenu-item-description">Frequently asked questions about MDN Plus</p></div></a></li></ul></li><li class="top-level-entry-container "><a class="top-level-entry menu-link" href="/en-US/curriculum/">Curriculum <sup class="new">New</sup></a></li><li class="top-level-entry-container "><a class="top-level-entry menu-link" href="/en-US/blog/">Blog</a></li><li class="top-level-entry-container "><button type="button" id="tools-button" class="top-level-entry menu-toggle" aria-controls="tools-menu" aria-expanded="false">Tools</button><ul id="tools-menu" class="submenu tools hidden inline-submenu-lg" aria-labelledby="tools-button"><li class=" "><a href="/en-US/play" class="submenu-item "><div class="submenu-icon"></div><div class="submenu-content-container"><div class="submenu-item-heading">Playground</div><p class="submenu-item-description">Write, test and share your code</p></div></a></li><li class=" "><a href="/en-US/observatory" class="submenu-item "><div class="submenu-icon"></div><div class="submenu-content-container"><div class="submenu-item-heading">HTTP Observatory</div><p class="submenu-item-description">Scan a website for free</p></div></a></li><li class=" "><a href="/en-US/plus/ai-help" class="submenu-item "><div class="submenu-icon"></div><div class="submenu-content-container"><div class="submenu-item-heading">AI Help</div><p class="submenu-item-description">Get real-time assistance and support</p></div></a></li></ul></li></ul></nav><div class="header-search"><form action="/en-US/search" class="search-form search-widget" id="top-nav-search-form" role="search"><label id="top-nav-search-label" for="top-nav-search-input" class="visually-hidden">Search MDN</label><input aria-activedescendant="" aria-autocomplete="list" aria-controls="top-nav-search-menu" aria-expanded="false" aria-labelledby="top-nav-search-label" autoComplete="off" id="top-nav-search-input" role="combobox" type="search" class="search-input-field" name="q" placeholder=" " required="" value=""/><button type="button" class="button action has-icon clear-search-button"><span class="button-wrap"><span class="icon icon-cancel "></span><span class="visually-hidden">Clear search input</span></span></button><button type="submit" class="button action has-icon search-button"><span class="button-wrap"><span class="icon icon-search "></span><span class="visually-hidden">Search</span></span></button><div id="top-nav-search-menu" role="listbox" aria-labelledby="top-nav-search-label"></div></form></div><div class="theme-switcher-menu"><button type="button" class="button action has-icon theme-switcher-menu small" aria-haspopup="menu"><span class="button-wrap"><span class="icon icon-theme-os-default "></span>Theme</span></button></div><ul class="auth-container"><li><a href="/users/fxa/login/authenticate/?next=%2Fen-US%2Fdocs%2FLearn_web_development%2FCore%2FFrameworks_libraries%2FReact_accessibility" class="login-link" rel="nofollow">Log in</a></li><li><a href="/users/fxa/login/authenticate/?next=%2Fen-US%2Fdocs%2FLearn_web_development%2FCore%2FFrameworks_libraries%2FReact_accessibility" target="_self" rel="nofollow" class="button primary mdn-plus-subscribe-link"><span class="button-wrap">Sign up for free</span></a></li></ul></div></div></header><div class="article-actions-container"><div class="container"><button type="button" class="button action has-icon sidebar-button" aria-label="Expand sidebar" aria-expanded="false" aria-controls="sidebar-quicklinks"><span class="button-wrap"><span class="icon icon-sidebar "></span></span></button><nav class="breadcrumbs-container" aria-label="Breadcrumb"><ol typeof="BreadcrumbList" vocab="https://schema.org/" aria-label="breadcrumbs"><li property="itemListElement" typeof="ListItem"><a href="/en-US/docs/Learn_web_development" class="breadcrumb" property="item" typeof="WebPage"><span property="name">Learn</span></a><meta property="position" content="1"/></li><li property="itemListElement" typeof="ListItem"><a href="/en-US/docs/Learn_web_development/Core" class="breadcrumb" property="item" typeof="WebPage"><span property="name">Core learning modules</span></a><meta property="position" content="2"/></li><li property="itemListElement" typeof="ListItem"><a href="/en-US/docs/Learn_web_development/Core/Frameworks_libraries" class="breadcrumb" property="item" typeof="WebPage"><span property="name">JavaScript frameworks and libraries</span></a><meta property="position" content="3"/></li><li property="itemListElement" typeof="ListItem"><a href="/en-US/docs/Learn_web_development/Core/Frameworks_libraries/React_accessibility" class="breadcrumb-current-page" property="item" typeof="WebPage"><span property="name">Accessibility in React</span></a><meta property="position" content="4"/></li></ol></nav><div class="article-actions"><button type="button" class="button action has-icon article-actions-toggle" aria-label="Article actions"><span class="button-wrap"><span class="icon icon-ellipses "></span><span class="article-actions-dialog-heading">Article Actions</span></span></button><ul class="article-actions-entries"><li class="article-actions-entry"><div class="languages-switcher-menu open-on-focus-within"><button id="languages-switcher-button" type="button" class="button action small has-icon languages-switcher-menu" aria-haspopup="menu"><span class="button-wrap"><span class="icon icon-language "></span>English (US)</span></button><div class="hidden"><ul class="submenu language-menu " aria-labelledby="language-menu-button"><li class=" "><form class="submenu-item locale-redirect-setting"><div class="group"><label class="switch"><input type="checkbox" name="locale-redirect"/><span class="slider"></span><span class="label">Remember language</span></label><a href="https://github.com/orgs/mdn/discussions/739" rel="external noopener noreferrer" target="_blank" title="Enable this setting to automatically switch to this language when it's available. (Click to learn more.)"><span class="icon icon-question-mark "></span></a></div></form></li><li class=" "><a data-locale="de" href="/de/docs/Learn_web_development/Core/Frameworks_libraries/React_accessibility" class="button submenu-item"><span>Deutsch</span><span title="Diese Übersetzung ist Teil eines Experiments."><span class="icon icon-experimental "></span></span></a></li><li class=" "><a data-locale="ja" href="/ja/docs/Learn_web_development/Core/Frameworks_libraries/React_accessibility" class="button submenu-item"><span>日本語</span></a></li><li class=" "><a data-locale="ko" href="/ko/docs/Learn_web_development/Core/Frameworks_libraries/React_accessibility" class="button submenu-item"><span>한국어</span></a></li></ul></div></div></li></ul></div></div></div></div><div class="main-wrapper"><div class="sidebar-container"><aside id="sidebar-quicklinks" class="sidebar"><button type="button" class="button action backdrop" aria-label="Collapse sidebar"><span class="button-wrap"></span></button><nav aria-label="Related Topics" class="sidebar-inner"><header class="sidebar-actions"><section class="sidebar-filter-container"><div class="sidebar-filter "><label id="sidebar-filter-label" class="sidebar-filter-label" for="sidebar-filter-input"><span class="icon icon-filter"></span><span class="visually-hidden">Filter sidebar</span></label><input id="sidebar-filter-input" autoComplete="off" class="sidebar-filter-input-field false" type="text" placeholder="Filter" value=""/><button type="button" class="button action has-icon clear-sidebar-filter-button"><span class="button-wrap"><span class="icon icon-cancel "></span><span class="visually-hidden">Clear filter input</span></span></button></div></section></header><div class="sidebar-inner-nav"><div class="in-nav-toc"><div class="document-toc-container"><section class="document-toc"><header><h2 class="document-toc-heading">In this article</h2></header><ul class="document-toc-list"><li class="document-toc-item "><a class="document-toc-link" href="#including_keyboard_users">Including keyboard users</a></li><li class="document-toc-item "><a class="document-toc-link" href="#exploring_the_keyboard_usability_problem">Exploring the keyboard usability problem</a></li><li class="document-toc-item "><a class="document-toc-link" href="#focusing_between_templates">Focusing between templates</a></li><li class="document-toc-item "><a class="document-toc-link" href="#more_robust_focus_management">More robust focus management</a></li><li class="document-toc-item "><a class="document-toc-link" href="#focusing_when_the_user_deletes_a_task">Focusing when the user deletes a task</a></li><li class="document-toc-item "><a class="document-toc-link" href="#finished!">Finished!</a></li></ul></section></div></div><div class="sidebar-body"><ol><li class="section"><a href="/en-US/docs/Learn_web_development/Getting_started">Getting started modules</a></li><li class="toggle"><details><summary><a href="/en-US/docs/Learn_web_development/Getting_started/Environment_setup">Environment setup</a></summary><ol><li><a href="/en-US/docs/Learn_web_development/Getting_started/Environment_setup/Installing_software">Installing basic software</a></li><li><a href="/en-US/docs/Learn_web_development/Getting_started/Environment_setup/Browsing_the_web">Browsing the web</a></li><li><a href="/en-US/docs/Learn_web_development/Getting_started/Environment_setup/Code_editors">Code editors</a></li><li><a href="/en-US/docs/Learn_web_development/Getting_started/Environment_setup/Dealing_with_files">Dealing with files</a></li><li><a href="/en-US/docs/Learn_web_development/Getting_started/Environment_setup/Command_line">Command line crash course</a></li></ol></details></li><li class="toggle"><details><summary><a href="/en-US/docs/Learn_web_development/Getting_started/Your_first_website">Your first website</a></summary><ol><li><a href="/en-US/docs/Learn_web_development/Getting_started/Your_first_website/What_will_your_website_look_like">What will your website look like?</a></li><li><a href="/en-US/docs/Learn_web_development/Getting_started/Your_first_website/Creating_the_content">HTML: Creating the content</a></li><li><a href="/en-US/docs/Learn_web_development/Getting_started/Your_first_website/Styling_the_content">CSS: Styling the content</a></li><li><a href="/en-US/docs/Learn_web_development/Getting_started/Your_first_website/Adding_interactivity">JavaScript: Adding interactivity</a></li><li><a href="/en-US/docs/Learn_web_development/Getting_started/Your_first_website/Publishing_your_website">Publishing your website</a></li></ol></details></li><li class="toggle"><details><summary><a href="/en-US/docs/Learn_web_development/Getting_started/Web_standards">Web standards</a></summary><ol><li><a href="/en-US/docs/Learn_web_development/Getting_started/Web_standards/How_the_web_works">How the web works</a></li><li><a href="/en-US/docs/Learn_web_development/Getting_started/Web_standards/The_web_standards_model">The web standards model</a></li><li><a href="/en-US/docs/Learn_web_development/Getting_started/Web_standards/How_browsers_load_websites">How browsers load websites</a></li></ol></details></li><li class="toggle"><details><summary><a href="/en-US/docs/Learn_web_development/Getting_started/Soft_skills">Soft skills</a></summary><ol><li><a href="/en-US/docs/Learn_web_development/Getting_started/Soft_skills/Research_and_learning">Research and learning</a></li><li><a href="/en-US/docs/Learn_web_development/Getting_started/Soft_skills/Collaboration_and_teamwork">Collaboration and teamwork</a></li><li><a href="/en-US/docs/Learn_web_development/Getting_started/Soft_skills/Workflows_and_processes">Workflows and processes</a></li><li><a href="/en-US/docs/Learn_web_development/Getting_started/Soft_skills/Job_interviews">Succeeding in job interviews</a></li></ol></details></li><li class="section"><a href="/en-US/docs/Learn_web_development/Core">Core modules</a></li><li class="toggle"><details><summary><a href="/en-US/docs/Learn_web_development/Core/Structuring_content">Structuring content with HTML</a></summary><ol><li><a href="/en-US/docs/Learn_web_development/Core/Structuring_content/Basic_HTML_syntax">Basic HTML syntax</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Structuring_content/Webpage_metadata">What's in the head? Webpage metadata</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Structuring_content/Headings_and_paragraphs">Headings and paragraphs in HTML</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Structuring_content/Emphasis_and_importance">Emphasis and importance</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Structuring_content/Lists">Lists</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Structuring_content/Structuring_documents">Structuring documents</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Structuring_content/Advanced_text_features">Advanced text features</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Structuring_content/Creating_links">Creating links</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Structuring_content/Marking_up_a_letter">Challenge: Marking up a letter</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Structuring_content/Structuring_a_page_of_content">Challenge: Structuring a page of content</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Structuring_content/HTML_images">HTML images</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Structuring_content/HTML_video_and_audio">HTML video and audio</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Structuring_content/Mozilla_splash_page">Challenge: Mozilla splash page</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Structuring_content/HTML_table_basics">HTML table basics</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Structuring_content/Table_accessibility">HTML table accessibility</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Structuring_content/Planet_data_table">Challenge: Structuring a planet data table</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Structuring_content/HTML_forms">Forms and buttons in HTML</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Structuring_content/Debugging_HTML">Debugging HTML</a></li></ol></details></li><li class="toggle"><details><summary><a href="/en-US/docs/Learn_web_development/Core/Styling_basics">CSS styling basics</a></summary><ol><li><a href="/en-US/docs/Learn_web_development/Core/Styling_basics/What_is_CSS">What is CSS?</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Styling_basics/Getting_started">Getting started with CSS</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Styling_basics/Styling_a_bio_page">Challenge: Styling a biography page</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Styling_basics/Basic_selectors">Basic CSS selectors</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Styling_basics/Attribute_selectors">Attribute selectors</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Styling_basics/Pseudo_classes_and_elements">Pseudo-classes and pseudo-elements</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Styling_basics/Combinators">Combinators</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Styling_basics/Box_model">The box model</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Styling_basics/Handling_conflicts">Handling conflicts</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Styling_basics/Values_and_units">CSS values and units</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Styling_basics/Sizing">Sizing items in CSS</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Styling_basics/Backgrounds_and_borders">Backgrounds and borders</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Styling_basics/Overflow">Overflowing content</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Styling_basics/Images_media_forms">Images, media, and form elements</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Styling_basics/Tables">Styling tables</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Styling_basics/Debugging_CSS">Debugging CSS</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Styling_basics/Fundamental_CSS_comprehension">Challenge: Fundamental CSS comprehension</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Styling_basics/Fancy_letterheaded_paper">Challenge: Creating fancy letterheaded paper</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Styling_basics/Cool-looking_box">Challenge: A cool-looking box</a></li></ol></details></li><li class="toggle"><details><summary><a href="/en-US/docs/Learn_web_development/Core/Text_styling">CSS text styling</a></summary><ol><li><a href="/en-US/docs/Learn_web_development/Core/Text_styling/Fundamentals">Fundamental text and font styling</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Text_styling/Styling_lists">Styling lists</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Text_styling/Styling_links">Styling links</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Text_styling/Web_fonts">Web fonts</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Text_styling/Typesetting_a_homepage">Challenge: Typesetting a community school homepage</a></li></ol></details></li><li class="toggle"><details><summary><a href="/en-US/docs/Learn_web_development/Core/CSS_layout">CSS layout</a></summary><ol><li><a href="/en-US/docs/Learn_web_development/Core/CSS_layout/Introduction">Introduction to CSS layout</a></li><li><a href="/en-US/docs/Learn_web_development/Core/CSS_layout/Floats">Floats</a></li><li><a href="/en-US/docs/Learn_web_development/Core/CSS_layout/Positioning">Positioning</a></li><li><a href="/en-US/docs/Learn_web_development/Core/CSS_layout/Flexbox">Flexbox</a></li><li><a href="/en-US/docs/Learn_web_development/Core/CSS_layout/Grids">CSS grid layout</a></li><li><a href="/en-US/docs/Learn_web_development/Core/CSS_layout/Responsive_Design">Responsive design</a></li><li><a href="/en-US/docs/Learn_web_development/Core/CSS_layout/Media_queries">Media query fundamentals</a></li><li><a href="/en-US/docs/Learn_web_development/Core/CSS_layout/Fundamental_Layout_Comprehension">Challenge: Fundamental layout comprehension</a></li></ol></details></li><li class="toggle"><details><summary><a href="/en-US/docs/Learn_web_development/Core/Scripting">Dynamic scripting with JavaScript</a></summary><ol><li><a href="/en-US/docs/Learn_web_development/Core/Scripting/What_is_JavaScript">What is JavaScript?</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Scripting/A_first_splash">A first splash into JavaScript</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Scripting/What_went_wrong">What went wrong? Troubleshooting JavaScript</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Scripting/Variables">Storing the information you need — Variables</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Scripting/Math">Basic math in JavaScript — numbers and operators</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Scripting/Strings">Handling text — strings in JavaScript</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Scripting/Useful_string_methods">Useful string methods</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Scripting/Arrays">Arrays</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Scripting/Silly_story_generator">Challenge: Silly story generator</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Scripting/Conditionals">Making decisions in your code — conditionals</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Scripting/Loops">Looping code</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Scripting/Functions">Functions — reusable blocks of code</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Scripting/Build_your_own_function">Build your own function</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Scripting/Return_values">Function return values</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Scripting/Events">Introduction to events</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Scripting/Event_bubbling">Event bubbling</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Scripting/Image_gallery">Challenge: Image gallery</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Scripting/Object_basics">JavaScript object basics</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Scripting/DOM_scripting">DOM scripting introduction</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Scripting/Network_requests">Making network requests with JavaScript</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Scripting/JSON">Working with JSON</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Scripting/Debugging_JavaScript">Debugging JavaScript and handling errors</a></li></ol></details></li><li class="toggle"><details open=""><summary><a href="/en-US/docs/Learn_web_development/Core/Frameworks_libraries">JavaScript frameworks and libraries</a></summary><ol><li><a href="/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Introduction">Introduction to client-side frameworks</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Main_features">Framework main features</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Frameworks_libraries/React_getting_started">Getting started with React</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Frameworks_libraries/React_todo_list_beginning">Beginning our React todo list</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Frameworks_libraries/React_components">Componentizing our React app</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Frameworks_libraries/React_interactivity_events_state">React interactivity: Events and state</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Frameworks_libraries/React_interactivity_filtering_conditional_rendering">React interactivity: Editing, filtering, conditional rendering</a></li><li><em><a href="/en-US/docs/Learn_web_development/Core/Frameworks_libraries/React_accessibility" aria-current="page">Accessibility in React</a></em></li><li><a href="/en-US/docs/Learn_web_development/Core/Frameworks_libraries/React_resources">React resources</a></li></ol></details></li><li class="toggle"><details><summary><a href="/en-US/docs/Learn_web_development/Core/Accessibility">Accessibility</a></summary><ol><li><a href="/en-US/docs/Learn_web_development/Core/Accessibility/What_is_accessibility">What is accessibility?</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Accessibility/Tooling">Accessibility tooling and assistive technology</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Accessibility/HTML">HTML: A good basis for accessibility</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Accessibility/CSS_and_JavaScript">CSS and JavaScript accessibility best practices</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Accessibility/WAI-ARIA_basics">WAI-ARIA basics</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Accessibility/Multimedia">Accessible multimedia</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Accessibility/Mobile">Mobile accessibility</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Accessibility/Accessibility_troubleshooting">Challenge: Accessibility troubleshooting</a></li></ol></details></li><li><a href="/en-US/docs/Learn_web_development/Core/Design_for_developers">Design for developers</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Version_control">Version control</a></li><li class="section"><a href="/en-US/docs/Learn_web_development/Extensions">Extension modules</a></li><li class="toggle"><details><summary><a href="/en-US/docs/Learn_web_development/Extensions/Advanced_JavaScript_objects">Advanced JavaScript objects</a></summary><ol><li><a href="/en-US/docs/Learn_web_development/Extensions/Advanced_JavaScript_objects/Object_prototypes">Object prototypes</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Advanced_JavaScript_objects/Object-oriented_programming">Object-oriented programming</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Advanced_JavaScript_objects/Classes_in_JavaScript">Classes in JavaScript</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Advanced_JavaScript_objects/Object_building_practice">Object building practice</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Advanced_JavaScript_objects/Adding_bouncing_balls_features">Challenge: Adding features to our bouncing balls demo</a></li></ol></details></li><li class="toggle"><details><summary><a href="/en-US/docs/Learn_web_development/Extensions/Client-side_APIs">Client-side web APIs</a></summary><ol><li><a href="/en-US/docs/Learn_web_development/Extensions/Client-side_APIs/Introduction">Introduction to web APIs</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Client-side_APIs/Video_and_audio_APIs">Video and Audio APIs</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Client-side_APIs/Drawing_graphics">Drawing graphics</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Client-side_APIs/Client-side_storage">Client-side storage</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Client-side_APIs/Third_party_APIs">Third-party APIs</a></li></ol></details></li><li class="toggle"><details><summary><a href="/en-US/docs/Learn_web_development/Extensions/Async_JS">Asynchronous JavaScript</a></summary><ol><li><a href="/en-US/docs/Learn_web_development/Extensions/Async_JS/Introducing">Introducing asynchronous JavaScript</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Async_JS/Promises">How to use promises</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Async_JS/Implementing_a_promise-based_API">How to implement a promise-based API</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Async_JS/Introducing_workers">Introducing workers</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Async_JS/Sequencing_animations">Challenge: Sequencing animations</a></li></ol></details></li><li class="toggle"><details><summary><a href="/en-US/docs/Learn_web_development/Extensions/Forms">Web forms</a></summary><ol><li><a href="/en-US/docs/Learn_web_development/Extensions/Forms/Your_first_form">Your first form</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Forms/How_to_structure_a_web_form">How to structure a web form</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Forms/Basic_native_form_controls">Basic native form controls</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Forms/HTML5_input_types">The HTML5 input types</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Forms/Other_form_controls">Other form controls</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Forms/Styling_web_forms">Styling web forms</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Forms/Advanced_form_styling">Advanced form styling</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Forms/UI_pseudo-classes">UI pseudo-classes</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Forms/Form_validation">Client-side form validation</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Forms/Sending_and_retrieving_form_data">Sending form data</a></li></ol></details></li><li class="toggle"><details><summary><a href="/en-US/docs/Learn_web_development/Extensions/Client-side_tools">Understanding client-side tools</a></summary><ol><li><a href="/en-US/docs/Learn_web_development/Extensions/Client-side_tools/Overview">Client-side tooling overview</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Client-side_tools/Package_management">Package management basics</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Client-side_tools/Introducing_complete_toolchain">Introducing a complete toolchain</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Client-side_tools/Deployment">Deploying our app</a></li></ol></details></li><li class="toggle"><details><summary><a href="/en-US/docs/Learn_web_development/Extensions/Server-side">Server-side websites</a></summary><ol><li class="toggle"><details><summary><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/First_steps">Server-side first steps</a></summary><ol><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/First_steps/Introduction">Introduction to the server side</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/First_steps/Client-Server_overview">Client-Server Overview</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/First_steps/Web_frameworks">Server-side web frameworks</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/First_steps/Website_security">Website security</a></li></ol></details></li><li class="toggle"><details><summary><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/Django">Django web framework (Python)</a></summary><ol><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/Django/Introduction">Django introduction</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/Django/development_environment">Setting up a Django development environment</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/Django/Tutorial_local_library_website">Django Tutorial: The Local Library website</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/Django/skeleton_website">Django Tutorial Part 2: Creating a skeleton website</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/Django/Models">Django Tutorial Part 3: Using models</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/Django/Admin_site">Django Tutorial Part 4: Django admin site</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/Django/Home_page">Django Tutorial Part 5: Creating our home page</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/Django/Generic_views">Django Tutorial Part 6: Generic list and detail views</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/Django/Sessions">Django Tutorial Part 7: Sessions framework</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/Django/Authentication">Django Tutorial Part 8: User authentication and permissions</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/Django/Forms">Django Tutorial Part 9: Working with forms</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/Django/Testing">Django Tutorial Part 10: Testing a Django web application</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/Django/Deployment">Django Tutorial Part 11: Deploying Django to production</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/Django/web_application_security">Django web application security</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/Django/django_assessment_blog">Assessment: DIY Django mini blog</a></li></ol></details></li><li class="toggle"><details><summary><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs">Express web framework (Node.js)</a></summary><ol><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/Introduction">Express/Node introduction</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/development_environment">Setting up a Node development environment</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/Tutorial_local_library_website">Express Tutorial: The Local Library website</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/skeleton_website">Express Tutorial Part 2: Creating a skeleton website</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/mongoose">Express Tutorial Part 3: Using a Database (with Mongoose)</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/routes">Express Tutorial Part 4: Routes and controllers</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/Displaying_data">Express Tutorial Part 5: Displaying library data</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/forms">Express Tutorial Part 6: Working with forms</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/deployment">Express Tutorial Part 7: Deploying to production</a></li></ol></details></li></ol></details></li><li class="toggle"><details><summary><a href="/en-US/docs/Learn_web_development/Extensions/Performance">Web performance</a></summary><ol><li><a href="/en-US/docs/Learn_web_development/Extensions/Performance/why_web_performance">The "why" of web performance</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Performance/What_is_web_performance">What is web performance?</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Performance/Perceived_performance">Perceived performance</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Performance/Measuring_performance">Measuring performance</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Performance/Multimedia">Multimedia: Images</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Performance/video">Multimedia: video</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Performance/JavaScript">JavaScript performance optimization</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Performance/HTML">HTML performance optimization</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Performance/CSS">CSS performance optimization</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Performance/business_case_for_performance">The business case for web performance</a></li></ol></details></li><li class="toggle"><details><summary><a href="/en-US/docs/Learn_web_development/Extensions/Testing">Testing</a></summary><ol><li><a href="/en-US/docs/Learn_web_development/Extensions/Testing/Introduction">Introduction to cross-browser testing</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Testing/Testing_strategies">Strategies for carrying out testing</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Testing/HTML_and_CSS">Handling common HTML and CSS problems</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Testing/Feature_detection">Implementing feature detection</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Testing/Automated_testing">Introduction to automated testing</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Testing/Your_own_automation_environment">Setting up your own test automation environment</a></li></ol></details></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Transform_animate">Transform and animate CSS</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Security_privacy">Security and privacy</a></li><li class="section">Further resources</li><li class="toggle"><details><summary><a href="/en-US/docs/Learn_web_development/Howto">How to solve common problems</a></summary><ol><li><a href="/en-US/docs/Learn_web_development/Howto/Solve_HTML_problems">Solve common HTML problems</a></li><li><a href="/en-US/docs/Learn_web_development/Howto/Solve_CSS_problems">Solve common CSS problems</a></li><li><a href="/en-US/docs/Learn_web_development/Howto/Solve_JavaScript_problems">Solve common JavaScript problems</a></li><li><a href="/en-US/docs/Learn_web_development/Howto/Web_mechanics">Web mechanics</a></li><li><a href="/en-US/docs/Learn_web_development/Howto/Tools_and_setup">Tools and setup</a></li><li><a href="/en-US/docs/Learn_web_development/Howto/Design_and_accessibility">Design and accessibility</a></li></ol></details></li><li><a href="/en-US/docs/Learn_web_development/About">About</a></li><li><a href="/en-US/docs/Learn_web_development/Educators">Resources for educators</a></li><li><a href="/en-US/docs/Learn_web_development/Changelog">Changelog</a></li></ol></div></div><section class="place side"></section></nav></aside><div class="toc-container"><aside class="toc"><nav><div class="document-toc-container"><section class="document-toc"><header><h2 class="document-toc-heading">In this article</h2></header><ul class="document-toc-list"><li class="document-toc-item "><a class="document-toc-link" href="#including_keyboard_users">Including keyboard users</a></li><li class="document-toc-item "><a class="document-toc-link" href="#exploring_the_keyboard_usability_problem">Exploring the keyboard usability problem</a></li><li class="document-toc-item "><a class="document-toc-link" href="#focusing_between_templates">Focusing between templates</a></li><li class="document-toc-item "><a class="document-toc-link" href="#more_robust_focus_management">More robust focus management</a></li><li class="document-toc-item "><a class="document-toc-link" href="#focusing_when_the_user_deletes_a_task">Focusing when the user deletes a task</a></li><li class="document-toc-item "><a class="document-toc-link" href="#finished!">Finished!</a></li></ul></section></div></nav></aside><section class="place side"></section></div></div><main id="content" class="main-content "><article class="main-page-content" lang="en-US"><header><h1>Accessibility in React</h1></header><div class="section-content"><ul class="prev-next"><li><a class="button secondary" href="/en-US/docs/Learn_web_development/Core/Frameworks_libraries/React_interactivity_filtering_conditional_rendering"><span class="button-wrap"> Previous </span></a></li><li><a class="button secondary" href="/en-US/docs/Learn_web_development/Core/Frameworks_libraries"><span class="button-wrap"> Overview: JavaScript frameworks and libraries</span></a></li><li><a class="button secondary" href="/en-US/docs/Learn_web_development/Core/Frameworks_libraries/React_resources"><span class="button-wrap"> Next </span></a></li></ul> <p>In our final tutorial article, we'll focus on (pun intended) accessibility, including focus management in React, which can improve usability and reduce confusion for both keyboard-only and screen reader users.</p> <figure class="table-container"><table> <tbody> <tr> <th scope="row">Prerequisites:</th> <td> Familiarity with the core <a href="/en-US/docs/Learn_web_development/Core/Structuring_content">HTML</a>, <a href="/en-US/docs/Learn_web_development/Core/Styling_basics">CSS</a>, and <a href="/en-US/docs/Learn_web_development/Core/Scripting">JavaScript</a> languages, and the <a href="/en-US/docs/Learn_web_development/Getting_started/Environment_setup/Command_line">terminal/command line</a>. </td> </tr> <tr> <th scope="row">Learning outcomes:</th> <td>Implementing keyboard accessibility in React.</td> </tr> </tbody> </table></figure></div><section aria-labelledby="including_keyboard_users"><h2 id="including_keyboard_users"><a href="#including_keyboard_users">Including keyboard users</a></h2><div class="section-content"><p>At this point, we've implemented all the features we set out to implement. Users can add a new task, check and uncheck tasks, delete tasks, or edit task names. Also, they can filter their task list by all, active, or completed tasks.</p> <p>Or, at least, they can do all of these things with a mouse. Unfortunately, these features are not very accessible to keyboard-only users. Let's explore this now.</p></div></section><section aria-labelledby="exploring_the_keyboard_usability_problem"><h2 id="exploring_the_keyboard_usability_problem"><a href="#exploring_the_keyboard_usability_problem">Exploring the keyboard usability problem</a></h2><div class="section-content"><p>Start by clicking on the input at the top of our app, as if you're going to add a new task. You'll see a thick, dashed outline around that input. This outline is your visual indicator that the browser is currently focused on this element. Press the <kbd>Tab</kbd> key, and you will see the outline appear around the "Add" button beneath the input. This shows you that the browser's focus has moved.</p> <p>Press <kbd>Tab</kbd> a few more times, and you will see this dashed focus indicator move between each of the filter buttons. Keep going until the focus indicator is around the first "Edit" button. Press <kbd>Enter</kbd>.</p> <p>The <code><Todo /></code> component will switch templates, as we designed, and you'll see a form that lets us edit the name of the task.</p> <p>But where did our focus indicator go?</p> <p>When we switch between templates in our <code><Todo /></code> component, we completely remove the elements from the old template and replace them with the elements from the new template. That means the element that we were focused on no longer exists, so there's no visual cue as to where the browser's focus is. This could confuse a wide variety of users — particularly users who rely on the keyboard, or users who use assistive technology.</p> <p>To improve the experience for keyboard and assistive technology users, we should manage the browser's focus ourselves.</p></div></section><section aria-labelledby="aside_a_note_on_our_focus_indicator"><h3 id="aside_a_note_on_our_focus_indicator"><a href="#aside_a_note_on_our_focus_indicator">Aside: a note on our focus indicator</a></h3><div class="section-content"><p>If you click the "All", "Active", or "Completed" filter buttons with your mouse, you <em>won't</em> see a visible focus indicator, but you will do if you move between them with the <kbd>Tab</kbd> key on your keyboard. Don't worry — your code isn't broken!</p> <p>Our CSS file uses the <a href="/en-US/docs/Web/CSS/:focus-visible"><code>:focus-visible</code></a> pseudo-class to provide custom styling for the focus indicator, and the browser uses a set of internal rules to determine when to show it to the user. Generally, the browser <em>will</em> show a focus indicator in response to keyboard input, and <em>might</em> show it in response to mouse input. <code><button></code> elements <em>don't</em> show a focus indicator in response to mouse input, while <code><input></code> elements <em>do</em>.</p> <p>The behavior of <code>:focus-visible</code> is more selective than the older <a href="/en-US/docs/Web/CSS/:focus"><code>:focus</code></a> pseudo-class, with which you might be more familiar. <code>:focus</code> shows a focus indicator in many more situations, and you can use it instead of or in combination with <code>:focus-visible</code> if you prefer.</p></div></section><section aria-labelledby="focusing_between_templates"><h2 id="focusing_between_templates"><a href="#focusing_between_templates">Focusing between templates</a></h2><div class="section-content"><p>When a user changes the <code><Todo /></code> template from viewing to editing, we should focus on the <code><input></code> used to rename it; when they change back from editing to viewing, we should move focus back to the "Edit" button.</p></div></section><section aria-labelledby="targeting_our_elements"><h3 id="targeting_our_elements"><a href="#targeting_our_elements">Targeting our elements</a></h3><div class="section-content"><p>Up to this point, we've been writing JSX components and letting React build the resulting DOM behind the scenes. Most of the time, we don't need to target specific elements in the DOM because we can use React's state and props to control what gets rendered. To manage focus, however, we <em>do</em> need to be able to target specific DOM elements.</p> <p>This is where the <code>useRef()</code> hook comes in.</p> <p>First, change the <code>import</code> statement at the top of <code>Todo.jsx</code> so that it includes <code>useRef</code>:</p> <div class="code-example"><div class="example-header"><span class="language-name">jsx</span></div><pre class="brush: jsx notranslate"><code>import { useRef, useState } from "react"; </code></pre></div> <p><code>useRef()</code> creates an object with a single property: <code>current</code>. Refs can store any values we want them to, and we can look up those values later. We can even store references to DOM elements, which is exactly what we're going to do here.</p> <p>Next, create two new constants beneath the <code>useState()</code> hooks in your <code>Todo()</code> function. Each should be a ref – one for the "Edit" button in the view template and one for the edit field in the editing template.</p> <div class="code-example"><div class="example-header"><span class="language-name">jsx</span></div><pre class="brush: jsx notranslate"><code>const editFieldRef = useRef(null); const editButtonRef = useRef(null); </code></pre></div> <p>These refs have a default value of <code>null</code> to make it clear that they'll be empty until they're attached to their DOM elements. To attach them to their elements, we'll add the special <code>ref</code> attribute to each element's JSX, and set the values of those attributes to the appropriately named <code>ref</code> objects.</p> <p>Update the <code><input></code> in your editing template so that it reads like this:</p> <div class="code-example"><div class="example-header"><span class="language-name">jsx</span></div><pre class="brush: jsx notranslate"><code><input id={props.id} className="todo-text" type="text" value={newName} onChange={handleChange} ref={editFieldRef} /> </code></pre></div> <p>Update the "Edit" button in your view template so that it reads like this:</p> <div class="code-example"><div class="example-header"><span class="language-name">jsx</span></div><pre class="brush: jsx notranslate"><code><button type="button" className="btn" onClick={() => setEditing(true)} ref={editButtonRef}> Edit <span className="visually-hidden">{props.name}</span> </button> </code></pre></div> <p>Doing this will populate our <code>editFieldRef</code> and <code>editButtonRef</code> with references to the DOM elements they're attached to, but <em>only</em> after React has rendered the component. Test that out for yourself: add the following line somewhere in the body of your <code>Todo()</code> function, below where <code>editButtonRef</code> is initialized:</p> <div class="code-example"><div class="example-header"><span class="language-name">jsx</span></div><pre class="brush: jsx notranslate"><code>console.log(editButtonRef.current); </code></pre></div> <p>You'll see that the value of <code>editButtonRef.current</code> is <code>null</code> when the component first renders, but if you click an "Edit" button, it will log the <code><button></code> element to the console. This is because the ref is populated only after the component renders, and clicking the "Edit" button causes the component to re-render. Be sure to delete this log before moving on.</p> <div class="notecard note"> <p><strong>Note:</strong> Your logs will appear 6 times because we have 3 instances of <code><Todo /></code> in our app and React renders our components twice in development.</p> </div> <p>We're getting closer! To take advantage of our newly referenced elements, we need to use another React hook: <code>useEffect()</code>.</p></div></section><section aria-labelledby="implementing_useeffect"><h3 id="implementing_useeffect"><a href="#implementing_useeffect">Implementing <code>useEffect()</code></a></h3><div class="section-content"><p><a href="https://react.dev/reference/react/useEffect" class="external" target="_blank"><code>useEffect()</code></a> is so named because it runs any side-effects that we'd like to add to the render process but which can't be run inside the main function body. <code>useEffect()</code> runs right after a component renders, meaning the DOM elements we referenced in the previous section will be available for us to use.</p> <p>Change the import statement of <code>Todo.jsx</code> again to add <code>useEffect</code>:</p> <div class="code-example"><div class="example-header"><span class="language-name">jsx</span></div><pre class="brush: jsx notranslate"><code>import { useEffect, useRef, useState } from "react"; </code></pre></div> <p><code>useEffect()</code> takes a function as an argument; this function is executed <em>after</em> the component renders. To demonstrate this, put the following <code>useEffect()</code> call just above the <code>return</code> statement in the body of <code>Todo()</code>, and pass a function into it that logs the words "side effect" to your console:</p> <div class="code-example"><div class="example-header"><span class="language-name">jsx</span></div><pre class="brush: jsx notranslate"><code>useEffect(() => { console.log("side effect"); }); </code></pre></div> <p>To illustrate the difference between the main render process and code run inside <code>useEffect()</code>, add another log – put this one below the previous addition:</p> <div class="code-example"><div class="example-header"><span class="language-name">jsx</span></div><pre class="brush: jsx notranslate"><code>console.log("main render"); </code></pre></div> <p>Now, open the app in your browser. You should see both messages in your console, with each one repeating multiple times. Note how "main render" logged first, and "side effect" logged second, even though the "side effect" log appears first in the code.</p> <pre class="brush: plain notranslate">main render Todo.jsx side effect Todo.jsx </pre> <p>Again, the logs are ordered this way because code inside <code>useEffect()</code> runs <em>after</em> the component renders. This takes some getting used to, just keep it in mind as you move forward. For now, delete <code>console.log("main render")</code> and we'll move on to implementing our focus management.</p></div></section><section aria-labelledby="focusing_on_our_editing_field"><h3 id="focusing_on_our_editing_field"><a href="#focusing_on_our_editing_field">Focusing on our editing field</a></h3><div class="section-content"><p>Now that we know our <code>useEffect()</code> hook works, we can manage focus with it. As a reminder, we want to focus on the editing field when we switch to the editing template.</p> <p>Update your existing <code>useEffect()</code> hook so that it reads like this:</p> <div class="code-example"><div class="example-header"><span class="language-name">jsx</span></div><pre class="brush: jsx notranslate"><code>useEffect(() => { if (isEditing) { editFieldRef.current.focus(); } }, [isEditing]); </code></pre></div> <p>These changes make it so that, if <code>isEditing</code> is true, React reads the current value of the <code>editFieldRef</code> and moves browser focus to it. We also pass an array into <code>useEffect()</code> as a second argument. This array is a list of values <code>useEffect()</code> should depend on. With these values included, <code>useEffect()</code> will only run when one of those values changes. We only want to change focus when the value of <code>isEditing</code> changes.</p> <p>Try it now: use the <kbd>Tab</kbd> key to navigate to one of the "Edit" buttons, then press <kbd>Enter</kbd>. You should see the <code><Todo /></code> component switch to its editing template, and the browser focus indicator should appear around the <code><input></code> element!</p></div></section><section aria-labelledby="moving_focus_back_to_the_edit_button"><h3 id="moving_focus_back_to_the_edit_button"><a href="#moving_focus_back_to_the_edit_button">Moving focus back to the edit button</a></h3><div class="section-content"><p>At first glance, getting React to move focus back to our "Edit" button when the edit is saved or cancelled appears deceptively easy. Surely we could add a condition to our <code>useEffect</code> to focus on the edit button if <code>isEditing</code> is <code>false</code>? Let's try it now — update your <code>useEffect()</code> call like so:</p> <div class="code-example"><div class="example-header"><span class="language-name">jsx</span></div><pre class="brush: jsx notranslate"><code>useEffect(() => { if (isEditing) { editFieldRef.current.focus(); } else { editButtonRef.current.focus(); } }, [isEditing]); </code></pre></div> <p>This kind of works. If you use your keyboard to trigger the "Edit" button (remember: <kbd>Tab</kbd> to it and press <kbd>Enter</kbd>), you'll see that your focus moves between the Edit <code><input></code> and "Edit" button as you start and end an edit. However, you may have noticed a new problem — the "Edit" button in the final <code><Todo /></code> component is focused immediately on page load before we even interact with the app!</p> <p>Our <code>useEffect()</code> hook is behaving exactly as we designed it: it runs as soon as the component renders, sees that <code>isEditing</code> is <code>false</code>, and focuses the "Edit" button. There are three instances of <code><Todo /></code>, and focus is given to the "Edit" button of the one that renders last.</p> <p>We need to refactor our approach so that focus changes only when <code>isEditing</code> changes from one value to another.</p></div></section><section aria-labelledby="more_robust_focus_management"><h2 id="more_robust_focus_management"><a href="#more_robust_focus_management">More robust focus management</a></h2><div class="section-content"><p>To meet our refined criteria, we need to know not just the value of <code>isEditing</code>, but also <em>when that value has changed</em>. To do that, we need to be able to read the previous value of the <code>isEditing</code> constant. Using pseudocode, our logic should be something like this:</p> <div class="code-example"><div class="example-header"><span class="language-name">jsx</span></div><pre class="brush: jsx notranslate"><code>if (wasNotEditingBefore && isEditingNow) { focusOnEditField(); } else if (wasEditingBefore && isNotEditingNow) { focusOnEditButton(); } </code></pre></div> <p>The React team has discussed <a href="https://legacy.reactjs.org/docs/hooks-faq.html#how-to-get-the-previous-props-or-state" class="external" target="_blank">ways to get a component's previous state</a>, and provided an example hook we can use for the job.</p></div></section><section aria-labelledby="enter_useprevious"><h3 id="enter_useprevious"><a href="#enter_useprevious">Enter <code>usePrevious()</code></a></h3><div class="section-content"><p>Paste the following code near the top of <code>Todo.jsx</code>, above your <code>Todo()</code> function.</p> <div class="code-example"><div class="example-header"><span class="language-name">jsx</span></div><pre class="brush: jsx notranslate"><code>function usePrevious(value) { const ref = useRef(); useEffect(() => { ref.current = value; }); return ref.current; } </code></pre></div> <p><code>usePrevious()</code> is a <em>custom hook</em> that tracks a value across renders. It:</p> <ol> <li>Uses the <code>useRef()</code> hook to create an empty <code>ref</code>.</li> <li>Returns the <code>ref</code>'s <code>current</code> value to the component that called it.</li> <li>Calls <code>useEffect()</code> and updates the value stored in <code>ref.current</code> after each rendering of the calling component.</li> </ol> <p>The behavior of <code>useEffect()</code> is key to this functionality. Because <code>ref.current</code> is updated inside a <code>useEffect()</code> call, it's always one step behind whatever value is in the component's main render cycle – hence the name <code>usePrevious()</code>.</p></div></section><section aria-labelledby="using_useprevious"><h3 id="using_useprevious"><a href="#using_useprevious">Using <code>usePrevious()</code></a></h3><div class="section-content"><p>Now we can define a <code>wasEditing</code> constant to track the previous value of <code>isEditing</code>; this is achieved by calling <code>usePrevious</code> with <code>isEditing</code> as an argument. Add the following inside <code>Todo()</code>, below the <code>useRef</code> lines:</p> <div class="code-example"><div class="example-header"><span class="language-name">jsx</span></div><pre class="brush: jsx notranslate"><code>const wasEditing = usePrevious(isEditing); </code></pre></div> <p>You can see how <code>usePrevious()</code> behaves by adding a console log beneath this line:</p> <div class="code-example"><div class="example-header"><span class="language-name">jsx</span></div><pre class="brush: jsx notranslate"><code>console.log(wasEditing); </code></pre></div> <p>In this log, the <code>current</code> value of <code>wasEditing</code> will always be the previous value of <code>isEditing</code>. Click on the "Edit" and "Cancel" button a few times to watch it change, then delete this log when you're ready to move on.</p> <p>With this <code>wasEditing</code> constant, we can update our <code>useEffect()</code> hook to implement the pseudocode we discussed before:</p> <div class="code-example"><div class="example-header"><span class="language-name">jsx</span></div><pre class="brush: jsx notranslate"><code>useEffect(() => { if (!wasEditing && isEditing) { editFieldRef.current.focus(); } else if (wasEditing && !isEditing) { editButtonRef.current.focus(); } }, [wasEditing, isEditing]); </code></pre></div> <p>Note that the logic of <code>useEffect()</code> now depends on <code>wasEditing</code>, so we provide it in the array of dependencies.</p> <p>Try using your keyboard to activate the "Edit" and "Cancel" buttons in the <code><Todo /></code> component; you'll see the browser focus indicator move appropriately, without the problem we discussed at the start of this section.</p></div></section><section aria-labelledby="focusing_when_the_user_deletes_a_task"><h2 id="focusing_when_the_user_deletes_a_task"><a href="#focusing_when_the_user_deletes_a_task">Focusing when the user deletes a task</a></h2><div class="section-content"><p>There's one last keyboard experience gap: when a user deletes a task from the list, the focus vanishes. We're going to follow a pattern similar to our previous changes: we'll make a new ref, and utilize our <code>usePrevious()</code> hook, so that we can focus on the list heading whenever a user deletes a task.</p></div></section><section aria-labelledby="why_the_list_heading"><h3 id="why_the_list_heading"><a href="#why_the_list_heading">Why the list heading?</a></h3><div class="section-content"><p>Sometimes, the place we want to send our focus to is obvious: when we toggled our <code><Todo /></code> templates, we had an origin point to "go back" to — the "Edit" button. In this case however, since we're completely removing elements from the DOM, we have no place to go back to. The next best thing is an intuitive location somewhere nearby. The list heading is our best choice because it's close to the list item the user will delete, and focusing on it will tell the user how many tasks are left.</p></div></section><section aria-labelledby="creating_our_ref"><h3 id="creating_our_ref"><a href="#creating_our_ref">Creating our ref</a></h3><div class="section-content"><p>Import the <code>useRef()</code> and <code>useEffect()</code> hooks into <code>App.jsx</code> — you'll need them both below:</p> <div class="code-example"><div class="example-header"><span class="language-name">jsx</span></div><pre class="brush: jsx notranslate"><code>import { useState, useRef, useEffect } from "react"; </code></pre></div> <p>Next, declare a new ref inside the <code>App()</code> function, just above the <code>return</code> statement:</p> <div class="code-example"><div class="example-header"><span class="language-name">jsx</span></div><pre class="brush: jsx notranslate"><code>const listHeadingRef = useRef(null); </code></pre></div></div></section><section aria-labelledby="prepare_the_heading"><h3 id="prepare_the_heading"><a href="#prepare_the_heading">Prepare the heading</a></h3><div class="section-content"><p>Heading elements like our <code><h2></code> are not usually focusable. This isn't a problem — we can make any element programmatically focusable by adding the attribute <a href="/en-US/docs/Web/HTML/Global_attributes/tabindex"><code>tabindex="-1"</code></a> to it. This means <em>only focusable with JavaScript</em>. You can't press <kbd>Tab</kbd> to focus on an element with a tabindex of <code>-1</code> the same way you could do with a <a href="/en-US/docs/Web/HTML/Element/button"><code><button></code></a> or <a href="/en-US/docs/Web/HTML/Element/a"><code><a></code></a> element (this can be done using <code>tabindex="0"</code>, but that's not appropriate in this case).</p> <p>Let's add the <code>tabindex</code> attribute — written as <code>tabIndex</code> in JSX — to the heading above our list of tasks, along with our <code>listHeadingRef</code>:</p> <div class="code-example"><div class="example-header"><span class="language-name">jsx</span></div><pre class="brush: jsx notranslate"><code><h2 id="list-heading" tabIndex="-1" ref={listHeadingRef}> {headingText} </h2> </code></pre></div> <div class="notecard note"> <p><strong>Note:</strong> The <code>tabindex</code> attribute is excellent for accessibility edge cases, but you should take <strong>great care</strong> not to overuse it. Only apply a <code>tabindex</code> to an element when you're sure that making it focusable will benefit your user somehow. In most cases, you should utilize elements that can naturally take focus, such as buttons, anchors, and inputs. Irresponsible usage of <code>tabindex</code> could have a profoundly negative impact on keyboard and screen reader users!</p> </div></div></section><section aria-labelledby="getting_previous_state"><h3 id="getting_previous_state"><a href="#getting_previous_state">Getting previous state</a></h3><div class="section-content"><p>We want to focus on the element associated with our ref (via the <code>ref</code> attribute) only when our user deletes a task from their list. That's going to require the <code>usePrevious()</code> hook we used earlier on. Add it to the top of your <code>App.jsx</code> file, just below the imports:</p> <div class="code-example"><div class="example-header"><span class="language-name">jsx</span></div><pre class="brush: jsx notranslate"><code>function usePrevious(value) { const ref = useRef(); useEffect(() => { ref.current = value; }); return ref.current; } </code></pre></div> <p>Now add the following, above the <code>return</code> statement inside the <code>App()</code> function:</p> <div class="code-example"><div class="example-header"><span class="language-name">jsx</span></div><pre class="brush: jsx notranslate"><code>const prevTaskLength = usePrevious(tasks.length); </code></pre></div> <p>Here we are invoking <code>usePrevious()</code> to track the previous length of the tasks array.</p> <div class="notecard note"> <p><strong>Note:</strong> Since we're now utilizing <code>usePrevious()</code> in two files, it might be more efficient to move the <code>usePrevious()</code> function into its own file, export it from that file, and import it where you need it. Try doing this as an exercise once you've got to the end.</p> </div></div></section><section aria-labelledby="using_useeffect_to_control_our_heading_focus"><h3 id="using_useeffect_to_control_our_heading_focus"><a href="#using_useeffect_to_control_our_heading_focus">Using <code>useEffect()</code> to control our heading focus</a></h3><div class="section-content"><p>Now that we've stored how many tasks we previously had, we can set up a <code>useEffect()</code> hook to run when our number of tasks changes, which will focus the heading if the number of tasks we have now is less than it previously was — that is, we deleted a task!</p> <p>Add the following into the body of your <code>App()</code> function, just below your previous additions:</p> <div class="code-example"><div class="example-header"><span class="language-name">jsx</span></div><pre class="brush: jsx notranslate"><code>useEffect(() => { if (tasks.length < prevTaskLength) { listHeadingRef.current.focus(); } }, [tasks.length, prevTaskLength]); </code></pre></div> <p>We only try to focus on our list heading if we have fewer tasks now than we did before. The dependencies passed into this hook ensure it will only try to re-run when either of those values (the number of current tasks, or the number of previous tasks) changes.</p> <p>Now, when you use your keyboard to delete a task in your browser, you will see our dashed focus outline appear around the heading above the list.</p></div></section><section aria-labelledby="finished!"><h2 id="finished!"><a href="#finished!">Finished!</a></h2><div class="section-content"><p>You've just finished building a React app from the ground up! Congratulations! The skills you've learned here will be a great foundation to build on as you continue working with React.</p> <p>Most of the time, you can be an effective contributor to a React project even if all you do is think carefully about components and their state and props. Remember to always write the best HTML you can.</p> <p><code>useRef()</code> and <code>useEffect()</code> are somewhat advanced features, and you should be proud of yourself for using them! Look out for opportunities to practice them more, because doing so will allow you to create inclusive experiences for users. Remember: our app would have been inaccessible to keyboard users without them!</p> <div class="notecard note"> <p><strong>Note:</strong> If you need to check your code against our version, you can find a finished version of the sample React app code in our <a href="https://github.com/mdn/todo-react" class="external" target="_blank">todo-react repository</a>. For a running live version, see <a href="https://mdn.github.io/todo-react/" class="external" target="_blank">https://mdn.github.io/todo-react/</a>.</p> </div> <p>In the very last article we'll present you with a list of React resources that you can use to go further in your learning.</p> <ul class="prev-next"><li><a class="button secondary" href="/en-US/docs/Learn_web_development/Core/Frameworks_libraries/React_interactivity_filtering_conditional_rendering"><span class="button-wrap"> Previous </span></a></li><li><a class="button secondary" href="/en-US/docs/Learn_web_development/Core/Frameworks_libraries"><span class="button-wrap"> Overview: JavaScript frameworks and libraries</span></a></li><li><a class="button secondary" href="/en-US/docs/Learn_web_development/Core/Frameworks_libraries/React_resources"><span class="button-wrap"> Next </span></a></li></ul></div></section></article><aside class="article-footer"><div class="article-footer-inner"><div class="svg-container"><svg xmlns="http://www.w3.org/2000/svg" width="162" height="162" viewBox="0 0 162 162" fill="none" role="none"><mask id="b" fill="#fff"><path d="M97.203 47.04c8.113-7.886 18.004-13.871 28.906-17.492a78 78 0 0 1 33.969-3.39c11.443 1.39 22.401 5.295 32.024 11.411s17.656 14.28 23.476 23.86c5.819 9.579 9.269 20.318 10.083 31.385a69.85 69.85 0 0 1-5.387 32.44c-4.358 10.272-11.115 19.443-19.747 26.801-8.632 7.359-18.908 12.709-30.034 15.637l-6.17-21.698c7.666-2.017 14.746-5.703 20.694-10.773 5.948-5.071 10.603-11.389 13.606-18.467a48.14 48.14 0 0 0 3.712-22.352c-.561-7.625-2.938-15.025-6.948-21.625s-9.544-12.226-16.175-16.44-14.181-6.904-22.065-7.863a53.75 53.75 0 0 0-23.405 2.336c-7.513 2.495-14.327 6.62-19.918 12.053z"></path></mask><path stroke="url(#a)" stroke-dasharray="6, 6" stroke-width="2" d="M97.203 47.04c8.113-7.886 18.004-13.871 28.906-17.492a78 78 0 0 1 33.969-3.39c11.443 1.39 22.401 5.295 32.024 11.411s17.656 14.28 23.476 23.86c5.819 9.579 9.269 20.318 10.083 31.385a69.85 69.85 0 0 1-5.387 32.44c-4.358 10.272-11.115 19.443-19.747 26.801-8.632 7.359-18.908 12.709-30.034 15.637l-6.17-21.698c7.666-2.017 14.746-5.703 20.694-10.773 5.948-5.071 10.603-11.389 13.606-18.467a48.14 48.14 0 0 0 3.712-22.352c-.561-7.625-2.938-15.025-6.948-21.625s-9.544-12.226-16.175-16.44-14.181-6.904-22.065-7.863a53.75 53.75 0 0 0-23.405 2.336c-7.513 2.495-14.327 6.62-19.918 12.053z" mask="url(#b)" style="stroke:url(#a)" transform="translate(-63.992 -25.587)"></path><ellipse cx="8.066" cy="111.597" fill="var(--background-tertiary)" rx="53.677" ry="53.699" transform="matrix(.71707 -.697 .7243 .6895 0 0)"></ellipse><g clip-path="url(#c)" transform="translate(-63.992 -25.587)"><path fill="#9abff5" d="m144.256 137.379 32.906 12.434a4.41 4.41 0 0 1 2.559 5.667l-9.326 24.679a4.41 4.41 0 0 1-5.667 2.559l-8.226-3.108-2.332 6.17c-.466 1.233-.375 1.883-1.609 1.417l-2.253-.527c-.411-.155-.95-.594-1.206-1.161l-4.734-10.484-12.545-4.741a4.41 4.41 0 0 1-2.559-5.667l9.325-24.679a4.41 4.41 0 0 1 5.667-2.559m9.961 29.617 8.227 3.108 3.264-8.638-.498-6.768-4.113-1.555.548 7.258-4.319-1.632zm-12.339-4.663 8.226 3.108 3.264-8.637-.498-6.769-4.113-1.554.548 7.257-4.319-1.632z"></path></g><g clip-path="url(#d)" transform="translate(-63.992 -25.587)"><path fill="#81b0f3" d="M135.35 60.136 86.67 41.654c-3.346-1.27-7.124.428-8.394 3.775L64.414 81.938c-1.27 3.347.428 7.125 3.774 8.395l12.17 4.62-3.465 9.128c-.693 1.826-1.432 2.457.394 3.15l3.014 1.625c.609.231 1.637.274 2.477-.104l15.53-6.983 18.56 7.047c3.346 1.27 7.124-.428 8.395-3.775l13.862-36.51c1.27-3.346-.428-7.124-3.775-8.395M95.261 83.207l-12.17-4.62 4.852-12.779 7.19-7.017 6.085 2.31-7.725 7.51 6.389 2.426zm18.255 6.93-12.17-4.62 4.852-12.778 7.189-7.017 6.085 2.31-7.725 7.51 6.39 2.426z"></path></g><defs><clipPath id="c"><path fill="#fff" d="m198.638 146.586-65.056-24.583-24.583 65.057 65.056 24.582z"></path></clipPath><clipPath id="d"><path fill="#fff" d="m66.438 14.055 96.242 36.54-36.54 96.243-96.243-36.54z"></path></clipPath><linearGradient id="a" x1="97.203" x2="199.995" y1="47.04" y2="152.793" gradientUnits="userSpaceOnUse"><stop stop-color="#086DFC"></stop><stop offset="0.246" stop-color="#2C81FA"></stop><stop offset="0.516" stop-color="#5497F8"></stop><stop offset="0.821" stop-color="#80B0F6"></stop><stop offset="1" stop-color="#9ABFF5"></stop></linearGradient></defs></svg></div><h2>Help improve MDN</h2><fieldset class="feedback"><label>Was this page helpful to you?</label><div class="button-container"><button type="button" class="button primary has-icon yes"><span class="button-wrap"><span class="icon icon-thumbs-up "></span>Yes</span></button><button type="button" class="button primary has-icon no"><span class="button-wrap"><span class="icon icon-thumbs-down "></span>No</span></button></div></fieldset><a class="contribute" href="https://github.com/mdn/content/blob/main/CONTRIBUTING.md" title="This will take you to our contribution guidelines on GitHub." target="_blank" rel="noopener noreferrer">Learn how to contribute</a>.<p class="last-modified-date">This page was last modified on<!-- --> <time dateTime="2024-12-19T15:37:45.000Z">Dec 19, 2024</time> by<!-- --> <a href="/en-US/docs/Learn_web_development/Core/Frameworks_libraries/React_accessibility/contributors.txt" rel="nofollow">MDN contributors</a>.</p><div id="on-github" class="on-github"><a href="https://github.com/mdn/content/blob/main/files/en-us/learn_web_development/core/frameworks_libraries/react_accessibility/index.md?plain=1" title="Folder: en-us/learn_web_development/core/frameworks_libraries/react_accessibility (Opens in a new tab)" target="_blank" rel="noopener noreferrer">View this page on GitHub</a> <!-- -->•<!-- --> <a href="https://github.com/mdn/content/issues/new?template=page-report.yml&mdn-url=https%3A%2F%2Fdeveloper.mozilla.org%2Fen-US%2Fdocs%2FLearn_web_development%2FCore%2FFrameworks_libraries%2FReact_accessibility&metadata=%3C%21--+Do+not+make+changes+below+this+line+--%3E%0A%3Cdetails%3E%0A%3Csummary%3EPage+report+details%3C%2Fsummary%3E%0A%0A*+Folder%3A+%60en-us%2Flearn_web_development%2Fcore%2Fframeworks_libraries%2Freact_accessibility%60%0A*+MDN+URL%3A+https%3A%2F%2Fdeveloper.mozilla.org%2Fen-US%2Fdocs%2FLearn_web_development%2FCore%2FFrameworks_libraries%2FReact_accessibility%0A*+GitHub+URL%3A+https%3A%2F%2Fgithub.com%2Fmdn%2Fcontent%2Fblob%2Fmain%2Ffiles%2Fen-us%2Flearn_web_development%2Fcore%2Fframeworks_libraries%2Freact_accessibility%2Findex.md%0A*+Last+commit%3A+https%3A%2F%2Fgithub.com%2Fmdn%2Fcontent%2Fcommit%2F5b20f5f4265f988f80f513db0e4b35c7e0cd70dc%0A*+Document+last+modified%3A+2024-12-19T15%3A37%3A45.000Z%0A%0A%3C%2Fdetails%3E" title="This will take you to GitHub to file a new issue." target="_blank" rel="noopener noreferrer">Report a problem with this content</a></div></div></aside></main></div></div><footer id="nav-footer" class="page-footer"><div class="page-footer-grid"><div class="page-footer-logo-col"><a href="/" class="mdn-footer-logo" aria-label="MDN homepage"><svg width="48" height="17" viewBox="0 0 48 17" fill="none" xmlns="http://www.w3.org/2000/svg"><title id="mdn-footer-logo-svg">MDN logo</title><path d="M20.04 16.512H15.504V10.416C15.504 9.488 15.344 8.824 15.024 8.424C14.72 8.024 14.264 7.824 13.656 7.824C12.92 7.824 12.384 8.064 12.048 8.544C11.728 9.024 11.568 9.64 11.568 10.392V14.184H13.008V16.512H8.472V10.416C8.472 9.488 8.312 8.824 7.992 8.424C7.688 8.024 7.232 7.824 6.624 7.824C5.872 7.824 5.336 8.064 5.016 8.544C4.696 9.024 4.536 9.64 4.536 10.392V14.184H6.6V16.512H0V14.184H1.44V8.04H0.024V5.688H4.536V7.32C5.224 6.088 6.32 5.472 7.824 5.472C8.608 5.472 9.328 5.664 9.984 6.048C10.64 6.432 11.096 7.016 11.352 7.8C11.992 6.248 13.168 5.472 14.88 5.472C15.856 5.472 16.72 5.776 17.472 6.384C18.224 6.992 18.6 7.936 18.6 9.216V14.184H20.04V16.512Z" fill="currentColor"></path><path d="M33.6714 16.512H29.1354V14.496C28.8314 15.12 28.3834 15.656 27.7914 16.104C27.1994 16.536 26.4154 16.752 25.4394 16.752C24.0154 16.752 22.8954 16.264 22.0794 15.288C21.2634 14.312 20.8554 12.984 20.8554 11.304C20.8554 9.688 21.2554 8.312 22.0554 7.176C22.8554 6.04 24.0634 5.472 25.6794 5.472C26.5594 5.472 27.2794 5.648 27.8394 6C28.3994 6.352 28.8314 6.8 29.1354 7.344V2.352H26.9754V0H32.2314V14.184H33.6714V16.512ZM29.1354 11.04V10.776C29.1354 9.88 28.8954 9.184 28.4154 8.688C27.9514 8.176 27.3674 7.92 26.6634 7.92C25.9754 7.92 25.3674 8.176 24.8394 8.688C24.3274 9.2 24.0714 10.008 24.0714 11.112C24.0714 12.152 24.3114 12.944 24.7914 13.488C25.2714 14.032 25.8394 14.304 26.4954 14.304C27.3114 14.304 27.9514 13.96 28.4154 13.272C28.8954 12.584 29.1354 11.84 29.1354 11.04Z" fill="currentColor"></path><path d="M47.9589 16.512H41.9829V14.184H43.4229V10.416C43.4229 9.488 43.2629 8.824 42.9429 8.424C42.6389 8.024 42.1829 7.824 41.5749 7.824C40.8389 7.824 40.2709 8.056 39.8709 8.52C39.4709 8.968 39.2629 9.56 39.2469 10.296V14.184H40.6869V16.512H34.7109V14.184H36.1509V8.04H34.5909V5.688H39.2469V7.344C39.9669 6.096 41.1269 5.472 42.7269 5.472C43.7509 5.472 44.6389 5.776 45.3909 6.384C46.1429 6.992 46.5189 7.936 46.5189 9.216V14.184H47.9589V16.512Z" fill="currentColor"></path></svg></a><p>Your blueprint for a better internet.</p><ul class="social-icons"><li><a href="https://mastodon.social/@mdn" target="_blank" rel="me noopener noreferrer"><span class="icon icon-mastodon"></span><span class="visually-hidden">MDN on Mastodon</span></a></li><li><a href="https://twitter.com/mozdevnet" target="_blank" rel="noopener noreferrer"><span class="icon icon-twitter-x"></span><span class="visually-hidden">MDN on X (formerly Twitter)</span></a></li><li><a href="https://github.com/mdn/" target="_blank" rel="noopener noreferrer"><span class="icon icon-github-mark-small"></span><span class="visually-hidden">MDN on GitHub</span></a></li><li><a href="/en-US/blog/rss.xml" target="_blank"><span class="icon icon-feed"></span><span class="visually-hidden">MDN Blog RSS Feed</span></a></li></ul></div><div class="page-footer-nav-col-1"><h2 class="footer-nav-heading">MDN</h2><ul class="footer-nav-list"><li class="footer-nav-item"><a href="/en-US/about">About</a></li><li class="footer-nav-item"><a href="/en-US/blog/">Blog</a></li><li class="footer-nav-item"><a href="https://www.mozilla.org/en-US/careers/listings/?team=ProdOps" target="_blank" rel="noopener noreferrer">Careers</a></li><li class="footer-nav-item"><a href="/en-US/advertising">Advertise with us</a></li></ul></div><div class="page-footer-nav-col-2"><h2 class="footer-nav-heading">Support</h2><ul class="footer-nav-list"><li class="footer-nav-item"><a class="footer-nav-link" href="https://support.mozilla.org/products/mdn-plus">Product help</a></li><li class="footer-nav-item"><a class="footer-nav-link" href="/en-US/docs/MDN/Community/Issues">Report an issue</a></li></ul></div><div class="page-footer-nav-col-3"><h2 class="footer-nav-heading">Our communities</h2><ul class="footer-nav-list"><li class="footer-nav-item"><a class="footer-nav-link" href="/en-US/community">MDN Community</a></li><li class="footer-nav-item"><a class="footer-nav-link" href="https://discourse.mozilla.org/c/mdn/236" target="_blank" rel="noopener noreferrer">MDN Forum</a></li><li class="footer-nav-item"><a class="footer-nav-link" href="/discord" target="_blank" rel="noopener noreferrer">MDN Chat</a></li></ul></div><div class="page-footer-nav-col-4"><h2 class="footer-nav-heading">Developers</h2><ul class="footer-nav-list"><li class="footer-nav-item"><a class="footer-nav-link" href="/en-US/docs/Web">Web Technologies</a></li><li class="footer-nav-item"><a class="footer-nav-link" href="/en-US/docs/Learn">Learn Web Development</a></li><li class="footer-nav-item"><a class="footer-nav-link" href="/en-US/plus">MDN Plus</a></li><li class="footer-nav-item"><a href="https://hacks.mozilla.org/" target="_blank" rel="noopener noreferrer">Hacks Blog</a></li></ul></div><div class="page-footer-moz"><a href="https://www.mozilla.org/" class="footer-moz-logo-link" target="_blank" rel="noopener noreferrer"><svg xmlns="http://www.w3.org/2000/svg" width="137" height="32" fill="none" viewBox="0 0 267.431 62.607"><path fill="currentColor" d="m13.913 23.056 5.33 25.356h2.195l5.33-25.356h14.267v38.976h-7.578V29.694h-2.194l-7.264 32.337h-7.343L9.418 29.694H7.223v32.337H-.354V23.056Zm47.137 9.123c9.12 0 14.423 5.385 14.423 15.214s-5.33 15.214-14.423 15.214c-9.12 0-14.423-5.385-14.423-15.214 0-9.855 5.304-15.214 14.423-15.214m0 24.363c4.285 0 6.428-2.196 6.428-7.032v-4.287c0-4.836-2.143-7.032-6.428-7.032s-6.428 2.196-6.428 7.032v4.287c0 4.836 2.143 7.032 6.428 7.032m18.473-.157 15.47-18.01h-15.26v-5.647h24.352v5.646L88.616 56.385h15.704v5.646H79.523Zm29.318-23.657h11.183V62.03h-7.578V38.375h-3.632v-5.646zm3.605-9.672h7.578v5.646h-7.578zm13.17 0h11.21v38.976h-7.578v-33.33h-3.632zm16.801 0H153.6v38.976h-7.577v-33.33h-3.632v-5.646zm29.03 9.123c4.442 0 7.394 2.143 8.231 5.881h2.194v-5.332h9.276v5.646h-3.632v18.011h3.632v5.646h-4.442c-3.135 0-4.834-1.699-4.834-4.836V56.7h-2.194c-.81 3.738-3.789 5.881-8.23 5.881-6.978 0-11.916-5.829-11.916-15.214 0-9.384 4.938-15.187 11.915-15.187m2.3 24.363c4.284 0 6.192-2.196 6.192-7.032v-4.287c0-4.836-1.908-7.032-6.193-7.032-4.18 0-6.193 2.196-6.193 7.032v4.287c0 4.836 2.012 7.032 6.193 7.032m48.34 5.489h-7.577V0h7.577zm6.585-29.643h32.165v-2.196l-21.295-7.634v-6.143l21.295-7.633V6.588h-25.345V0h32.165v12.522l-17.35 5.881V20.6l17.35 5.882v12.521h-38.985zm0-25.801h6.794v6.796h-6.794z"></path></svg></a><ul class="footer-moz-list"><li class="footer-moz-item"><a href="https://www.mozilla.org/privacy/websites/" class="footer-moz-link" target="_blank" rel="noopener noreferrer">Website Privacy Notice</a></li><li class="footer-moz-item"><a href="https://www.mozilla.org/privacy/websites/#cookies" class="footer-moz-link" target="_blank" rel="noopener noreferrer">Cookies</a></li><li class="footer-moz-item"><a href="https://www.mozilla.org/about/legal/terms/mozilla" class="footer-moz-link" target="_blank" rel="noopener noreferrer">Legal</a></li><li class="footer-moz-item"><a href="https://www.mozilla.org/about/governance/policies/participation/" class="footer-moz-link" target="_blank" rel="noopener noreferrer">Community Participation Guidelines</a></li></ul></div><div class="page-footer-legal"><p id="license" class="page-footer-legal-text">Visit<!-- --> <a href="https://www.mozilla.org" target="_blank" rel="noopener noreferrer">Mozilla Corporation’s</a> <!-- -->not-for-profit parent, the<!-- --> <a target="_blank" rel="noopener noreferrer" href="https://foundation.mozilla.org/">Mozilla Foundation</a>.<br/>Portions of this content are ©1998–<!-- -->2025<!-- --> by individual mozilla.org contributors. Content available under<!-- --> <a href="/en-US/docs/MDN/Writing_guidelines/Attrib_copyright_license">a Creative Commons license</a>.</p></div></div></footer></div><script type="application/json" id="hydration">{"url":"/en-US/docs/Learn_web_development/Core/Frameworks_libraries/React_accessibility","doc":{"body":[{"type":"prose","value":{"id":null,"title":null,"isH3":false,"content":"<ul class=\"prev-next\"><li><a class=\"button secondary\" href=\"/en-US/docs/Learn_web_development/Core/Frameworks_libraries/React_interactivity_filtering_conditional_rendering\"><span class=\"button-wrap\"> Previous </span></a></li><li><a class=\"button secondary\" href=\"/en-US/docs/Learn_web_development/Core/Frameworks_libraries\"><span class=\"button-wrap\"> Overview: JavaScript frameworks and libraries</span></a></li><li><a class=\"button secondary\" href=\"/en-US/docs/Learn_web_development/Core/Frameworks_libraries/React_resources\"><span class=\"button-wrap\"> Next </span></a></li></ul>\n<p>In our final tutorial article, we'll focus on (pun intended) accessibility, including focus management in React, which can improve usability and reduce confusion for both keyboard-only and screen reader users.</p>\n<figure class=\"table-container\"><table>\n <tbody>\n <tr>\n <th scope=\"row\">Prerequisites:</th>\n <td>\n Familiarity with the core <a href=\"/en-US/docs/Learn_web_development/Core/Structuring_content\">HTML</a>,\n <a href=\"/en-US/docs/Learn_web_development/Core/Styling_basics\">CSS</a>, and\n <a href=\"/en-US/docs/Learn_web_development/Core/Scripting\">JavaScript</a> languages, and the <a href=\"/en-US/docs/Learn_web_development/Getting_started/Environment_setup/Command_line\">terminal/command line</a>.\n </td>\n </tr>\n <tr>\n <th scope=\"row\">Learning outcomes:</th>\n <td>Implementing keyboard accessibility in React.</td>\n </tr>\n </tbody>\n</table></figure>"}},{"type":"prose","value":{"id":"including_keyboard_users","title":"Including keyboard users","isH3":false,"content":"<p>At this point, we've implemented all the features we set out to implement. Users can add a new task, check and uncheck tasks, delete tasks, or edit task names. Also, they can filter their task list by all, active, or completed tasks.</p>\n<p>Or, at least, they can do all of these things with a mouse. Unfortunately, these features are not very accessible to keyboard-only users. Let's explore this now.</p>"}},{"type":"prose","value":{"id":"exploring_the_keyboard_usability_problem","title":"Exploring the keyboard usability problem","isH3":false,"content":"<p>Start by clicking on the input at the top of our app, as if you're going to add a new task. You'll see a thick, dashed outline around that input. This outline is your visual indicator that the browser is currently focused on this element. Press the <kbd>Tab</kbd> key, and you will see the outline appear around the \"Add\" button beneath the input. This shows you that the browser's focus has moved.</p>\n<p>Press <kbd>Tab</kbd> a few more times, and you will see this dashed focus indicator move between each of the filter buttons. Keep going until the focus indicator is around the first \"Edit\" button. Press <kbd>Enter</kbd>.</p>\n<p>The <code><Todo /></code> component will switch templates, as we designed, and you'll see a form that lets us edit the name of the task.</p>\n<p>But where did our focus indicator go?</p>\n<p>When we switch between templates in our <code><Todo /></code> component, we completely remove the elements from the old template and replace them with the elements from the new template. That means the element that we were focused on no longer exists, so there's no visual cue as to where the browser's focus is. This could confuse a wide variety of users — particularly users who rely on the keyboard, or users who use assistive technology.</p>\n<p>To improve the experience for keyboard and assistive technology users, we should manage the browser's focus ourselves.</p>"}},{"type":"prose","value":{"id":"aside_a_note_on_our_focus_indicator","title":"Aside: a note on our focus indicator","isH3":true,"content":"<p>If you click the \"All\", \"Active\", or \"Completed\" filter buttons with your mouse, you <em>won't</em> see a visible focus indicator, but you will do if you move between them with the <kbd>Tab</kbd> key on your keyboard. Don't worry — your code isn't broken!</p>\n<p>Our CSS file uses the <a href=\"/en-US/docs/Web/CSS/:focus-visible\"><code>:focus-visible</code></a> pseudo-class to provide custom styling for the focus indicator, and the browser uses a set of internal rules to determine when to show it to the user. Generally, the browser <em>will</em> show a focus indicator in response to keyboard input, and <em>might</em> show it in response to mouse input. <code><button></code> elements <em>don't</em> show a focus indicator in response to mouse input, while <code><input></code> elements <em>do</em>.</p>\n<p>The behavior of <code>:focus-visible</code> is more selective than the older <a href=\"/en-US/docs/Web/CSS/:focus\"><code>:focus</code></a> pseudo-class, with which you might be more familiar. <code>:focus</code> shows a focus indicator in many more situations, and you can use it instead of or in combination with <code>:focus-visible</code> if you prefer.</p>"}},{"type":"prose","value":{"id":"focusing_between_templates","title":"Focusing between templates","isH3":false,"content":"<p>When a user changes the <code><Todo /></code> template from viewing to editing, we should focus on the <code><input></code> used to rename it; when they change back from editing to viewing, we should move focus back to the \"Edit\" button.</p>"}},{"type":"prose","value":{"id":"targeting_our_elements","title":"Targeting our elements","isH3":true,"content":"<p>Up to this point, we've been writing JSX components and letting React build the resulting DOM behind the scenes. Most of the time, we don't need to target specific elements in the DOM because we can use React's state and props to control what gets rendered. To manage focus, however, we <em>do</em> need to be able to target specific DOM elements.</p>\n<p>This is where the <code>useRef()</code> hook comes in.</p>\n<p>First, change the <code>import</code> statement at the top of <code>Todo.jsx</code> so that it includes <code>useRef</code>:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">jsx</span></div><pre class=\"brush: jsx notranslate\"><code>import { useRef, useState } from \"react\";\n</code></pre></div>\n<p><code>useRef()</code> creates an object with a single property: <code>current</code>. Refs can store any values we want them to, and we can look up those values later. We can even store references to DOM elements, which is exactly what we're going to do here.</p>\n<p>Next, create two new constants beneath the <code>useState()</code> hooks in your <code>Todo()</code> function. Each should be a ref – one for the \"Edit\" button in the view template and one for the edit field in the editing template.</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">jsx</span></div><pre class=\"brush: jsx notranslate\"><code>const editFieldRef = useRef(null);\nconst editButtonRef = useRef(null);\n</code></pre></div>\n<p>These refs have a default value of <code>null</code> to make it clear that they'll be empty until they're attached to their DOM elements. To attach them to their elements, we'll add the special <code>ref</code> attribute to each element's JSX, and set the values of those attributes to the appropriately named <code>ref</code> objects.</p>\n<p>Update the <code><input></code> in your editing template so that it reads like this:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">jsx</span></div><pre class=\"brush: jsx notranslate\"><code><input\n id={props.id}\n className=\"todo-text\"\n type=\"text\"\n value={newName}\n onChange={handleChange}\n ref={editFieldRef}\n/>\n</code></pre></div>\n<p>Update the \"Edit\" button in your view template so that it reads like this:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">jsx</span></div><pre class=\"brush: jsx notranslate\"><code><button\n type=\"button\"\n className=\"btn\"\n onClick={() => setEditing(true)}\n ref={editButtonRef}>\n Edit <span className=\"visually-hidden\">{props.name}</span>\n</button>\n</code></pre></div>\n<p>Doing this will populate our <code>editFieldRef</code> and <code>editButtonRef</code> with references to the DOM elements they're attached to, but <em>only</em> after React has rendered the component. Test that out for yourself: add the following line somewhere in the body of your <code>Todo()</code> function, below where <code>editButtonRef</code> is initialized:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">jsx</span></div><pre class=\"brush: jsx notranslate\"><code>console.log(editButtonRef.current);\n</code></pre></div>\n<p>You'll see that the value of <code>editButtonRef.current</code> is <code>null</code> when the component first renders, but if you click an \"Edit\" button, it will log the <code><button></code> element to the console. This is because the ref is populated only after the component renders, and clicking the \"Edit\" button causes the component to re-render. Be sure to delete this log before moving on.</p>\n<div class=\"notecard note\">\n<p><strong>Note:</strong>\nYour logs will appear 6 times because we have 3 instances of <code><Todo /></code> in our app and React renders our components twice in development.</p>\n</div>\n<p>We're getting closer! To take advantage of our newly referenced elements, we need to use another React hook: <code>useEffect()</code>.</p>"}},{"type":"prose","value":{"id":"implementing_useeffect","title":"Implementing <code>useEffect()</code>","isH3":true,"content":"<p><a href=\"https://react.dev/reference/react/useEffect\" class=\"external\" target=\"_blank\"><code>useEffect()</code></a> is so named because it runs any side-effects that we'd like to add to the render process but which can't be run inside the main function body. <code>useEffect()</code> runs right after a component renders, meaning the DOM elements we referenced in the previous section will be available for us to use.</p>\n<p>Change the import statement of <code>Todo.jsx</code> again to add <code>useEffect</code>:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">jsx</span></div><pre class=\"brush: jsx notranslate\"><code>import { useEffect, useRef, useState } from \"react\";\n</code></pre></div>\n<p><code>useEffect()</code> takes a function as an argument; this function is executed <em>after</em> the component renders. To demonstrate this, put the following <code>useEffect()</code> call just above the <code>return</code> statement in the body of <code>Todo()</code>, and pass a function into it that logs the words \"side effect\" to your console:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">jsx</span></div><pre class=\"brush: jsx notranslate\"><code>useEffect(() => {\n console.log(\"side effect\");\n});\n</code></pre></div>\n<p>To illustrate the difference between the main render process and code run inside <code>useEffect()</code>, add another log – put this one below the previous addition:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">jsx</span></div><pre class=\"brush: jsx notranslate\"><code>console.log(\"main render\");\n</code></pre></div>\n<p>Now, open the app in your browser. You should see both messages in your console, with each one repeating multiple times. Note how \"main render\" logged first, and \"side effect\" logged second, even though the \"side effect\" log appears first in the code.</p>\n<pre class=\"brush: plain notranslate\">main render Todo.jsx\nside effect Todo.jsx\n</pre>\n<p>Again, the logs are ordered this way because code inside <code>useEffect()</code> runs <em>after</em> the component renders. This takes some getting used to, just keep it in mind as you move forward. For now, delete <code>console.log(\"main render\")</code> and we'll move on to implementing our focus management.</p>"}},{"type":"prose","value":{"id":"focusing_on_our_editing_field","title":"Focusing on our editing field","isH3":true,"content":"<p>Now that we know our <code>useEffect()</code> hook works, we can manage focus with it. As a reminder, we want to focus on the editing field when we switch to the editing template.</p>\n<p>Update your existing <code>useEffect()</code> hook so that it reads like this:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">jsx</span></div><pre class=\"brush: jsx notranslate\"><code>useEffect(() => {\n if (isEditing) {\n editFieldRef.current.focus();\n }\n}, [isEditing]);\n</code></pre></div>\n<p>These changes make it so that, if <code>isEditing</code> is true, React reads the current value of the <code>editFieldRef</code> and moves browser focus to it. We also pass an array into <code>useEffect()</code> as a second argument. This array is a list of values <code>useEffect()</code> should depend on. With these values included, <code>useEffect()</code> will only run when one of those values changes. We only want to change focus when the value of <code>isEditing</code> changes.</p>\n<p>Try it now: use the <kbd>Tab</kbd> key to navigate to one of the \"Edit\" buttons, then press <kbd>Enter</kbd>. You should see the <code><Todo /></code> component switch to its editing template, and the browser focus indicator should appear around the <code><input></code> element!</p>"}},{"type":"prose","value":{"id":"moving_focus_back_to_the_edit_button","title":"Moving focus back to the edit button","isH3":true,"content":"<p>At first glance, getting React to move focus back to our \"Edit\" button when the edit is saved or cancelled appears deceptively easy. Surely we could add a condition to our <code>useEffect</code> to focus on the edit button if <code>isEditing</code> is <code>false</code>? Let's try it now — update your <code>useEffect()</code> call like so:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">jsx</span></div><pre class=\"brush: jsx notranslate\"><code>useEffect(() => {\n if (isEditing) {\n editFieldRef.current.focus();\n } else {\n editButtonRef.current.focus();\n }\n}, [isEditing]);\n</code></pre></div>\n<p>This kind of works. If you use your keyboard to trigger the \"Edit\" button (remember: <kbd>Tab</kbd> to it and press <kbd>Enter</kbd>), you'll see that your focus moves between the Edit <code><input></code> and \"Edit\" button as you start and end an edit. However, you may have noticed a new problem — the \"Edit\" button in the final <code><Todo /></code> component is focused immediately on page load before we even interact with the app!</p>\n<p>Our <code>useEffect()</code> hook is behaving exactly as we designed it: it runs as soon as the component renders, sees that <code>isEditing</code> is <code>false</code>, and focuses the \"Edit\" button. There are three instances of <code><Todo /></code>, and focus is given to the \"Edit\" button of the one that renders last.</p>\n<p>We need to refactor our approach so that focus changes only when <code>isEditing</code> changes from one value to another.</p>"}},{"type":"prose","value":{"id":"more_robust_focus_management","title":"More robust focus management","isH3":false,"content":"<p>To meet our refined criteria, we need to know not just the value of <code>isEditing</code>, but also <em>when that value has changed</em>. To do that, we need to be able to read the previous value of the <code>isEditing</code> constant. Using pseudocode, our logic should be something like this:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">jsx</span></div><pre class=\"brush: jsx notranslate\"><code>if (wasNotEditingBefore && isEditingNow) {\n focusOnEditField();\n} else if (wasEditingBefore && isNotEditingNow) {\n focusOnEditButton();\n}\n</code></pre></div>\n<p>The React team has discussed <a href=\"https://legacy.reactjs.org/docs/hooks-faq.html#how-to-get-the-previous-props-or-state\" class=\"external\" target=\"_blank\">ways to get a component's previous state</a>, and provided an example hook we can use for the job.</p>"}},{"type":"prose","value":{"id":"enter_useprevious","title":"Enter <code>usePrevious()</code>","isH3":true,"content":"<p>Paste the following code near the top of <code>Todo.jsx</code>, above your <code>Todo()</code> function.</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">jsx</span></div><pre class=\"brush: jsx notranslate\"><code>function usePrevious(value) {\n const ref = useRef();\n useEffect(() => {\n ref.current = value;\n });\n return ref.current;\n}\n</code></pre></div>\n<p><code>usePrevious()</code> is a <em>custom hook</em> that tracks a value across renders. It:</p>\n<ol>\n<li>Uses the <code>useRef()</code> hook to create an empty <code>ref</code>.</li>\n<li>Returns the <code>ref</code>'s <code>current</code> value to the component that called it.</li>\n<li>Calls <code>useEffect()</code> and updates the value stored in <code>ref.current</code> after each rendering of the calling component.</li>\n</ol>\n<p>The behavior of <code>useEffect()</code> is key to this functionality. Because <code>ref.current</code> is updated inside a <code>useEffect()</code> call, it's always one step behind whatever value is in the component's main render cycle – hence the name <code>usePrevious()</code>.</p>"}},{"type":"prose","value":{"id":"using_useprevious","title":"Using <code>usePrevious()</code>","isH3":true,"content":"<p>Now we can define a <code>wasEditing</code> constant to track the previous value of <code>isEditing</code>; this is achieved by calling <code>usePrevious</code> with <code>isEditing</code> as an argument. Add the following inside <code>Todo()</code>, below the <code>useRef</code> lines:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">jsx</span></div><pre class=\"brush: jsx notranslate\"><code>const wasEditing = usePrevious(isEditing);\n</code></pre></div>\n<p>You can see how <code>usePrevious()</code> behaves by adding a console log beneath this line:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">jsx</span></div><pre class=\"brush: jsx notranslate\"><code>console.log(wasEditing);\n</code></pre></div>\n<p>In this log, the <code>current</code> value of <code>wasEditing</code> will always be the previous value of <code>isEditing</code>. Click on the \"Edit\" and \"Cancel\" button a few times to watch it change, then delete this log when you're ready to move on.</p>\n<p>With this <code>wasEditing</code> constant, we can update our <code>useEffect()</code> hook to implement the pseudocode we discussed before:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">jsx</span></div><pre class=\"brush: jsx notranslate\"><code>useEffect(() => {\n if (!wasEditing && isEditing) {\n editFieldRef.current.focus();\n } else if (wasEditing && !isEditing) {\n editButtonRef.current.focus();\n }\n}, [wasEditing, isEditing]);\n</code></pre></div>\n<p>Note that the logic of <code>useEffect()</code> now depends on <code>wasEditing</code>, so we provide it in the array of dependencies.</p>\n<p>Try using your keyboard to activate the \"Edit\" and \"Cancel\" buttons in the <code><Todo /></code> component; you'll see the browser focus indicator move appropriately, without the problem we discussed at the start of this section.</p>"}},{"type":"prose","value":{"id":"focusing_when_the_user_deletes_a_task","title":"Focusing when the user deletes a task","isH3":false,"content":"<p>There's one last keyboard experience gap: when a user deletes a task from the list, the focus vanishes. We're going to follow a pattern similar to our previous changes: we'll make a new ref, and utilize our <code>usePrevious()</code> hook, so that we can focus on the list heading whenever a user deletes a task.</p>"}},{"type":"prose","value":{"id":"why_the_list_heading","title":"Why the list heading?","isH3":true,"content":"<p>Sometimes, the place we want to send our focus to is obvious: when we toggled our <code><Todo /></code> templates, we had an origin point to \"go back\" to — the \"Edit\" button. In this case however, since we're completely removing elements from the DOM, we have no place to go back to. The next best thing is an intuitive location somewhere nearby. The list heading is our best choice because it's close to the list item the user will delete, and focusing on it will tell the user how many tasks are left.</p>"}},{"type":"prose","value":{"id":"creating_our_ref","title":"Creating our ref","isH3":true,"content":"<p>Import the <code>useRef()</code> and <code>useEffect()</code> hooks into <code>App.jsx</code> — you'll need them both below:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">jsx</span></div><pre class=\"brush: jsx notranslate\"><code>import { useState, useRef, useEffect } from \"react\";\n</code></pre></div>\n<p>Next, declare a new ref inside the <code>App()</code> function, just above the <code>return</code> statement:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">jsx</span></div><pre class=\"brush: jsx notranslate\"><code>const listHeadingRef = useRef(null);\n</code></pre></div>"}},{"type":"prose","value":{"id":"prepare_the_heading","title":"Prepare the heading","isH3":true,"content":"<p>Heading elements like our <code><h2></code> are not usually focusable. This isn't a problem — we can make any element programmatically focusable by adding the attribute <a href=\"/en-US/docs/Web/HTML/Global_attributes/tabindex\"><code>tabindex=\"-1\"</code></a> to it. This means <em>only focusable with JavaScript</em>. You can't press <kbd>Tab</kbd> to focus on an element with a tabindex of <code>-1</code> the same way you could do with a <a href=\"/en-US/docs/Web/HTML/Element/button\"><code><button></code></a> or <a href=\"/en-US/docs/Web/HTML/Element/a\"><code><a></code></a> element (this can be done using <code>tabindex=\"0\"</code>, but that's not appropriate in this case).</p>\n<p>Let's add the <code>tabindex</code> attribute — written as <code>tabIndex</code> in JSX — to the heading above our list of tasks, along with our <code>listHeadingRef</code>:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">jsx</span></div><pre class=\"brush: jsx notranslate\"><code><h2 id=\"list-heading\" tabIndex=\"-1\" ref={listHeadingRef}>\n {headingText}\n</h2>\n</code></pre></div>\n<div class=\"notecard note\">\n<p><strong>Note:</strong>\nThe <code>tabindex</code> attribute is excellent for accessibility edge cases, but you should take <strong>great care</strong> not to overuse it. Only apply a <code>tabindex</code> to an element when you're sure that making it focusable will benefit your user somehow. In most cases, you should utilize elements that can naturally take focus, such as buttons, anchors, and inputs. Irresponsible usage of <code>tabindex</code> could have a profoundly negative impact on keyboard and screen reader users!</p>\n</div>"}},{"type":"prose","value":{"id":"getting_previous_state","title":"Getting previous state","isH3":true,"content":"<p>We want to focus on the element associated with our ref (via the <code>ref</code> attribute) only when our user deletes a task from their list. That's going to require the <code>usePrevious()</code> hook we used earlier on. Add it to the top of your <code>App.jsx</code> file, just below the imports:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">jsx</span></div><pre class=\"brush: jsx notranslate\"><code>function usePrevious(value) {\n const ref = useRef();\n useEffect(() => {\n ref.current = value;\n });\n return ref.current;\n}\n</code></pre></div>\n<p>Now add the following, above the <code>return</code> statement inside the <code>App()</code> function:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">jsx</span></div><pre class=\"brush: jsx notranslate\"><code>const prevTaskLength = usePrevious(tasks.length);\n</code></pre></div>\n<p>Here we are invoking <code>usePrevious()</code> to track the previous length of the tasks array.</p>\n<div class=\"notecard note\">\n<p><strong>Note:</strong>\nSince we're now utilizing <code>usePrevious()</code> in two files, it might be more efficient to move the <code>usePrevious()</code> function into its own file, export it from that file, and import it where you need it. Try doing this as an exercise once you've got to the end.</p>\n</div>"}},{"type":"prose","value":{"id":"using_useeffect_to_control_our_heading_focus","title":"Using <code>useEffect()</code> to control our heading focus","isH3":true,"content":"<p>Now that we've stored how many tasks we previously had, we can set up a <code>useEffect()</code> hook to run when our number of tasks changes, which will focus the heading if the number of tasks we have now is less than it previously was — that is, we deleted a task!</p>\n<p>Add the following into the body of your <code>App()</code> function, just below your previous additions:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">jsx</span></div><pre class=\"brush: jsx notranslate\"><code>useEffect(() => {\n if (tasks.length < prevTaskLength) {\n listHeadingRef.current.focus();\n }\n}, [tasks.length, prevTaskLength]);\n</code></pre></div>\n<p>We only try to focus on our list heading if we have fewer tasks now than we did before. The dependencies passed into this hook ensure it will only try to re-run when either of those values (the number of current tasks, or the number of previous tasks) changes.</p>\n<p>Now, when you use your keyboard to delete a task in your browser, you will see our dashed focus outline appear around the heading above the list.</p>"}},{"type":"prose","value":{"id":"finished!","title":"Finished!","isH3":false,"content":"<p>You've just finished building a React app from the ground up! Congratulations! The skills you've learned here will be a great foundation to build on as you continue working with React.</p>\n<p>Most of the time, you can be an effective contributor to a React project even if all you do is think carefully about components and their state and props. Remember to always write the best HTML you can.</p>\n<p><code>useRef()</code> and <code>useEffect()</code> are somewhat advanced features, and you should be proud of yourself for using them! Look out for opportunities to practice them more, because doing so will allow you to create inclusive experiences for users. Remember: our app would have been inaccessible to keyboard users without them!</p>\n<div class=\"notecard note\">\n<p><strong>Note:</strong>\nIf you need to check your code against our version, you can find a finished version of the sample React app code in our <a href=\"https://github.com/mdn/todo-react\" class=\"external\" target=\"_blank\">todo-react repository</a>. For a running live version, see <a href=\"https://mdn.github.io/todo-react/\" class=\"external\" target=\"_blank\">https://mdn.github.io/todo-react/</a>.</p>\n</div>\n<p>In the very last article we'll present you with a list of React resources that you can use to go further in your learning.</p>\n<ul class=\"prev-next\"><li><a class=\"button secondary\" href=\"/en-US/docs/Learn_web_development/Core/Frameworks_libraries/React_interactivity_filtering_conditional_rendering\"><span class=\"button-wrap\"> Previous </span></a></li><li><a class=\"button secondary\" href=\"/en-US/docs/Learn_web_development/Core/Frameworks_libraries\"><span class=\"button-wrap\"> Overview: JavaScript frameworks and libraries</span></a></li><li><a class=\"button secondary\" href=\"/en-US/docs/Learn_web_development/Core/Frameworks_libraries/React_resources\"><span class=\"button-wrap\"> Next </span></a></li></ul>"}}],"isActive":true,"isMarkdown":true,"isTranslated":false,"locale":"en-US","mdn_url":"/en-US/docs/Learn_web_development/Core/Frameworks_libraries/React_accessibility","modified":"2024-12-19T15:37:45.000Z","native":"English (US)","noIndexing":false,"other_translations":[{"locale":"de","title":"Barrierefreiheit in React","native":"Deutsch"},{"locale":"ja","title":"React でのアクセシビリティ","native":"日本語"},{"locale":"ko","title":"Accessibility in React","native":"한국어"}],"pageTitle":"Accessibility in React - Learn web development | MDN","parents":[{"uri":"/en-US/docs/Learn_web_development","title":"Learn"},{"uri":"/en-US/docs/Learn_web_development/Core","title":"Core learning modules"},{"uri":"/en-US/docs/Learn_web_development/Core/Frameworks_libraries","title":"JavaScript frameworks and libraries"},{"uri":"/en-US/docs/Learn_web_development/Core/Frameworks_libraries/React_accessibility","title":"Accessibility in React"}],"popularity":null,"short_title":"Accessibility in React","sidebarHTML":"<ol><li class=\"section\"><a href=\"/en-US/docs/Learn_web_development/Getting_started\">Getting started modules</a></li><li class=\"toggle\"><details><summary><a href=\"/en-US/docs/Learn_web_development/Getting_started/Environment_setup\">Environment setup</a></summary><ol><li><a href=\"/en-US/docs/Learn_web_development/Getting_started/Environment_setup/Installing_software\">Installing basic software</a></li><li><a href=\"/en-US/docs/Learn_web_development/Getting_started/Environment_setup/Browsing_the_web\">Browsing the web</a></li><li><a href=\"/en-US/docs/Learn_web_development/Getting_started/Environment_setup/Code_editors\">Code editors</a></li><li><a href=\"/en-US/docs/Learn_web_development/Getting_started/Environment_setup/Dealing_with_files\">Dealing with files</a></li><li><a href=\"/en-US/docs/Learn_web_development/Getting_started/Environment_setup/Command_line\">Command line crash course</a></li></ol></details></li><li class=\"toggle\"><details><summary><a href=\"/en-US/docs/Learn_web_development/Getting_started/Your_first_website\">Your first website</a></summary><ol><li><a href=\"/en-US/docs/Learn_web_development/Getting_started/Your_first_website/What_will_your_website_look_like\">What will your website look like?</a></li><li><a href=\"/en-US/docs/Learn_web_development/Getting_started/Your_first_website/Creating_the_content\">HTML: Creating the content</a></li><li><a href=\"/en-US/docs/Learn_web_development/Getting_started/Your_first_website/Styling_the_content\">CSS: Styling the content</a></li><li><a href=\"/en-US/docs/Learn_web_development/Getting_started/Your_first_website/Adding_interactivity\">JavaScript: Adding interactivity</a></li><li><a href=\"/en-US/docs/Learn_web_development/Getting_started/Your_first_website/Publishing_your_website\">Publishing your website</a></li></ol></details></li><li class=\"toggle\"><details><summary><a href=\"/en-US/docs/Learn_web_development/Getting_started/Web_standards\">Web standards</a></summary><ol><li><a href=\"/en-US/docs/Learn_web_development/Getting_started/Web_standards/How_the_web_works\">How the web works</a></li><li><a href=\"/en-US/docs/Learn_web_development/Getting_started/Web_standards/The_web_standards_model\">The web standards model</a></li><li><a href=\"/en-US/docs/Learn_web_development/Getting_started/Web_standards/How_browsers_load_websites\">How browsers load websites</a></li></ol></details></li><li class=\"toggle\"><details><summary><a href=\"/en-US/docs/Learn_web_development/Getting_started/Soft_skills\">Soft skills</a></summary><ol><li><a href=\"/en-US/docs/Learn_web_development/Getting_started/Soft_skills/Research_and_learning\">Research and learning</a></li><li><a href=\"/en-US/docs/Learn_web_development/Getting_started/Soft_skills/Collaboration_and_teamwork\">Collaboration and teamwork</a></li><li><a href=\"/en-US/docs/Learn_web_development/Getting_started/Soft_skills/Workflows_and_processes\">Workflows and processes</a></li><li><a href=\"/en-US/docs/Learn_web_development/Getting_started/Soft_skills/Job_interviews\">Succeeding in job interviews</a></li></ol></details></li><li class=\"section\"><a href=\"/en-US/docs/Learn_web_development/Core\">Core modules</a></li><li class=\"toggle\"><details><summary><a href=\"/en-US/docs/Learn_web_development/Core/Structuring_content\">Structuring content with HTML</a></summary><ol><li><a href=\"/en-US/docs/Learn_web_development/Core/Structuring_content/Basic_HTML_syntax\">Basic HTML syntax</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Structuring_content/Webpage_metadata\">What's in the head? Webpage metadata</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Structuring_content/Headings_and_paragraphs\">Headings and paragraphs in HTML</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Structuring_content/Emphasis_and_importance\">Emphasis and importance</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Structuring_content/Lists\">Lists</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Structuring_content/Structuring_documents\">Structuring documents</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Structuring_content/Advanced_text_features\">Advanced text features</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Structuring_content/Creating_links\">Creating links</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Structuring_content/Marking_up_a_letter\">Challenge: Marking up a letter</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Structuring_content/Structuring_a_page_of_content\">Challenge: Structuring a page of content</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Structuring_content/HTML_images\">HTML images</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Structuring_content/HTML_video_and_audio\">HTML video and audio</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Structuring_content/Mozilla_splash_page\">Challenge: Mozilla splash page</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Structuring_content/HTML_table_basics\">HTML table basics</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Structuring_content/Table_accessibility\">HTML table accessibility</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Structuring_content/Planet_data_table\">Challenge: Structuring a planet data table</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Structuring_content/HTML_forms\">Forms and buttons in HTML</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Structuring_content/Debugging_HTML\">Debugging HTML</a></li></ol></details></li><li class=\"toggle\"><details><summary><a href=\"/en-US/docs/Learn_web_development/Core/Styling_basics\">CSS styling basics</a></summary><ol><li><a href=\"/en-US/docs/Learn_web_development/Core/Styling_basics/What_is_CSS\">What is CSS?</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Styling_basics/Getting_started\">Getting started with CSS</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Styling_basics/Styling_a_bio_page\">Challenge: Styling a biography page</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Styling_basics/Basic_selectors\">Basic CSS selectors</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Styling_basics/Attribute_selectors\">Attribute selectors</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Styling_basics/Pseudo_classes_and_elements\">Pseudo-classes and pseudo-elements</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Styling_basics/Combinators\">Combinators</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Styling_basics/Box_model\">The box model</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Styling_basics/Handling_conflicts\">Handling conflicts</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Styling_basics/Values_and_units\">CSS values and units</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Styling_basics/Sizing\">Sizing items in CSS</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Styling_basics/Backgrounds_and_borders\">Backgrounds and borders</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Styling_basics/Overflow\">Overflowing content</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Styling_basics/Images_media_forms\">Images, media, and form elements</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Styling_basics/Tables\">Styling tables</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Styling_basics/Debugging_CSS\">Debugging CSS</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Styling_basics/Fundamental_CSS_comprehension\">Challenge: Fundamental CSS comprehension</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Styling_basics/Fancy_letterheaded_paper\">Challenge: Creating fancy letterheaded paper</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Styling_basics/Cool-looking_box\">Challenge: A cool-looking box</a></li></ol></details></li><li class=\"toggle\"><details><summary><a href=\"/en-US/docs/Learn_web_development/Core/Text_styling\">CSS text styling</a></summary><ol><li><a href=\"/en-US/docs/Learn_web_development/Core/Text_styling/Fundamentals\">Fundamental text and font styling</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Text_styling/Styling_lists\">Styling lists</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Text_styling/Styling_links\">Styling links</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Text_styling/Web_fonts\">Web fonts</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Text_styling/Typesetting_a_homepage\">Challenge: Typesetting a community school homepage</a></li></ol></details></li><li class=\"toggle\"><details><summary><a href=\"/en-US/docs/Learn_web_development/Core/CSS_layout\">CSS layout</a></summary><ol><li><a href=\"/en-US/docs/Learn_web_development/Core/CSS_layout/Introduction\">Introduction to CSS layout</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/CSS_layout/Floats\">Floats</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/CSS_layout/Positioning\">Positioning</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/CSS_layout/Flexbox\">Flexbox</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/CSS_layout/Grids\">CSS grid layout</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/CSS_layout/Responsive_Design\">Responsive design</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/CSS_layout/Media_queries\">Media query fundamentals</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/CSS_layout/Fundamental_Layout_Comprehension\">Challenge: Fundamental layout comprehension</a></li></ol></details></li><li class=\"toggle\"><details><summary><a href=\"/en-US/docs/Learn_web_development/Core/Scripting\">Dynamic scripting with JavaScript</a></summary><ol><li><a href=\"/en-US/docs/Learn_web_development/Core/Scripting/What_is_JavaScript\">What is JavaScript?</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Scripting/A_first_splash\">A first splash into JavaScript</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Scripting/What_went_wrong\">What went wrong? Troubleshooting JavaScript</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Scripting/Variables\">Storing the information you need — Variables</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Scripting/Math\">Basic math in JavaScript — numbers and operators</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Scripting/Strings\">Handling text — strings in JavaScript</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Scripting/Useful_string_methods\">Useful string methods</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Scripting/Arrays\">Arrays</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Scripting/Silly_story_generator\">Challenge: Silly story generator</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Scripting/Conditionals\">Making decisions in your code — conditionals</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Scripting/Loops\">Looping code</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Scripting/Functions\">Functions — reusable blocks of code</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Scripting/Build_your_own_function\">Build your own function</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Scripting/Return_values\">Function return values</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Scripting/Events\">Introduction to events</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Scripting/Event_bubbling\">Event bubbling</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Scripting/Image_gallery\">Challenge: Image gallery</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Scripting/Object_basics\">JavaScript object basics</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Scripting/DOM_scripting\">DOM scripting introduction</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Scripting/Network_requests\">Making network requests with JavaScript</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Scripting/JSON\">Working with JSON</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Scripting/Debugging_JavaScript\">Debugging JavaScript and handling errors</a></li></ol></details></li><li class=\"toggle\"><details open=\"\"><summary><a href=\"/en-US/docs/Learn_web_development/Core/Frameworks_libraries\">JavaScript frameworks and libraries</a></summary><ol><li><a href=\"/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Introduction\">Introduction to client-side frameworks</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Main_features\">Framework main features</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Frameworks_libraries/React_getting_started\">Getting started with React</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Frameworks_libraries/React_todo_list_beginning\">Beginning our React todo list</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Frameworks_libraries/React_components\">Componentizing our React app</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Frameworks_libraries/React_interactivity_events_state\">React interactivity: Events and state</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Frameworks_libraries/React_interactivity_filtering_conditional_rendering\">React interactivity: Editing, filtering, conditional rendering</a></li><li><em><a href=\"/en-US/docs/Learn_web_development/Core/Frameworks_libraries/React_accessibility\" aria-current=\"page\">Accessibility in React</a></em></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Frameworks_libraries/React_resources\">React resources</a></li></ol></details></li><li class=\"toggle\"><details><summary><a href=\"/en-US/docs/Learn_web_development/Core/Accessibility\">Accessibility</a></summary><ol><li><a href=\"/en-US/docs/Learn_web_development/Core/Accessibility/What_is_accessibility\">What is accessibility?</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Accessibility/Tooling\">Accessibility tooling and assistive technology</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Accessibility/HTML\">HTML: A good basis for accessibility</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Accessibility/CSS_and_JavaScript\">CSS and JavaScript accessibility best practices</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Accessibility/WAI-ARIA_basics\">WAI-ARIA basics</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Accessibility/Multimedia\">Accessible multimedia</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Accessibility/Mobile\">Mobile accessibility</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Accessibility/Accessibility_troubleshooting\">Challenge: Accessibility troubleshooting</a></li></ol></details></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Design_for_developers\">Design for developers</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Version_control\">Version control</a></li><li class=\"section\"><a href=\"/en-US/docs/Learn_web_development/Extensions\">Extension modules</a></li><li class=\"toggle\"><details><summary><a href=\"/en-US/docs/Learn_web_development/Extensions/Advanced_JavaScript_objects\">Advanced JavaScript objects</a></summary><ol><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Advanced_JavaScript_objects/Object_prototypes\">Object prototypes</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Advanced_JavaScript_objects/Object-oriented_programming\">Object-oriented programming</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Advanced_JavaScript_objects/Classes_in_JavaScript\">Classes in JavaScript</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Advanced_JavaScript_objects/Object_building_practice\">Object building practice</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Advanced_JavaScript_objects/Adding_bouncing_balls_features\">Challenge: Adding features to our bouncing balls demo</a></li></ol></details></li><li class=\"toggle\"><details><summary><a href=\"/en-US/docs/Learn_web_development/Extensions/Client-side_APIs\">Client-side web APIs</a></summary><ol><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Client-side_APIs/Introduction\">Introduction to web APIs</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Client-side_APIs/Video_and_audio_APIs\">Video and Audio APIs</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Client-side_APIs/Drawing_graphics\">Drawing graphics</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Client-side_APIs/Client-side_storage\">Client-side storage</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Client-side_APIs/Third_party_APIs\">Third-party APIs</a></li></ol></details></li><li class=\"toggle\"><details><summary><a href=\"/en-US/docs/Learn_web_development/Extensions/Async_JS\">Asynchronous JavaScript</a></summary><ol><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Async_JS/Introducing\">Introducing asynchronous JavaScript</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Async_JS/Promises\">How to use promises</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Async_JS/Implementing_a_promise-based_API\">How to implement a promise-based API</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Async_JS/Introducing_workers\">Introducing workers</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Async_JS/Sequencing_animations\">Challenge: Sequencing animations</a></li></ol></details></li><li class=\"toggle\"><details><summary><a href=\"/en-US/docs/Learn_web_development/Extensions/Forms\">Web forms</a></summary><ol><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Forms/Your_first_form\">Your first form</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Forms/How_to_structure_a_web_form\">How to structure a web form</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Forms/Basic_native_form_controls\">Basic native form controls</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Forms/HTML5_input_types\">The HTML5 input types</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Forms/Other_form_controls\">Other form controls</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Forms/Styling_web_forms\">Styling web forms</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Forms/Advanced_form_styling\">Advanced form styling</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Forms/UI_pseudo-classes\">UI pseudo-classes</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Forms/Form_validation\">Client-side form validation</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Forms/Sending_and_retrieving_form_data\">Sending form data</a></li></ol></details></li><li class=\"toggle\"><details><summary><a href=\"/en-US/docs/Learn_web_development/Extensions/Client-side_tools\">Understanding client-side tools</a></summary><ol><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Client-side_tools/Overview\">Client-side tooling overview</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Client-side_tools/Package_management\">Package management basics</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Client-side_tools/Introducing_complete_toolchain\">Introducing a complete toolchain</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Client-side_tools/Deployment\">Deploying our app</a></li></ol></details></li><li class=\"toggle\"><details><summary><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side\">Server-side websites</a></summary><ol><li class=\"toggle\"><details><summary><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/First_steps\">Server-side first steps</a></summary><ol><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/First_steps/Introduction\">Introduction to the server side</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/First_steps/Client-Server_overview\">Client-Server Overview</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/First_steps/Web_frameworks\">Server-side web frameworks</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/First_steps/Website_security\">Website security</a></li></ol></details></li><li class=\"toggle\"><details><summary><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/Django\">Django web framework (Python)</a></summary><ol><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/Django/Introduction\">Django introduction</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/Django/development_environment\">Setting up a Django development environment</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/Django/Tutorial_local_library_website\">Django Tutorial: The Local Library website</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/Django/skeleton_website\">Django Tutorial Part 2: Creating a skeleton website</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/Django/Models\">Django Tutorial Part 3: Using models</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/Django/Admin_site\">Django Tutorial Part 4: Django admin site</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/Django/Home_page\">Django Tutorial Part 5: Creating our home page</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/Django/Generic_views\">Django Tutorial Part 6: Generic list and detail views</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/Django/Sessions\">Django Tutorial Part 7: Sessions framework</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/Django/Authentication\">Django Tutorial Part 8: User authentication and permissions</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/Django/Forms\">Django Tutorial Part 9: Working with forms</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/Django/Testing\">Django Tutorial Part 10: Testing a Django web application</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/Django/Deployment\">Django Tutorial Part 11: Deploying Django to production</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/Django/web_application_security\">Django web application security</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/Django/django_assessment_blog\">Assessment: DIY Django mini blog</a></li></ol></details></li><li class=\"toggle\"><details><summary><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs\">Express web framework (Node.js)</a></summary><ol><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/Introduction\">Express/Node introduction</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/development_environment\">Setting up a Node development environment</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/Tutorial_local_library_website\">Express Tutorial: The Local Library website</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/skeleton_website\">Express Tutorial Part 2: Creating a skeleton website</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/mongoose\">Express Tutorial Part 3: Using a Database (with Mongoose)</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/routes\">Express Tutorial Part 4: Routes and controllers</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/Displaying_data\">Express Tutorial Part 5: Displaying library data</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/forms\">Express Tutorial Part 6: Working with forms</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/deployment\">Express Tutorial Part 7: Deploying to production</a></li></ol></details></li></ol></details></li><li class=\"toggle\"><details><summary><a href=\"/en-US/docs/Learn_web_development/Extensions/Performance\">Web performance</a></summary><ol><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Performance/why_web_performance\">The \"why\" of web performance</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Performance/What_is_web_performance\">What is web performance?</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Performance/Perceived_performance\">Perceived performance</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Performance/Measuring_performance\">Measuring performance</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Performance/Multimedia\">Multimedia: Images</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Performance/video\">Multimedia: video</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Performance/JavaScript\">JavaScript performance optimization</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Performance/HTML\">HTML performance optimization</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Performance/CSS\">CSS performance optimization</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Performance/business_case_for_performance\">The business case for web performance</a></li></ol></details></li><li class=\"toggle\"><details><summary><a href=\"/en-US/docs/Learn_web_development/Extensions/Testing\">Testing</a></summary><ol><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Testing/Introduction\">Introduction to cross-browser testing</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Testing/Testing_strategies\">Strategies for carrying out testing</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Testing/HTML_and_CSS\">Handling common HTML and CSS problems</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Testing/Feature_detection\">Implementing feature detection</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Testing/Automated_testing\">Introduction to automated testing</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Testing/Your_own_automation_environment\">Setting up your own test automation environment</a></li></ol></details></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Transform_animate\">Transform and animate CSS</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Security_privacy\">Security and privacy</a></li><li class=\"section\">Further resources</li><li class=\"toggle\"><details><summary><a href=\"/en-US/docs/Learn_web_development/Howto\">How to solve common problems</a></summary><ol><li><a href=\"/en-US/docs/Learn_web_development/Howto/Solve_HTML_problems\">Solve common HTML problems</a></li><li><a href=\"/en-US/docs/Learn_web_development/Howto/Solve_CSS_problems\">Solve common CSS problems</a></li><li><a href=\"/en-US/docs/Learn_web_development/Howto/Solve_JavaScript_problems\">Solve common JavaScript problems</a></li><li><a href=\"/en-US/docs/Learn_web_development/Howto/Web_mechanics\">Web mechanics</a></li><li><a href=\"/en-US/docs/Learn_web_development/Howto/Tools_and_setup\">Tools and setup</a></li><li><a href=\"/en-US/docs/Learn_web_development/Howto/Design_and_accessibility\">Design and accessibility</a></li></ol></details></li><li><a href=\"/en-US/docs/Learn_web_development/About\">About</a></li><li><a href=\"/en-US/docs/Learn_web_development/Educators\">Resources for educators</a></li><li><a href=\"/en-US/docs/Learn_web_development/Changelog\">Changelog</a></li></ol>","source":{"folder":"en-us/learn_web_development/core/frameworks_libraries/react_accessibility","github_url":"https://github.com/mdn/content/blob/main/files/en-us/learn_web_development/core/frameworks_libraries/react_accessibility/index.md","last_commit_url":"https://github.com/mdn/content/commit/5b20f5f4265f988f80f513db0e4b35c7e0cd70dc","filename":"index.md"},"summary":"In our final tutorial article, we'll focus on (pun intended) accessibility, including focus management in React, which can improve usability and reduce confusion for both keyboard-only and screen reader users.","title":"Accessibility in React","toc":[{"text":"Including keyboard users","id":"including_keyboard_users"},{"text":"Exploring the keyboard usability problem","id":"exploring_the_keyboard_usability_problem"},{"text":"Focusing between templates","id":"focusing_between_templates"},{"text":"More robust focus management","id":"more_robust_focus_management"},{"text":"Focusing when the user deletes a task","id":"focusing_when_the_user_deletes_a_task"},{"text":"Finished!","id":"finished!"}],"pageType":"learn-module-chapter"}}</script></body></html>