Skip to content

Fix accessibility issues in SGA#87

Open
amir-qayyum-khan wants to merge 1 commit intomitodl:masterfrom
amir-qayyum-khan:accessibility_fix
Open

Fix accessibility issues in SGA#87
amir-qayyum-khan wants to merge 1 commit intomitodl:masterfrom
amir-qayyum-khan:accessibility_fix

Conversation

@amir-qayyum-khan
Copy link

In this PR I fixed accessibility related issues. Added necessary ARIA tags into code.

@carsongee and @pdpinch please review it

Thanks

@pdpinch
Copy link
Member

pdpinch commented Apr 28, 2015

@amir-qayyum-arbisoft it looks like this needs a rebase?

FYI, @bdero is going to put this on sandbox and we'll see if we can get it reviewed by an MIT accessibility specialist.

@bdero
Copy link

bdero commented Apr 30, 2015

This is on sandxox2o

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A loop would probably be overkill for this, but please store the element before making these calls:

var uploadElement =  $(content).find(".upload");
uploadElement.attr(/* params */)
// ...etc...

@amir-qayyum-khan
Copy link
Author

@pdpinch and @bdero done with fix

@pdpinch
Copy link
Member

pdpinch commented May 27, 2015

@amir-qayyum-khan are there any changes we should consider for this, based on what you heard from edX?

@amir-qayyum-khan amir-qayyum-khan force-pushed the accessibility_fix branch 3 times, most recently from c2119c4 to d659fee Compare June 9, 2015 12:55
@tssheth
Copy link

tssheth commented Jul 23, 2015

How might I test this?

@amir-qayyum-khan
Copy link
Author

@jetej You can use screen reading tools like chromeVox (A chrome browser plugin) or command+F5 on mac to verify this PR.
Also read http://edx-partner-course-staff.readthedocs.org/en/latest/getting_started/accessibility.html

@tssheth
Copy link

tssheth commented Jul 24, 2015

Seems to work ok. I was able to use VoiceOver with both the student and instructor UI.

@pdpinch
Copy link
Member

pdpinch commented Jul 29, 2015

We'll still need another round of accessibility review after this, but this seems worth merging.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: should these be "upload_label"

@pdpinch
Copy link
Member

pdpinch commented Jul 29, 2015

Let's merge after the typo fix. This will all need another round of accessibility review afterwards, but this is an improvement.

@amir-qayyum-khan amir-qayyum-khan force-pushed the accessibility_fix branch 2 times, most recently from 31673b1 to b02665d Compare July 30, 2015 11:48
@amir-qayyum-khan
Copy link
Author

@pdpinch issue fixed

@amir-qayyum-khan amir-qayyum-khan changed the title fix accessibility issues in code Fix accessibility issues in SGA Jul 30, 2015
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be tabindex="-1" ?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tabindex="-1"

@pdpinch pdpinch assigned pdpinch and unassigned bdero Aug 14, 2015
@pdpinch pdpinch assigned amir-qayyum-khan and unassigned pdpinch Aug 14, 2015
@amir-qayyum-khan amir-qayyum-khan force-pushed the accessibility_fix branch 2 times, most recently from 2d731a0 to a138ad5 Compare August 24, 2015 11:28
@amir-qayyum-khan
Copy link
Author

Done @pdpinch

@pdpinch
Copy link
Member

pdpinch commented Aug 4, 2017

@amir-qayyum-khan not urgent, but could you rebase this sometime? I'm not sure if it's still relevant, but I'd like to clean this up.

@pdpinch
Copy link
Member

pdpinch commented Apr 9, 2018

@amir-qayyum-khan do you know if we have an issue for this?

@amir-qayyum-khan
Copy link
Author

I dont think so @pdpinch

@pdpinch
Copy link
Member

pdpinch commented Nov 26, 2018

@amir-qayyum-khan can you address the merge conflicts?

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aims to improve accessibility in the Staff Graded Assignment (SGA) module by adding ARIA attributes and making semantic HTML improvements. While the intent is good, several ARIA attributes are misapplied or used incorrectly, which could confuse assistive technology users rather than help them.

