Add ARIA labels to progressbars

People using screen readers might have a hard time knowing what a
progressbar is about unless we provide a label for it. Axe was reporting
failures like:

```
aria-progressbar-name: ARIA progressbar nodes must have an accessible
name (serious)
https://dequeuniversity.com/rules/axe/4.10/aria-progressbar-name?application=axeAPI
The following 1 node violate this rule:

  Selector: .progress
  HTML: <div class="progress" role="progressbar" tabindex="0"
             aria-valuenow="0.0" aria-valuemin="0" aria-valuemax="100">
          <div class="progress-meter" style="width: 0.0%"></div>
        </div>
  Fix any of the following:
  - aria-label attribute does not exist or is empty
  - aria-labelledby attribute does not exist, references
    elements that do not exist or references elements that are empty
  - Element has no title attribute
```

Note that, in the case of the ballot progressbar, it's easier to use
`aria-labelledby`, while in other place it's easier to use `aria-label`,
so we using the easier solution in each scenario.
This commit is contained in:
Javi Martín
2025-02-25 14:11:00 +01:00
parent 48593a19ea
commit 45c74681c4
6 changed files with 16 additions and 5 deletions

View File

@@ -2,7 +2,7 @@
<h5><%= t("milestones.index.progress") %></h5>
<div class="margin">
<%= progress_tag_for(primary_progress_bar) %>
<%= progress_tag_for(primary_progress_bar, label: t("milestones.index.progress")) %>
</div>
<% if secondary_progress_bars.any? %>
@@ -13,7 +13,7 @@
<%= progress_bar.title %>
</div>
<div class="small-12 medium-6 large-8 column end">
<%= progress_tag_for(progress_bar) %>
<%= progress_tag_for(progress_bar, label: progress_bar.title) %>
</div>
</div>
<% end %>

View File

@@ -19,11 +19,12 @@ class Milestones::ProgressBarsComponent < ApplicationComponent
milestoneable.secondary_progress_bars
end
def progress_tag_for(progress_bar)
def progress_tag_for(progress_bar, label:)
text = number_to_percentage(progress_bar.percentage, precision: 0)
tag.div class: "progress",
role: "progressbar",
"aria-label": label,
"aria-valuenow": progress_bar.percentage,
"aria-valuetext": "#{progress_bar.percentage}%",
"aria-valuemax": ProgressBar::RANGE.max,

View File

@@ -2,7 +2,7 @@
<%= sanitize(ballot.amount_progress(heading)) %>
</p>
<div class="progress" role="progressbar" tabindex="0"
<div class="progress" role="progressbar" tabindex="0" aria-labelledby="total_amount"
aria-valuenow="<%= ballot.percentage_spent(heading) %>" aria-valuemin="0" aria-valuemax="100">
<div class="progress-meter"
style="width: <%= ballot.percentage_spent(heading) %>%">

View File

@@ -37,7 +37,8 @@
<%= next_goal_progress %>%
</div>
<div class="progress" role="progressbar" tabindex="0" aria-valuenow="0" aria-valuemin="0"
aria-valuetext="<%= "#{next_goal_progress}%" %>" aria-valuemax="100">
aria-valuetext="<%= "#{next_goal_progress}%" %>" aria-valuemax="100"
aria-label="<%= t("layouts.dashboard.proposal_totals.current_goal") %>">
<div class="progress-meter" style="width: <%= next_goal_progress %>%"></div>
</div>
</div>

View File

@@ -18,6 +18,7 @@ describe Milestones::ProgressBarsComponent do
expect(page).to have_content "Progress"
expect(page).to have_css "[role=progressbar]", count: 1
expect(page).to have_css "[role=progressbar][aria-label='Progress']"
end
it "renders both main and secondary progress bars" do
@@ -29,5 +30,7 @@ describe Milestones::ProgressBarsComponent do
expect(page).to have_content "Progress"
expect(page).to have_content "Build laboratory"
expect(page).to have_css "[role=progressbar]", count: 2
expect(page).to have_css "[role=progressbar][aria-label='Progress']"
expect(page).to have_css "[role=progressbar][aria-label='Build laboratory']"
end
end

View File

@@ -108,6 +108,12 @@ describe "Ballots" do
create(:budget_investment, :selected, heading: new_york, price: 20000, title: "Paint cabs black")
visit budget_investments_path(budget, heading_id: new_york)
within("#progress_bar") do
expect(page).to have_css "#total_amount", exact_text: "AMOUNT SPENT €0 / TOTAL BUDGET €1,000,000"
expect(page).to have_css "[role=progressbar][aria-labelledby='total_amount']"
end
add_to_ballot("Bring back King Kong")
within("#progress_bar") do