Where: frontend-app-course-authoring, Settings → Grading
(${APPS}/<mount>/course/<key>/settings/grading). Measured on Tutor main,
2026-09-08, on a fresh course (default Pass/Fail range).
Finding: axe reports two critical WCAG 2.2 AA violations in the editor's own
controls, independent of authored content:
button-name (1 node per draggable boundary): the range handles
(button.grading-scale-segment-btn-resize[role="slider"]) carry
aria-valuemin/max/now but no accessible name, so a screen reader announces
"slider, 50" with no indication of which grade boundary it moves.
label (3 nodes on the default range, one per segment): the segment name
fields (input[data-testid="grading-scale-segment-input"]) have no label,
placeholder, or aria-label; the failing bucket's disabled field included.
Suggested fix: give each handle an aria-label naming the boundary it moves
(e.g. "Boundary between A and B"), and each segment field an aria-label
("Grade name") — the range text beside it is not associated with the input.
Where:
frontend-app-course-authoring, Settings → Grading(
${APPS}/<mount>/course/<key>/settings/grading). Measured on Tutormain,2026-09-08, on a fresh course (default Pass/Fail range).
Finding: axe reports two critical WCAG 2.2 AA violations in the editor's own
controls, independent of authored content:
button-name(1 node per draggable boundary): the range handles(
button.grading-scale-segment-btn-resize[role="slider"]) carryaria-valuemin/max/nowbut no accessible name, so a screen reader announces"slider, 50" with no indication of which grade boundary it moves.
label(3 nodes on the default range, one per segment): the segment namefields (
input[data-testid="grading-scale-segment-input"]) have no label,placeholder, or
aria-label; the failing bucket's disabled field included.Suggested fix: give each handle an
aria-labelnaming the boundary it moves(e.g. "Boundary between A and B"), and each segment field an
aria-label("Grade name") — the range text beside it is not associated with the input.