Key changes include:

  • Addition of ARIA attributes (role, aria-live, aria-describedby, aria-label) throughout templates
  • Improved table semantic structure with proper thead/tbody elements
  • Enhanced focus management for error messages in JavaScript
  • Removal of aria-hidden attributes from modal sections

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 12 comments.

File Description
edx_sga/templates/staff_graded_assignment/show.html Added ARIA attributes to various elements, improved table structure with thead/tbody, removed aria-hidden from modals, and wrapped text in span elements
edx_sga/templates/staff_graded_assignment/edit.html Changed list structure from ul/li to div elements, added aria-describedby to inputs, added role="form" to container, and included aria-label for settings tab
edx_sga/static/js/src/edx_sga.js Added progressbar ARIA attributes to upload element, implemented focus management for error messages, and added aria-valuenow/aria-valuetext for progress updates

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

form.find('.error').html('<br/>Grade must be positive.');
form.find('.error').focus();
} else if (score > max_score) {
form.find('.error').html('<br/>Maximum score is ' + max_score);
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent focus management: the error message is missing a .focus() call here, while all other validation error cases (lines 209, 212, 215) properly set focus to the error element for accessibility. Add form.find('.error').focus(); after line 217 to maintain consistency and ensure screen reader users are notified of this validation error.

Suggested change
form.find('.error').html('<br/>Maximum score is ' + max_score);
form.find('.error').html('<br/>Maximum score is ' + max_score);
form.find('.error').focus();

Copilot uses AI. Check for mistakes.

<div class="sga-block" data-state="{{ student_state }}" data-max-size="{{ max_file_size }}"
data-staff="{{ is_course_staff }}">
data-staff="{{ is_course_staff }}" role="article" aria-describedby="title">
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The aria-describedby="title" reference on line 4 points to an element with id="title" on line 7, but this element is inside a script template and may not exist in the DOM when the outer div is rendered. The referenced element is rendered dynamically via JavaScript template, so it won't be available when the page initially loads. This creates a broken ARIA reference. Consider moving the role and aria-describedby to the dynamically rendered content inside the template, or ensure the title element exists before the aria-describedby reference.

Copilot uses AI. Check for mistakes.
</tr>
<thead>
<tr>
<th>{% trans "Module Fields" %}</th>
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The table has only one column header but two columns of data (name and field value). The <thead> should have a <th> for each column to properly describe the table structure for screen readers. Add a second <th> for the field value column, or consider restructuring as a definition list if this is meant to be a list of name-value pairs.

Suggested change
<th>{% trans "Module Fields" %}</th>
<th>{% trans "Field Name" %}</th>
<th>{% trans "Field Value" %}</th>

Copilot uses AI. Check for mistakes.
</td>
<td>
<div class="upload">
<div class="upload" aria-live="assertive" role="alert" tabindex="-1">
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar issue as line 36: role="alert", aria-live="assertive", and tabindex="-1" are incorrectly applied to this static upload container. These ARIA attributes should only be used for dynamic announcements and status messages, not for the container element itself. Remove these attributes from this div.

Suggested change
<div class="upload" aria-live="assertive" role="alert" tabindex="-1">
<div class="upload">

Copilot uses AI. Check for mistakes.
style="height: 80%" id="{{ id }}-debug">
<div class="inner-wrapper" style="color: black">
<header><h2>{% trans "Staff Debug" %}</h2></header>
<header role="banner"><h2>{% trans "Staff Debug" %}</h2></header>
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The role="banner" attribute is incorrectly used here. The banner role should be used for the main header of the page/site, not for modal headers. Each page should typically have only one banner landmark. This header is within a modal dialog and should not use the banner role. Consider removing this role attribute.

Suggested change
<header role="banner"><h2>{% trans "Staff Debug" %}</h2></header>
<header><h2>{% trans "Staff Debug" %}</h2></header>

Copilot uses AI. Check for mistakes.
</section>

<section aria-hidden="true" class="modal grade-modal" id="{{ id }}-enter-grade">
<section class="modal grade-modal" id="{{ id }}-enter-grade">
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Extra whitespace before the class attribute. Should be <section class="modal grade-modal" instead of <section class="modal grade-modal" (note the double space).

Suggested change
<section class="modal grade-modal" id="{{ id }}-enter-grade">
<section class="modal grade-modal" id="{{ id }}-enter-grade">

Copilot uses AI. Check for mistakes.
Comment on lines +11 to +12
<label for="file_uploaded"><b>File uploaded<span class="sr">&nbsp;download link</span></b></label>
<a href="<%= downloadUrl %>" id="file_uploaded"><%= uploaded.filename %></a>
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The <label> element is being used incorrectly here. Labels should be associated with form controls (input, select, textarea), not with links. The uploaded file link is not a form input. Consider using a <span> or removing the label wrapper entirely, and rely on the semantic meaning of the link text itself. The screen reader text addition is good, but the label wrapper is semantically incorrect.

Suggested change
<label for="file_uploaded"><b>File uploaded<span class="sr">&nbsp;download link</span></b></label>
<a href="<%= downloadUrl %>" id="file_uploaded"><%= uploaded.filename %></a>
<span><b>File uploaded<span class="sr">&nbsp;download link</span></b></span>
<a href="<%= downloadUrl %>" id="file_uploaded" aria-label="Download uploaded file: <%= uploaded.filename %>"><%= uploaded.filename %></a>

Copilot uses AI. Check for mistakes.
<td>
<% if (assignment.may_grade) { %>
<a class="enter-grade-button button" href="#{{ id }}-enter-grade">
<a class="enter-grade-button button" href="#{{ id }}-enter-grade" role="button">
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Links should not have role="button". This creates confusion for assistive technology users as the element is semantically a link (using an anchor tag with href). If this needs to behave like a button, consider using an actual <button> element instead. Otherwise, keep it as a link without the role attribute.

Suggested change
<a class="enter-grade-button button" href="#{{ id }}-enter-grade" role="button">
<a class="enter-grade-button button" href="#{{ id }}-enter-grade">

Copilot uses AI. Check for mistakes.
<span id="upload_label">{% trans "Upload your assignment" %}</span>
<% } %>
<div class="upload">
<div class="upload" aria-describedby="upload_label" role="alert" aria-live="assertive" tabindex="-1">
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The role="alert", aria-live="assertive", and tabindex="-1" attributes are misapplied to this upload container. The role="alert" is meant for important, time-sensitive messages that should interrupt the user, not for static UI containers. The upload div doesn't receive programmatic focus in the JavaScript code (only error elements do), making tabindex="-1" unnecessary. Remove these ARIA attributes from this div - they should only be applied to actual dynamic status/error message elements.

Suggested change
<div class="upload" aria-describedby="upload_label" role="alert" aria-live="assertive" tabindex="-1">
<div class="upload" aria-describedby="upload_label">

Copilot uses AI. Check for mistakes.
Comment on lines +4 to +15
<div class="list-input settings-list">
{% for field, value, validator in fields %}
<li class="field comp-setting-entry metadata_entry">
<div class="field comp-setting-entry metadata_entry">
<div class="wrapper-comp-setting">
<label class="label setting-label"
<label class="label setting-label"
for="{{ field.name }}_input">{{ field.display_name }}</label>
<input class="input setting-input" type="text"
id="{{ field.name }}_input" name="{{ field.name}}"
<input class="input setting-input" type="text" aria-describedby="{{ field.name }}_hint"
id="{{ field.name }}_input" name="{{ field.name}}"
value="{{ value }}" data-validator="{{ validator }}"/>
</div>
<span class="tip setting-help">{{ field.help }}</span>
</li>
<span id="{{ field.name }}_hint" class="tip setting-help">{{ field.help }}</span>
</div>
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changing the semantic structure from <ul> and <li> to <div> elements reduces the semantic meaning and accessibility of the list. The original structure communicated that these were a list of settings to screen readers. Consider keeping the <ul> and <li> structure for better semantics, or if a div structure is required, add role="list" and role="listitem" to maintain the semantic information.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants