[{"data":1,"prerenderedAt":1078},["ShallowReactive",2],{"site-header-nav":3,"page-\u002Freact-nextjs-accessibility-patterns\u002Freact-hooks-for-accessibility\u002Fmaking-react-useeffect-accessible-for-screen-readers\u002F":156,"content-navigation":1004},[4,66,70],{"title":5,"path":6,"stem":7,"children":8},"Core Accessibility Principles For Modern Frameworks","\u002Fcore-accessibility-principles-for-modern-frameworks","core-accessibility-principles-for-modern-frameworks",[9,12,18,24,36,48,60],{"title":10,"path":6,"stem":11},"Core Accessibility Principles for Modern Frameworks","core-accessibility-principles-for-modern-frameworks\u002Findex",{"title":13,"path":14,"stem":15,"children":16},"Accessible Color Contrast & Theming","\u002Fcore-accessibility-principles-for-modern-frameworks\u002Faccessible-color-contrast-theming","core-accessibility-principles-for-modern-frameworks\u002Faccessible-color-contrast-theming\u002Findex",[17],{"title":13,"path":14,"stem":15},{"title":19,"path":20,"stem":21,"children":22},"Accessible Form Validation & Error States in Modern Frameworks","\u002Fcore-accessibility-principles-for-modern-frameworks\u002Faccessible-form-validation-error-states","core-accessibility-principles-for-modern-frameworks\u002Faccessible-form-validation-error-states\u002Findex",[23],{"title":19,"path":20,"stem":21},{"title":25,"path":26,"stem":27,"children":28},"Focus Management Strategies for SPAs","\u002Fcore-accessibility-principles-for-modern-frameworks\u002Ffocus-management-strategies-for-spas","core-accessibility-principles-for-modern-frameworks\u002Ffocus-management-strategies-for-spas\u002Findex",[29,30],{"title":25,"path":26,"stem":27},{"title":31,"path":32,"stem":33,"children":34},"Handling Focus Restoration After Dynamic Route Changes","\u002Fcore-accessibility-principles-for-modern-frameworks\u002Ffocus-management-strategies-for-spas\u002Fhandling-focus-restoration-after-dynamic-route-changes","core-accessibility-principles-for-modern-frameworks\u002Ffocus-management-strategies-for-spas\u002Fhandling-focus-restoration-after-dynamic-route-changes\u002Findex",[35],{"title":31,"path":32,"stem":33},{"title":37,"path":38,"stem":39,"children":40},"Keyboard Navigation Patterns for Modals","\u002Fcore-accessibility-principles-for-modern-frameworks\u002Fkeyboard-navigation-patterns-for-modals","core-accessibility-principles-for-modern-frameworks\u002Fkeyboard-navigation-patterns-for-modals\u002Findex",[41,42],{"title":37,"path":38,"stem":39},{"title":43,"path":44,"stem":45,"children":46},"Building Accessible Dropdowns Without External UI Kits","\u002Fcore-accessibility-principles-for-modern-frameworks\u002Fkeyboard-navigation-patterns-for-modals\u002Fbuilding-accessible-dropdowns-without-external-ui-kits","core-accessibility-principles-for-modern-frameworks\u002Fkeyboard-navigation-patterns-for-modals\u002Fbuilding-accessible-dropdowns-without-external-ui-kits\u002Findex",[47],{"title":43,"path":44,"stem":45},{"title":49,"path":50,"stem":51,"children":52},"Screen Reader Compatibility Testing for Modern Frameworks","\u002Fcore-accessibility-principles-for-modern-frameworks\u002Fscreen-reader-compatibility-testing","core-accessibility-principles-for-modern-frameworks\u002Fscreen-reader-compatibility-testing\u002Findex",[53,54],{"title":49,"path":50,"stem":51},{"title":55,"path":56,"stem":57,"children":58},"Testing ARIA Live Regions with Jest and Testing Library","\u002Fcore-accessibility-principles-for-modern-frameworks\u002Fscreen-reader-compatibility-testing\u002Ftesting-aria-live-regions-with-jest-and-testing-library","core-accessibility-principles-for-modern-frameworks\u002Fscreen-reader-compatibility-testing\u002Ftesting-aria-live-regions-with-jest-and-testing-library\u002Findex",[59],{"title":55,"path":56,"stem":57},{"title":61,"path":62,"stem":63,"children":64},"Semantic HTML vs ARIA in Component Trees","\u002Fcore-accessibility-principles-for-modern-frameworks\u002Fsemantic-html-vs-aria-in-component-trees","core-accessibility-principles-for-modern-frameworks\u002Fsemantic-html-vs-aria-in-component-trees\u002Findex",[65],{"title":61,"path":62,"stem":63},{"title":67,"path":68,"stem":69},"Modern Framework Accessibility","\u002F","index",{"title":71,"path":72,"stem":73,"children":74},"React Nextjs Accessibility Patterns","\u002Freact-nextjs-accessibility-patterns","react-nextjs-accessibility-patterns",[75,78,90,102,108,126,144],{"title":76,"path":72,"stem":77},"React & Next.js Accessibility Patterns","react-nextjs-accessibility-patterns\u002Findex",{"title":79,"path":80,"stem":81,"children":82},"Accessible Component Libraries in React","\u002Freact-nextjs-accessibility-patterns\u002Faccessible-component-libraries-in-react","react-nextjs-accessibility-patterns\u002Faccessible-component-libraries-in-react\u002Findex",[83,84],{"title":79,"path":80,"stem":81},{"title":85,"path":86,"stem":87,"children":88},"Building Accessible Tabs in React Without Radix UI","\u002Freact-nextjs-accessibility-patterns\u002Faccessible-component-libraries-in-react\u002Fbuilding-accessible-tabs-in-react-without-radix-ui","react-nextjs-accessibility-patterns\u002Faccessible-component-libraries-in-react\u002Fbuilding-accessible-tabs-in-react-without-radix-ui\u002Findex",[89],{"title":85,"path":86,"stem":87},{"title":91,"path":92,"stem":93,"children":94},"Dynamic Content & State Announcements in React & Next.js","\u002Freact-nextjs-accessibility-patterns\u002Fdynamic-content-state-announcements","react-nextjs-accessibility-patterns\u002Fdynamic-content-state-announcements\u002Findex",[95,96],{"title":91,"path":92,"stem":93},{"title":97,"path":98,"stem":99,"children":100},"Implementing React Context for Global Accessibility Preferences","\u002Freact-nextjs-accessibility-patterns\u002Fdynamic-content-state-announcements\u002Freact-context-for-global-accessibility-preferences","react-nextjs-accessibility-patterns\u002Fdynamic-content-state-announcements\u002Freact-context-for-global-accessibility-preferences\u002Findex",[101],{"title":97,"path":98,"stem":99},{"title":103,"path":104,"stem":105,"children":106},"Form Handling with React Hook Form & Accessibility","\u002Freact-nextjs-accessibility-patterns\u002Fform-handling-with-react-hook-form-a11y","react-nextjs-accessibility-patterns\u002Fform-handling-with-react-hook-form-a11y\u002Findex",[107],{"title":103,"path":104,"stem":105},{"title":109,"path":110,"stem":111,"children":112},"Next.js App Router & A11y: Implementation Guide for Modern Frameworks","\u002Freact-nextjs-accessibility-patterns\u002Fnextjs-app-router-a11y","react-nextjs-accessibility-patterns\u002Fnextjs-app-router-a11y\u002Findex",[113,114,120],{"title":109,"path":110,"stem":111},{"title":115,"path":116,"stem":117,"children":118},"Implementing Skip Links in Next.js App Router: A Step-by-Step Guide","\u002Freact-nextjs-accessibility-patterns\u002Fnextjs-app-router-a11y\u002Fimplementing-skip-links-in-nextjs-app-router","react-nextjs-accessibility-patterns\u002Fnextjs-app-router-a11y\u002Fimplementing-skip-links-in-nextjs-app-router\u002Findex",[119],{"title":115,"path":116,"stem":117},{"title":121,"path":122,"stem":123,"children":124},"Next.js Dynamic Imports and Keyboard Navigation: A Complete A11y Implementation Guide","\u002Freact-nextjs-accessibility-patterns\u002Fnextjs-app-router-a11y\u002Fnextjs-dynamic-imports-and-keyboard-navigation","react-nextjs-accessibility-patterns\u002Fnextjs-app-router-a11y\u002Fnextjs-dynamic-imports-and-keyboard-navigation\u002Findex",[125],{"title":121,"path":122,"stem":123},{"title":127,"path":128,"stem":129,"children":130},"React Hooks for Accessibility: Implementation Patterns & State Management","\u002Freact-nextjs-accessibility-patterns\u002Freact-hooks-for-accessibility","react-nextjs-accessibility-patterns\u002Freact-hooks-for-accessibility\u002Findex",[131,132,138],{"title":127,"path":128,"stem":129},{"title":133,"path":134,"stem":135,"children":136},"Fixing Focus Trap Issues in React Portals","\u002Freact-nextjs-accessibility-patterns\u002Freact-hooks-for-accessibility\u002Ffixing-focus-trap-issues-in-react-portals","react-nextjs-accessibility-patterns\u002Freact-hooks-for-accessibility\u002Ffixing-focus-trap-issues-in-react-portals\u002Findex",[137],{"title":133,"path":134,"stem":135},{"title":139,"path":140,"stem":141,"children":142},"Making React useEffect Accessible for Screen Readers","\u002Freact-nextjs-accessibility-patterns\u002Freact-hooks-for-accessibility\u002Fmaking-react-useeffect-accessible-for-screen-readers","react-nextjs-accessibility-patterns\u002Freact-hooks-for-accessibility\u002Fmaking-react-useeffect-accessible-for-screen-readers\u002Findex",[143],{"title":139,"path":140,"stem":141},{"title":145,"path":146,"stem":147,"children":148},"Server Components & Client-Side Interactivity","\u002Freact-nextjs-accessibility-patterns\u002Fserver-components-client-side-interactivity","react-nextjs-accessibility-patterns\u002Fserver-components-client-side-interactivity\u002Findex",[149,150],{"title":145,"path":146,"stem":147},{"title":151,"path":152,"stem":153,"children":154},"Handling Accessible Modals in Next.js 14 Server Components","\u002Freact-nextjs-accessibility-patterns\u002Fserver-components-client-side-interactivity\u002Fhandling-accessible-modals-in-nextjs-14-server-components","react-nextjs-accessibility-patterns\u002Fserver-components-client-side-interactivity\u002Fhandling-accessible-modals-in-nextjs-14-server-components\u002Findex",[155],{"title":151,"path":152,"stem":153},{"id":157,"title":139,"body":158,"date":997,"description":998,"extension":999,"image":997,"meta":1000,"modifiedAt":997,"navigation":295,"noindex":1001,"path":140,"publishedAt":997,"seo":1002,"stem":141,"updatedAt":997,"__hash__":1003},"content\u002Freact-nextjs-accessibility-patterns\u002Freact-hooks-for-accessibility\u002Fmaking-react-useeffect-accessible-for-screen-readers\u002Findex.md",{"type":159,"value":160,"toc":984},"minimark",[161,165,187,194,199,205,241,247,251,258,596,623,628,632,635,663,856,861,888,893,897,932,936,944,950,963,973,977,980],[162,163,139],"h1",{"id":164},"making-react-useeffect-accessible-for-screen-readers",[166,167,168,169,173,174,178,179,182,183,186],"p",{},"When managing dynamic state in modern frontend architectures, developers frequently overlook how ",[170,171,172],"code",{},"useEffect"," triggers screen reader updates. This guide provides a reproducible implementation for synchronizing React side effects with ARIA live regions, ensuring reliable announcements without race conditions or duplicate speech. Adhering to these patterns is critical for compliance with WCAG 2.2 criteria: ",[175,176,177],"strong",{},"4.1.3 Status Messages (Level AA)",", ",[175,180,181],{},"1.3.1 Info and Relationships (Level A)",", and ",[175,184,185],{},"2.1.1 Keyboard (Level A)",".",[166,188,189,190,186],{},"Core implementation principles include aligning dependency arrays with live region DOM updates, preventing announcement stacking via cleanup functions, and debouncing rapid state changes to respect screen reader speech queues. For broader architectural context on integrating these patterns into your component tree, refer to established practices in ",[191,192,76],"a",{"href":193},"\u002Freact-nextjs-accessibility-patterns\u002F",[195,196,198],"h2",{"id":197},"understanding-useeffect-and-live-region-timing","Understanding useEffect and Live Region Timing",[166,200,201,202,204],{},"React's commit phase does not guarantee immediate DOM availability when ",[170,203,172],{}," executes. Screen readers rely on OS-level accessibility APIs and DOM mutation observers to detect changes. If state updates trigger rapid re-renders, the accessibility tree may receive conflicting or truncated announcements.",[206,207,208,218,235],"ul",{},[209,210,211,214,215,217],"li",{},[175,212,213],{},"Render Cycle vs. DOM Mutation:"," ",[170,216,172],{}," runs after the browser paints. However, screen readers queue announcements based on DOM node changes, not React state transitions. Directly mutating text without a stable container breaks the mutation observer chain.",[209,219,220,214,223,226,227,230,231,234],{},[175,221,222],{},"Polite vs. Assertive Timing:",[170,224,225],{},"aria-live=\"polite\""," queues announcements until the user pauses interaction. ",[170,228,229],{},"aria-live=\"assertive\""," interrupts the current speech queue. Reserve ",[170,232,233],{},"assertive"," exclusively for critical errors.",[209,236,237,240],{},[175,238,239],{},"Stacking Prevention:"," Screen readers maintain a finite speech queue. Rapid sequential updates to the same live region are dropped or merged unpredictably. Implement state guards to throttle announcements and ensure each update is distinct.",[166,242,243,246],{},[175,244,245],{},"Testing Workflow:"," Verify with VoiceOver (macOS\u002FiOS) and NVDA (Windows) that rapid state updates do not cause overlapping or truncated speech. Monitor the DOM via browser DevTools Elements panel to ensure the live region updates exactly once per intended state change.",[195,248,250],{"id":249},"implementing-controlled-state-announcements","Implementing Controlled State Announcements",[166,252,253,254,257],{},"Production-grade announcements require a custom hook that isolates accessibility logic from business state. This pattern uses ",[170,255,256],{},"useRef"," to track previous values, preventing redundant DOM writes when React re-renders identical state.",[259,260,265],"pre",{"className":261,"code":262,"language":263,"meta":264,"style":264},"language-tsx shiki shiki-themes github-light github-dark","import { useEffect, useRef, useState } from 'react';\n\nexport function useAnnounce(message: string) {\n const [text, setText] = useState('');\n const prevMessage = useRef(message);\n\n useEffect(() => {\n if (message && message !== prevMessage.current) {\n setText(message);\n prevMessage.current = message;\n }\n \u002F\u002F Cleanup ensures the screen reader registers a DOM change on subsequent updates\n return () => setText('');\n }, [message]);\n\n return (\n \u003Cspan\n aria-live=\"polite\"\n role=\"status\"\n style={{ position: 'absolute', width: '1px', height: '1px', overflow: 'hidden', clip: 'rect(0 0 0 0)' }}\n >\n {text}\n \u003C\u002Fspan>\n );\n}\n","tsx","",[170,266,267,290,297,327,361,378,383,398,419,427,438,444,451,470,476,481,489,499,510,521,561,567,573,584,590],{"__ignoreMap":264},[268,269,272,276,280,283,287],"span",{"class":270,"line":271},"line",1,[268,273,275],{"class":274},"szBVR","import",[268,277,279],{"class":278},"sVt8B"," { useEffect, useRef, useState } ",[268,281,282],{"class":274},"from",[268,284,286],{"class":285},"sZZnC"," 'react'",[268,288,289],{"class":278},";\n",[268,291,293],{"class":270,"line":292},2,[268,294,296],{"emptyLinePlaceholder":295},true,"\n",[268,298,300,303,306,310,313,317,320,324],{"class":270,"line":299},3,[268,301,302],{"class":274},"export",[268,304,305],{"class":274}," function",[268,307,309],{"class":308},"sScJk"," useAnnounce",[268,311,312],{"class":278},"(",[268,314,316],{"class":315},"s4XuR","message",[268,318,319],{"class":274},":",[268,321,323],{"class":322},"sj4cs"," string",[268,325,326],{"class":278},") {\n",[268,328,330,333,336,339,341,344,347,350,353,355,358],{"class":270,"line":329},4,[268,331,332],{"class":274}," const",[268,334,335],{"class":278}," [",[268,337,338],{"class":322},"text",[268,340,178],{"class":278},[268,342,343],{"class":322},"setText",[268,345,346],{"class":278},"] ",[268,348,349],{"class":274},"=",[268,351,352],{"class":308}," useState",[268,354,312],{"class":278},[268,356,357],{"class":285},"''",[268,359,360],{"class":278},");\n",[268,362,364,366,369,372,375],{"class":270,"line":363},5,[268,365,332],{"class":274},[268,367,368],{"class":322}," prevMessage",[268,370,371],{"class":274}," =",[268,373,374],{"class":308}," useRef",[268,376,377],{"class":278},"(message);\n",[268,379,381],{"class":270,"line":380},6,[268,382,296],{"emptyLinePlaceholder":295},[268,384,386,389,392,395],{"class":270,"line":385},7,[268,387,388],{"class":308}," useEffect",[268,390,391],{"class":278},"(() ",[268,393,394],{"class":274},"=>",[268,396,397],{"class":278}," {\n",[268,399,401,404,407,410,413,416],{"class":270,"line":400},8,[268,402,403],{"class":274}," if",[268,405,406],{"class":278}," (message ",[268,408,409],{"class":274},"&&",[268,411,412],{"class":278}," message ",[268,414,415],{"class":274},"!==",[268,417,418],{"class":278}," prevMessage.current) {\n",[268,420,422,425],{"class":270,"line":421},9,[268,423,424],{"class":308}," setText",[268,426,377],{"class":278},[268,428,430,433,435],{"class":270,"line":429},10,[268,431,432],{"class":278}," prevMessage.current ",[268,434,349],{"class":274},[268,436,437],{"class":278}," message;\n",[268,439,441],{"class":270,"line":440},11,[268,442,443],{"class":278}," }\n",[268,445,447],{"class":270,"line":446},12,[268,448,450],{"class":449},"sJ8bj"," \u002F\u002F Cleanup ensures the screen reader registers a DOM change on subsequent updates\n",[268,452,454,457,460,462,464,466,468],{"class":270,"line":453},13,[268,455,456],{"class":274}," return",[268,458,459],{"class":278}," () ",[268,461,394],{"class":274},[268,463,424],{"class":308},[268,465,312],{"class":278},[268,467,357],{"class":285},[268,469,360],{"class":278},[268,471,473],{"class":270,"line":472},14,[268,474,475],{"class":278}," }, [message]);\n",[268,477,479],{"class":270,"line":478},15,[268,480,296],{"emptyLinePlaceholder":295},[268,482,484,486],{"class":270,"line":483},16,[268,485,456],{"class":274},[268,487,488],{"class":278}," (\n",[268,490,492,495],{"class":270,"line":491},17,[268,493,494],{"class":278}," \u003C",[268,496,498],{"class":497},"s9eBZ","span\n",[268,500,502,505,507],{"class":270,"line":501},18,[268,503,504],{"class":308}," aria-live",[268,506,349],{"class":274},[268,508,509],{"class":285},"\"polite\"\n",[268,511,513,516,518],{"class":270,"line":512},19,[268,514,515],{"class":308}," role",[268,517,349],{"class":274},[268,519,520],{"class":285},"\"status\"\n",[268,522,524,527,529,532,535,538,541,544,546,549,552,555,558],{"class":270,"line":523},20,[268,525,526],{"class":308}," style",[268,528,349],{"class":274},[268,530,531],{"class":278},"{{ position: ",[268,533,534],{"class":285},"'absolute'",[268,536,537],{"class":278},", width: ",[268,539,540],{"class":285},"'1px'",[268,542,543],{"class":278},", height: ",[268,545,540],{"class":285},[268,547,548],{"class":278},", overflow: ",[268,550,551],{"class":285},"'hidden'",[268,553,554],{"class":278},", clip: ",[268,556,557],{"class":285},"'rect(0 0 0 0)'",[268,559,560],{"class":278}," }}\n",[268,562,564],{"class":270,"line":563},21,[268,565,566],{"class":278}," >\n",[268,568,570],{"class":270,"line":569},22,[268,571,572],{"class":278}," {text}\n",[268,574,576,579,581],{"class":270,"line":575},23,[268,577,578],{"class":278}," \u003C\u002F",[268,580,268],{"class":497},[268,582,583],{"class":278},">\n",[268,585,587],{"class":270,"line":586},24,[268,588,589],{"class":278}," );\n",[268,591,593],{"class":270,"line":592},25,[268,594,595],{"class":278},"}\n",[166,597,598,599,601,602,604,605,607,608,610,611,614,615,617,618,622],{},"The hook maintains a local ",[170,600,338],{}," state bound to a visually hidden ",[170,603,268],{},". The ",[170,606,172],{}," compares the incoming ",[170,609,316],{}," against ",[170,612,613],{},"prevMessage.current",". If they differ, it updates the live region and caches the new value. The cleanup function resets ",[170,616,338],{}," to an empty string, forcing a DOM mutation that triggers the screen reader on the next render cycle. For comprehensive hook-level accessibility strategies, consult the ",[191,619,621],{"href":620},"\u002Freact-nextjs-accessibility-patterns\u002Freact-hooks-for-accessibility\u002F","React Hooks for Accessibility"," documentation.",[166,624,625,627],{},[175,626,245],{}," Test with JAWS and Android TalkBack to confirm focus remains on the interactive element while announcements queue in the background. Verify that clearing the text state does not trigger an unwanted secondary announcement.",[195,629,631],{"id":630},"debugging-silent-failures-and-race-conditions","Debugging Silent Failures and Race Conditions",[166,633,634],{},"Silent failures occur when the live region unmounts during effect execution, when React StrictMode double-invokes effects in development, or when ARIA attributes are misconfigured.",[206,636,637,643,649],{},[209,638,639,642],{},[175,640,641],{},"React StrictMode Double-Invocation:"," In development, React mounts, unmounts, and remounts components. Without proper guards, this triggers duplicate announcements or leaves stale DOM nodes.",[209,644,645,648],{},[175,646,647],{},"Missing Cleanup:"," Failing to clear the announcement state causes the screen reader to ignore subsequent identical strings, as the accessibility tree detects no delta.",[209,650,651,654,655,658,659,662],{},[175,652,653],{},"Incorrect ARIA Values:"," Omitting ",[170,656,657],{},"role=\"status\""," or using invalid ",[170,660,661],{},"aria-live"," values breaks the accessibility tree mapping, causing the OS to ignore the container entirely.",[259,664,666],{"className":261,"code":665,"language":263,"meta":264,"style":264},"import { useState, useEffect } from 'react';\n\nfunction StatusContainer({ children }: { children: React.ReactNode }) {\n const [mounted, setMounted] = useState(false);\n\n useEffect(() => {\n setMounted(true);\n return () => setMounted(false);\n }, []);\n\n if (!mounted) return null;\n return \u003Cdiv aria-live=\"polite\" role=\"status\">{children}\u003C\u002Fdiv>;\n}\n",[170,667,668,681,685,722,749,753,763,775,791,796,800,821,852],{"__ignoreMap":264},[268,669,670,672,675,677,679],{"class":270,"line":271},[268,671,275],{"class":274},[268,673,674],{"class":278}," { useState, useEffect } ",[268,676,282],{"class":274},[268,678,286],{"class":285},[268,680,289],{"class":278},[268,682,683],{"class":270,"line":292},[268,684,296],{"emptyLinePlaceholder":295},[268,686,687,690,693,696,699,702,704,707,709,711,714,716,719],{"class":270,"line":299},[268,688,689],{"class":274},"function",[268,691,692],{"class":308}," StatusContainer",[268,694,695],{"class":278},"({ ",[268,697,698],{"class":315},"children",[268,700,701],{"class":278}," }",[268,703,319],{"class":274},[268,705,706],{"class":278}," { ",[268,708,698],{"class":315},[268,710,319],{"class":274},[268,712,713],{"class":308}," React",[268,715,186],{"class":278},[268,717,718],{"class":308},"ReactNode",[268,720,721],{"class":278}," }) {\n",[268,723,724,726,728,731,733,736,738,740,742,744,747],{"class":270,"line":329},[268,725,332],{"class":274},[268,727,335],{"class":278},[268,729,730],{"class":322},"mounted",[268,732,178],{"class":278},[268,734,735],{"class":322},"setMounted",[268,737,346],{"class":278},[268,739,349],{"class":274},[268,741,352],{"class":308},[268,743,312],{"class":278},[268,745,746],{"class":322},"false",[268,748,360],{"class":278},[268,750,751],{"class":270,"line":363},[268,752,296],{"emptyLinePlaceholder":295},[268,754,755,757,759,761],{"class":270,"line":380},[268,756,388],{"class":308},[268,758,391],{"class":278},[268,760,394],{"class":274},[268,762,397],{"class":278},[268,764,765,768,770,773],{"class":270,"line":385},[268,766,767],{"class":308}," setMounted",[268,769,312],{"class":278},[268,771,772],{"class":322},"true",[268,774,360],{"class":278},[268,776,777,779,781,783,785,787,789],{"class":270,"line":400},[268,778,456],{"class":274},[268,780,459],{"class":278},[268,782,394],{"class":274},[268,784,767],{"class":308},[268,786,312],{"class":278},[268,788,746],{"class":322},[268,790,360],{"class":278},[268,792,793],{"class":270,"line":421},[268,794,795],{"class":278}," }, []);\n",[268,797,798],{"class":270,"line":429},[268,799,296],{"emptyLinePlaceholder":295},[268,801,802,804,807,810,813,816,819],{"class":270,"line":440},[268,803,403],{"class":274},[268,805,806],{"class":278}," (",[268,808,809],{"class":274},"!",[268,811,812],{"class":278},"mounted) ",[268,814,815],{"class":274},"return",[268,817,818],{"class":322}," null",[268,820,289],{"class":278},[268,822,823,825,827,830,832,834,837,839,841,844,847,849],{"class":270,"line":446},[268,824,456],{"class":274},[268,826,494],{"class":278},[268,828,829],{"class":497},"div",[268,831,504],{"class":308},[268,833,349],{"class":274},[268,835,836],{"class":285},"\"polite\"",[268,838,515],{"class":308},[268,840,349],{"class":274},[268,842,843],{"class":285},"\"status\"",[268,845,846],{"class":278},">{children}\u003C\u002F",[268,848,829],{"class":497},[268,850,851],{"class":278},">;\n",[268,853,854],{"class":270,"line":453},[268,855,595],{"class":278},[166,857,858],{},[175,859,860],{},"Debugging Workflow:",[862,863,864,867,870,877],"ol",{},[209,865,866],{},"Enable \"Pause on DOM subtree modifications\" in Chrome\u002FEdge DevTools Elements panel.",[209,868,869],{},"Trigger the state change and verify the live region receives exactly one text node update.",[209,871,872,873,876],{},"Run ",[170,874,875],{},"npm run build"," to disable StrictMode double-invocation and confirm production behavior matches development.",[209,878,879,880,883,884,887],{},"Enable screen reader logging (e.g., NVDA's ",[170,881,882],{},"Log to File"," or VoiceOver's ",[170,885,886],{},"Show Log",") to verify announcement delivery timing against effect execution timestamps.",[166,889,890,892],{},[175,891,245],{}," Use browser DevTools to inspect DOM mutations during effect execution. Enable screen reader logging to verify announcement delivery timing.",[195,894,896],{"id":895},"common-pitfalls","Common Pitfalls",[206,898,899,908,917,926],{},[209,900,901,904,905,907],{},[175,902,903],{},"Omitting Cleanup Functions:"," Updating live region text inside ",[170,906,172],{}," without a cleanup function causes duplicate announcements on subsequent re-renders.",[209,909,910,913,914,916],{},[175,911,912],{},"Misusing Assertive Regions:"," Applying ",[170,915,229],{}," to non-critical updates (e.g., pagination, loading spinners) interrupts user navigation and degrades the experience.",[209,918,919,922,923,925],{},[175,920,921],{},"Premature DOM Access:"," Relying on ",[170,924,172],{}," to announce state before the DOM has committed the update results in silent failures, as screen readers observe the DOM, not React state.",[209,927,928,931],{},[175,929,930],{},"Unmounting Live Regions:"," Placing the live region inside a component that conditionally unmounts during the effect execution breaks the announcement queue. Always mount live regions at a stable parent level.",[195,933,935],{"id":934},"frequently-asked-questions","Frequently Asked Questions",[937,938,940,941,943],"h3",{"id":939},"why-does-my-useeffect-screen-reader-announcement-only-work-once","Why does my ",[170,942,172],{}," screen reader announcement only work once?",[166,945,946,947,949],{},"React may batch updates or reuse DOM nodes, causing the screen reader to ignore identical text. Use a ",[170,948,256],{}," to track previous values and clear the live region text on cleanup or via a short timeout to force a DOM mutation.",[937,951,953,954,956,957,959,960,962],{"id":952},"should-i-use-aria-livepolite-or-aria-liveassertive-with-useeffect","Should I use ",[170,955,225],{}," or ",[170,958,229],{}," with ",[170,961,172],{},"?",[166,964,965,966,969,970,972],{},"Use ",[170,967,968],{},"polite"," for background updates like form validation or loading states. Reserve ",[170,971,233],{}," for critical errors that require immediate user attention, as it forcibly interrupts the current speech queue.",[937,974,976],{"id":975},"how-do-i-handle-react-strictmode-double-rendering-with-live-regions","How do I handle React StrictMode double-rendering with live regions?",[166,978,979],{},"StrictMode intentionally invokes effects twice in development. Ensure your cleanup function resets the announcement state, and use a ref to guard against duplicate announcements during the second invocation. Production builds execute effects once, so development guards must be robust.",[981,982,983],"style",{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":264,"searchDepth":292,"depth":292,"links":985},[986,987,988,989,990],{"id":197,"depth":292,"text":198},{"id":249,"depth":292,"text":250},{"id":630,"depth":292,"text":631},{"id":895,"depth":292,"text":896},{"id":934,"depth":292,"text":935,"children":991},[992,994,996],{"id":939,"depth":299,"text":993},"Why does my useEffect screen reader announcement only work once?",{"id":952,"depth":299,"text":995},"Should I use aria-live=\"polite\" or aria-live=\"assertive\" with useEffect?",{"id":975,"depth":299,"text":976},null,"Make React useEffect updates screen-reader friendly by coordinating live regions, effect timing, and cleanup to avoid missed announcements.","md",{},false,{"title":139,"description":998},"AwIPJ_nZpaGn0JO8b1JPjzsJinvhJZ1AVjwqTbACd5Q",[1005,1035,1036],{"title":5,"path":6,"stem":7,"children":1006},[1007,1008,1011,1014,1020,1026,1032],{"title":10,"path":6,"stem":11},{"title":13,"path":14,"stem":15,"children":1009},[1010],{"title":13,"path":14,"stem":15},{"title":19,"path":20,"stem":21,"children":1012},[1013],{"title":19,"path":20,"stem":21},{"title":25,"path":26,"stem":27,"children":1015},[1016,1017],{"title":25,"path":26,"stem":27},{"title":31,"path":32,"stem":33,"children":1018},[1019],{"title":31,"path":32,"stem":33},{"title":37,"path":38,"stem":39,"children":1021},[1022,1023],{"title":37,"path":38,"stem":39},{"title":43,"path":44,"stem":45,"children":1024},[1025],{"title":43,"path":44,"stem":45},{"title":49,"path":50,"stem":51,"children":1027},[1028,1029],{"title":49,"path":50,"stem":51},{"title":55,"path":56,"stem":57,"children":1030},[1031],{"title":55,"path":56,"stem":57},{"title":61,"path":62,"stem":63,"children":1033},[1034],{"title":61,"path":62,"stem":63},{"title":67,"path":68,"stem":69},{"title":71,"path":72,"stem":73,"children":1037},[1038,1039,1045,1051,1054,1063,1072],{"title":76,"path":72,"stem":77},{"title":79,"path":80,"stem":81,"children":1040},[1041,1042],{"title":79,"path":80,"stem":81},{"title":85,"path":86,"stem":87,"children":1043},[1044],{"title":85,"path":86,"stem":87},{"title":91,"path":92,"stem":93,"children":1046},[1047,1048],{"title":91,"path":92,"stem":93},{"title":97,"path":98,"stem":99,"children":1049},[1050],{"title":97,"path":98,"stem":99},{"title":103,"path":104,"stem":105,"children":1052},[1053],{"title":103,"path":104,"stem":105},{"title":109,"path":110,"stem":111,"children":1055},[1056,1057,1060],{"title":109,"path":110,"stem":111},{"title":115,"path":116,"stem":117,"children":1058},[1059],{"title":115,"path":116,"stem":117},{"title":121,"path":122,"stem":123,"children":1061},[1062],{"title":121,"path":122,"stem":123},{"title":127,"path":128,"stem":129,"children":1064},[1065,1066,1069],{"title":127,"path":128,"stem":129},{"title":133,"path":134,"stem":135,"children":1067},[1068],{"title":133,"path":134,"stem":135},{"title":139,"path":140,"stem":141,"children":1070},[1071],{"title":139,"path":140,"stem":141},{"title":145,"path":146,"stem":147,"children":1073},[1074,1075],{"title":145,"path":146,"stem":147},{"title":151,"path":152,"stem":153,"children":1076},[1077],{"title":151,"path":152,"stem":153},1778094796327]