[{"data":1,"prerenderedAt":479},["ShallowReactive",2],{"docs:accessibility":3},{"frontmatter":4,"meta":5,"nodes":6},{},{},[7,12,16,19,24,55,78,82,93,269,293,314,318,331,335,377,398,402,422,426,429],[8,9,11],"h1",{"id":10},"accessibility","Accessibility",[13,14,15],"p",{},"What components handle, and what you still own.",[13,17,18],{},"Compose the parts and you inherit the ARIA roles and attributes, pointer and keyboard interaction, and focus management the pattern calls for, tunable through props. What's left is what a headless library can't decide: visible focus, color contrast, accessible names for your own controls, and reduced motion.",[20,21,23],"h2",{"id":22},"keyboard-navigation","Keyboard navigation",[13,25,26,27,32,33,40,41,40,45,49,50,54],{},"Every component follows the ",[28,29,31],"a",{"href":30},"https:\u002F\u002Fwww.w3.org\u002FWAI\u002FARIA\u002Fapg\u002F","WAI-ARIA Authoring Practices",", so keyboard support works the moment you render it, for people who can't use a pointer, and for anyone who prefers the keyboard. Depending on the component, that covers the arrow keys, alphanumeric typeahead, ",[34,35,39],"kbd",{"$":36},{"html":37,"block":38},1,0,"Home",", ",[34,42,44],{"$":43},{"html":37,"block":38},"End",[34,46,48],{"$":47},{"html":37,"block":38},"Enter",", and ",[34,51,53],{"$":52},{"html":37,"block":38},"Esc",".",[13,56,57,58,40,62,40,65,68,69,72,73,77],{},"The handlers already sit on the parts, so you never wire them. To change what a key does, reach for the component's own props — ",[59,60,61],"code",{},"closeOnClick",[59,63,64],{},"loopFocus",[59,66,67],{},"modal"," — rather than layering your own ",[59,70,71],{},"@keydown"," on top: a handler you pass is ",[28,74,76],{"href":75},"\u002Fcomposition#merging-your-own-attributes","chained onto the part's",", so both run.",[20,79,81],{"id":80},"focus-management","Focus management",[13,83,84,85,88,89,92],{},"Focus follows interaction on its own: into the overlay when it opens, back to the trigger when it closes. When the default landing spot is wrong, ",[59,86,87],{},"initialFocus"," and ",[59,90,91],{},"finalFocus"," point it at a specific element:",[94,95,99],"pre",{"language":96,"meta":97,"class":98},"vue","title=\"Dialog initial focus\"","shiki shiki-themes github-light github-dark dark:github-dark",[59,100,102,132,133,132,148,132,160,132,162,132,191,132,200,132,202,132,211,132,229,132,252,132,261],{"class":101},"language-vue",[103,104,107,111,115,119,122,125,129],"span",{"class":105,"style":106},"line","display: inline",[103,108,110],{"style":109},"color:#24292E;--shiki-dark:#E1E4E8","\u003C",[103,112,114],{"style":113},"color:#22863A;--shiki-dark:#85E89D","script",[103,116,118],{"style":117},"color:#6F42C1;--shiki-dark:#B392F0"," setup",[103,120,121],{"style":117}," lang",[103,123,124],{"style":109},"=",[103,126,128],{"style":127},"color:#032F62;--shiki-dark:#9ECBFF","\"ts\"",[103,130,131],{"style":109},">","\n",[103,134,135,139,142,145],{"class":105,"style":106},[103,136,138],{"style":137},"color:#D73A49;--shiki-dark:#F97583","import",[103,140,141],{"style":109}," { useTemplateRef } ",[103,143,144],{"style":137},"from",[103,146,147],{"style":127}," 'vue'",[103,149,150,152,155,157],{"class":105,"style":106},[103,151,138],{"style":137},[103,153,154],{"style":109}," { Dialog } ",[103,156,144],{"style":137},[103,158,159],{"style":127}," '@shardsui\u002Fvue\u002Fdialog'",[103,161],{"class":105,"style":106},[103,163,164,167,171,174,177,179,182,185,188],{"class":105,"style":106},[103,165,166],{"style":137},"const",[103,168,170],{"style":169},"color:#005CC5;--shiki-dark:#79B8FF"," confirmButton",[103,172,173],{"style":137}," =",[103,175,176],{"style":117}," useTemplateRef",[103,178,110],{"style":109},[103,180,181],{"style":117},"HTMLButtonElement",[103,183,184],{"style":109},">(",[103,186,187],{"style":127},"'confirm'",[103,189,190],{"style":109},")",[103,192,193,196,198],{"class":105,"style":106},[103,194,195],{"style":109},"\u003C\u002F",[103,197,114],{"style":113},[103,199,131],{"style":109},[103,201],{"class":105,"style":106},[103,203,204,206,209],{"class":105,"style":106},[103,205,110],{"style":109},[103,207,208],{"style":113},"template",[103,210,131],{"style":109},[103,212,213,216,219,222,224,227],{"class":105,"style":106},[103,214,215],{"style":109},"  \u003C",[103,217,218],{"style":113},"Dialog.Popup",[103,220,221],{"style":117}," :initial-focus",[103,223,124],{"style":109},[103,225,226],{"style":127},"\"() => confirmButton\"",[103,228,131],{"style":109},[103,230,231,234,237,240,242,245,248,250],{"class":105,"style":106},[103,232,233],{"style":109},"    \u003C",[103,235,236],{"style":113},"button",[103,238,239],{"style":117}," ref",[103,241,124],{"style":109},[103,243,244],{"style":127},"\"confirm\"",[103,246,247],{"style":109},">Confirm\u003C\u002F",[103,249,236],{"style":113},[103,251,131],{"style":109},[103,253,254,257,259],{"class":105,"style":106},[103,255,256],{"style":109},"  \u003C\u002F",[103,258,218],{"style":113},[103,260,131],{"style":109},[103,262,263,265,267],{"class":105,"style":106},[103,264,195],{"style":109},[103,266,208],{"style":113},[103,268,131],{"style":109},[13,270,271,272,275,276,279,280,40,283,40,286,40,289,292],{},"Both take an element, but a template ref starts out ",[59,273,274],{},"null",", so pass a getter. It's read at the moment focus moves, when the element exists. Both also take ",[59,277,278],{},"false"," to skip focusing entirely, and the function form receives the interaction type (",[59,281,282],{},"'mouse'",[59,284,285],{},"'keyboard'",[59,287,288],{},"'touch'",[59,290,291],{},"'pen'",") so the target can differ per input mode.",[13,294,295,296,300,301,304,305,308,309,313],{},"Moving focus is handled; making it ",[297,298,299],"em",{},"visible"," is on you. Style ",[59,302,303],{},":focus-visible"," — not ",[59,306,307],{},":focus",", which also fires on mouse clicks — with a ring that clears the ",[28,310,312],{"href":311},"https:\u002F\u002Fwww.w3.org\u002FWAI\u002FWCAG22\u002FUnderstanding\u002Ffocus-appearance","WCAG focus-appearance"," thresholds.",[20,315,317],{"id":316},"color-contrast","Color contrast",[13,319,320,321,325,326,330],{},"As you style, hold enough contrast between each foreground element and whatever sits behind it to clear the minimum thresholds. Unless a specific standard binds you, measure against ",[28,322,324],{"href":323},"https:\u002F\u002Fapcacontrast.com\u002F","APCA",". It accounts for font size and weight; ",[28,327,329],{"href":328},"https:\u002F\u002Fwww.w3.org\u002FWAI\u002FWCAG22\u002FUnderstanding\u002Fcontrast-minimum","WCAG"," 2 ratios do not.",[20,332,334],{"id":333},"accessible-labels","Accessible labels",[13,336,337,338,88,342,345,346,40,349,49,352,355,356,359,360,88,363,366,367,371,372,376],{},"Wrap form controls in ",[28,339,341],{"href":340},"\u002Ffield","Field",[59,343,344],{},"\u003CField.Control>"," is wired to its ",[59,347,348],{},"\u003CField.Label>",[59,350,351],{},"\u003CField.Description>",[59,353,354],{},"\u003CField.Error>"," for you: ",[59,357,358],{},"for"," on a native label, ",[59,361,362],{},"aria-labelledby",[59,364,365],{},"aria-describedby"," everywhere else. ",[28,368,370],{"href":369},"\u002Ffieldset","Fieldset"," does the same for a group and its legend. See the ",[28,373,375],{"href":374},"\u002Fforms","Forms guide"," for the whole shape.",[13,378,379,380,383,384,40,387,389,390,392,393,397],{},"Everything else needs a name you supply. Icon-only triggers — popover, menu, dialog — carry no text, so give the trigger an ",[59,381,382],{},"aria-label",". Custom controls take a name from ",[59,385,386],{},"alt",[59,388,382],{},", or ",[59,391,362],{},"; the ",[28,394,396],{"href":395},"https:\u002F\u002Fwww.w3.org\u002FTR\u002Fwai-aria-1.2\u002F#namecalculation","accessible-name computation"," spells out how those combine.",[20,399,401],{"id":400},"reduced-motion","Reduced motion",[13,403,404,405,408,409,412,413,416,417,421],{},"Enter\u002Fexit animations are yours to style, and some people disable motion at the OS level. Author resting styles with no motion and layer transitions on inside ",[59,406,407],{},"@media (prefers-reduced-motion: no-preference)",". The ",[59,410,411],{},"[data-starting-style]"," \u002F ",[59,414,415],{},"[data-ending-style]"," attributes still apply with no transition, so the element snaps between states and unmounts immediately. See ",[28,418,420],{"href":419},"\u002Fanimation#respect-reduced-motion","Animation"," for the full pattern.",[20,423,425],{"id":424},"testing","Testing",[13,427,428],{},"The library is tested, but your composition of it isn't. A checklist before shipping:",[430,431,432,440,449,455,461,470],"ul",{},[433,434,435,439],"li",{},[436,437,438],"strong",{},"Keyboard",": Tab to every control; exercise arrow keys, Enter, Space, and Esc in menus, dialogs, listboxes, and tabs.",[433,441,442,445,446,448],{},[436,443,444],{},"Focus visibility",": Confirm ",[59,447,303],{}," styles are visible on every interactive part.",[433,450,451,454],{},[436,452,453],{},"Screen readers",": Spot-check critical flows with VoiceOver (macOS\u002FiOS), NVDA, or JAWS.",[433,456,457,460],{},[436,458,459],{},"Touch",": Confirm hover-only affordances (tooltips, preview cards) are not the only way to reach essential information.",[433,462,463,466,467,54],{},[436,464,465],{},"Forms",": Submit with invalid data. Errors should land on the right field, and focus should move to the first failure. See ",[28,468,465],{"href":469},"\u002Fforms#showing-the-error",[433,471,472,474,475,478],{},[436,473,401],{},": Test with ",[59,476,477],{},"prefers-reduced-motion: reduce"," enabled.",1789390078350]