Skip to content

Commit b261b6f

Browse files
fix(devtools): Improve devtools accessibility by adding aria attributes, using semantic components and field labels (#9806)
* update devtool a11y * changeset * ci: apply automated fixes * Update packages/query-devtools/src/Devtools.tsx * unnecessary role * label -> input * ci: apply automated fixes --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
1 parent c9bc600 commit b261b6f

File tree

3 files changed

+167
-153
lines changed

3 files changed

+167
-153
lines changed

.changeset/slick-clubs-lay.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@tanstack/query-devtools': patch
3+
---
4+
5+
improves accessibility of devtools

packages/query-devtools/src/Devtools.tsx

Lines changed: 146 additions & 151 deletions
Original file line numberDiff line numberDiff line change
@@ -1000,7 +1000,7 @@ export const ContentView: Component<ContentViewProps> = (props) => {
10001000
'tsqd-action-open-pip',
10011001
)}
10021002
aria-label="Open in picture-in-picture mode"
1003-
title={`Open in picture-in-picture mode`}
1003+
title="Open in picture-in-picture mode"
10041004
>
10051005
<PiPIcon />
10061006
</button>
@@ -1013,6 +1013,8 @@ export const ContentView: Component<ContentViewProps> = (props) => {
10131013
'tsqd-actions-btn',
10141014
'tsqd-action-settings',
10151015
)}
1016+
aria-label="Open settings menu"
1017+
title="Open settings menu"
10161018
>
10171019
<Settings />
10181020
</DropdownMenu.Trigger>
@@ -1061,62 +1063,58 @@ export const ContentView: Component<ContentViewProps> = (props) => {
10611063
'tsqd-settings-submenu',
10621064
)}
10631065
>
1064-
<DropdownMenu.Item
1065-
onSelect={() => {
1066-
setDevtoolsPosition('top')
1067-
}}
1068-
as="button"
1069-
class={cx(
1070-
styles().settingsSubButton,
1071-
'tsqd-settings-menu-position-btn',
1072-
'tsqd-settings-menu-position-btn-top',
1073-
)}
1074-
>
1075-
<span>Top</span>
1076-
<ArrowUp />
1077-
</DropdownMenu.Item>
1078-
<DropdownMenu.Item
1079-
onSelect={() => {
1080-
setDevtoolsPosition('bottom')
1081-
}}
1082-
as="button"
1083-
class={cx(
1084-
styles().settingsSubButton,
1085-
'tsqd-settings-menu-position-btn',
1086-
'tsqd-settings-menu-position-btn-bottom',
1087-
)}
1088-
>
1089-
<span>Bottom</span>
1090-
<ArrowDown />
1091-
</DropdownMenu.Item>
1092-
<DropdownMenu.Item
1093-
onSelect={() => {
1094-
setDevtoolsPosition('left')
1095-
}}
1096-
as="button"
1097-
class={cx(
1098-
styles().settingsSubButton,
1099-
'tsqd-settings-menu-position-btn',
1100-
'tsqd-settings-menu-position-btn-left',
1101-
)}
1102-
>
1103-
<span>Left</span>
1104-
<ArrowLeft />
1105-
</DropdownMenu.Item>
1106-
<DropdownMenu.Item
1107-
onSelect={() => {
1108-
setDevtoolsPosition('right')
1109-
}}
1110-
as="button"
1111-
class={cx(
1112-
styles().settingsSubButton,
1113-
'tsqd-settings-menu-position-btn',
1114-
'tsqd-settings-menu-position-btn-right',
1115-
)}
1066+
<DropdownMenu.RadioGroup
1067+
aria-label="Position settings"
1068+
value={props.localStore.position}
1069+
onChange={(value) =>
1070+
setDevtoolsPosition(value as DevtoolsPosition)
1071+
}
11161072
>
1117-
<span>Right</span>
1118-
<ArrowRight />
1119-
</DropdownMenu.Item>
1073+
<DropdownMenu.RadioItem
1074+
value="top"
1075+
class={cx(
1076+
styles().settingsSubButton,
1077+
'tsqd-settings-menu-position-btn',
1078+
'tsqd-settings-menu-position-btn-top',
1079+
)}
1080+
>
1081+
<span>Top</span>
1082+
<ArrowUp />
1083+
</DropdownMenu.RadioItem>
1084+
<DropdownMenu.RadioItem
1085+
value="bottom"
1086+
class={cx(
1087+
styles().settingsSubButton,
1088+
'tsqd-settings-menu-position-btn',
1089+
'tsqd-settings-menu-position-btn-bottom',
1090+
)}
1091+
>
1092+
<span>Bottom</span>
1093+
<ArrowDown />
1094+
</DropdownMenu.RadioItem>
1095+
<DropdownMenu.RadioItem
1096+
value="left"
1097+
class={cx(
1098+
styles().settingsSubButton,
1099+
'tsqd-settings-menu-position-btn',
1100+
'tsqd-settings-menu-position-btn-left',
1101+
)}
1102+
>
1103+
<span>Left</span>
1104+
<ArrowLeft />
1105+
</DropdownMenu.RadioItem>
1106+
<DropdownMenu.RadioItem
1107+
value="right"
1108+
class={cx(
1109+
styles().settingsSubButton,
1110+
'tsqd-settings-menu-position-btn',
1111+
'tsqd-settings-menu-position-btn-right',
1112+
)}
1113+
>
1114+
<span>Right</span>
1115+
<ArrowRight />
1116+
</DropdownMenu.RadioItem>
1117+
</DropdownMenu.RadioGroup>
11201118
</DropdownMenu.SubContent>
11211119
</DropdownMenu.Portal>
11221120
</DropdownMenu.Sub>
@@ -1146,54 +1144,47 @@ export const ContentView: Component<ContentViewProps> = (props) => {
11461144
'tsqd-settings-submenu',
11471145
)}
11481146
>
1149-
<DropdownMenu.Item
1150-
onSelect={() => {
1151-
props.setLocalStore('theme_preference', 'light')
1152-
}}
1153-
as="button"
1154-
class={cx(
1155-
styles().settingsSubButton,
1156-
props.localStore.theme_preference === 'light' &&
1157-
styles().themeSelectedButton,
1158-
'tsqd-settings-menu-position-btn',
1159-
'tsqd-settings-menu-position-btn-top',
1160-
)}
1161-
>
1162-
<span>Light</span>
1163-
<Sun />
1164-
</DropdownMenu.Item>
1165-
<DropdownMenu.Item
1166-
onSelect={() => {
1167-
props.setLocalStore('theme_preference', 'dark')
1147+
<DropdownMenu.RadioGroup
1148+
value={props.localStore.theme_preference}
1149+
onChange={(value) => {
1150+
props.setLocalStore('theme_preference', value)
11681151
}}
1169-
as="button"
1170-
class={cx(
1171-
styles().settingsSubButton,
1172-
props.localStore.theme_preference === 'dark' &&
1173-
styles().themeSelectedButton,
1174-
'tsqd-settings-menu-position-btn',
1175-
'tsqd-settings-menu-position-btn-bottom',
1176-
)}
1152+
aria-label="Theme preference"
11771153
>
1178-
<span>Dark</span>
1179-
<Moon />
1180-
</DropdownMenu.Item>
1181-
<DropdownMenu.Item
1182-
onSelect={() => {
1183-
props.setLocalStore('theme_preference', 'system')
1184-
}}
1185-
as="button"
1186-
class={cx(
1187-
styles().settingsSubButton,
1188-
props.localStore.theme_preference === 'system' &&
1189-
styles().themeSelectedButton,
1190-
'tsqd-settings-menu-position-btn',
1191-
'tsqd-settings-menu-position-btn-left',
1192-
)}
1193-
>
1194-
<span>System</span>
1195-
<Monitor />
1196-
</DropdownMenu.Item>
1154+
<DropdownMenu.RadioItem
1155+
value="light"
1156+
class={cx(
1157+
styles().settingsSubButton,
1158+
'tsqd-settings-menu-position-btn',
1159+
'tsqd-settings-menu-position-btn-top',
1160+
)}
1161+
>
1162+
<span>Light</span>
1163+
<Sun />
1164+
</DropdownMenu.RadioItem>
1165+
<DropdownMenu.RadioItem
1166+
value="dark"
1167+
class={cx(
1168+
styles().settingsSubButton,
1169+
'tsqd-settings-menu-position-btn',
1170+
'tsqd-settings-menu-position-btn-bottom',
1171+
)}
1172+
>
1173+
<span>Dark</span>
1174+
<Moon />
1175+
</DropdownMenu.RadioItem>
1176+
<DropdownMenu.RadioItem
1177+
value="system"
1178+
class={cx(
1179+
styles().settingsSubButton,
1180+
'tsqd-settings-menu-position-btn',
1181+
'tsqd-settings-menu-position-btn-left',
1182+
)}
1183+
>
1184+
<span>System</span>
1185+
<Monitor />
1186+
</DropdownMenu.RadioItem>
1187+
</DropdownMenu.RadioGroup>
11971188
</DropdownMenu.SubContent>
11981189
</DropdownMenu.Portal>
11991190
</DropdownMenu.Sub>
@@ -1221,51 +1212,49 @@ export const ContentView: Component<ContentViewProps> = (props) => {
12211212
styles().settingsMenu,
12221213
'tsqd-settings-submenu',
12231214
)}
1215+
aria-label="Hide disabled queries setting"
12241216
>
1225-
<DropdownMenu.Item
1226-
onSelect={() => {
1227-
props.setLocalStore('hideDisabledQueries', 'false')
1228-
}}
1229-
as="button"
1230-
class={cx(
1231-
styles().settingsSubButton,
1232-
props.localStore.hideDisabledQueries !== 'true' &&
1233-
styles().themeSelectedButton,
1234-
'tsqd-settings-menu-position-btn',
1235-
'tsqd-settings-menu-position-btn-show',
1236-
)}
1217+
<DropdownMenu.RadioGroup
1218+
value={props.localStore.hideDisabledQueries}
1219+
onChange={(value) =>
1220+
props.setLocalStore('hideDisabledQueries', value)
1221+
}
12371222
>
1238-
<span>Show</span>
1239-
<Show
1240-
when={
1241-
props.localStore.hideDisabledQueries !== 'true'
1242-
}
1223+
<DropdownMenu.RadioItem
1224+
value="false"
1225+
class={cx(
1226+
styles().settingsSubButton,
1227+
'tsqd-settings-menu-position-btn',
1228+
'tsqd-settings-menu-position-btn-show',
1229+
)}
12431230
>
1244-
<CheckCircle />
1245-
</Show>
1246-
</DropdownMenu.Item>
1247-
<DropdownMenu.Item
1248-
onSelect={() => {
1249-
props.setLocalStore('hideDisabledQueries', 'true')
1250-
}}
1251-
as="button"
1252-
class={cx(
1253-
styles().settingsSubButton,
1254-
props.localStore.hideDisabledQueries === 'true' &&
1255-
styles().themeSelectedButton,
1256-
'tsqd-settings-menu-position-btn',
1257-
'tsqd-settings-menu-position-btn-hide',
1258-
)}
1259-
>
1260-
<span>Hide</span>
1261-
<Show
1262-
when={
1263-
props.localStore.hideDisabledQueries === 'true'
1264-
}
1231+
<span>Show</span>
1232+
<Show
1233+
when={
1234+
props.localStore.hideDisabledQueries !== 'true'
1235+
}
1236+
>
1237+
<CheckCircle />
1238+
</Show>
1239+
</DropdownMenu.RadioItem>
1240+
<DropdownMenu.RadioItem
1241+
value="true"
1242+
class={cx(
1243+
styles().settingsSubButton,
1244+
'tsqd-settings-menu-position-btn',
1245+
'tsqd-settings-menu-position-btn-hide',
1246+
)}
12651247
>
1266-
<CheckCircle />
1267-
</Show>
1268-
</DropdownMenu.Item>
1248+
<span>Hide</span>
1249+
<Show
1250+
when={
1251+
props.localStore.hideDisabledQueries === 'true'
1252+
}
1253+
>
1254+
<CheckCircle />
1255+
</Show>
1256+
</DropdownMenu.RadioItem>
1257+
</DropdownMenu.RadioGroup>
12691258
</DropdownMenu.SubContent>
12701259
</DropdownMenu.Portal>
12711260
</DropdownMenu.Sub>
@@ -1961,6 +1950,9 @@ const QueryDetails = () => {
19611950
styles().detailsBody,
19621951
'tsqd-query-details-summary-container',
19631952
)}
1953+
role="status"
1954+
aria-live="polite"
1955+
aria-atomic="true"
19641956
>
19651957
<div class="tsqd-query-details-summary">
19661958
<pre>
@@ -2372,6 +2364,9 @@ const MutationDetails = () => {
23722364
styles().detailsBody,
23732365
'tsqd-query-details-summary-container',
23742366
)}
2367+
role="status"
2368+
aria-live="polite"
2369+
aria-atomic="true"
23752370
>
23762371
<div class="tsqd-query-details-summary">
23772372
<pre>
@@ -3521,15 +3516,15 @@ const stylesFactory = (
35213516
outline-offset: 2px;
35223517
outline: 2px solid ${colors.blue[800]};
35233518
}
3524-
`,
3525-
themeSelectedButton: css`
3526-
background-color: ${t(colors.purple[100], colors.purple[900])};
3527-
color: ${t(colors.purple[700], colors.purple[300])};
3528-
& svg {
3529-
color: ${t(colors.purple[700], colors.purple[300])};
3530-
}
3531-
&:hover {
3519+
&[data-checked] {
35323520
background-color: ${t(colors.purple[100], colors.purple[900])};
3521+
color: ${t(colors.purple[700], colors.purple[300])};
3522+
& svg {
3523+
color: ${t(colors.purple[700], colors.purple[300])};
3524+
}
3525+
&:hover {
3526+
background-color: ${t(colors.purple[100], colors.purple[900])};
3527+
}
35333528
}
35343529
`,
35353530
viewToggle: css`

0 commit comments

Comments
 (0)