Skip to content

Commit e5465c9

Browse files
committed
Create an article re: badges
1 parent 6c2e204 commit e5465c9

File tree

2 files changed

+279
-1
lines changed

2 files changed

+279
-1
lines changed

DESCRIPTION

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,10 @@ Suggests:
6161
spelling (>= 1.2),
6262
styler (>= 1.2.0),
6363
testthat (>= 3.1.0)
64-
Config/Needs/website: tidyverse/tidytemplate
64+
Config/Needs/website:
65+
purrr,
66+
tidyverse/tidytemplate,
67+
xml2
6568
Config/testthat/edition: 3
6669
Encoding: UTF-8
6770
Language: en-US
Lines changed: 275 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,275 @@
1+
---
2+
title: "Exploring badge accessibility"
3+
---
4+
5+
```{r, include = FALSE}
6+
knitr::opts_chunk$set(
7+
collapse = TRUE,
8+
comment = "#>"
9+
)
10+
```
11+
12+
```{r setup}
13+
library(usethis)
14+
```
15+
16+
Various functions in usethis insert a badge into a package's README file.
17+
A badge consists of an image with information about the package, which is usually hyperlinked to a location with further details.
18+
Here is a typical badge:
19+
20+
<!-- badges: start -->
21+
[![badge_example](https://img.shields.io/badge/badge%20label-badge%20message-yellowgreen)](https://shields.io/)
22+
<!-- badges: end -->
23+
24+
For example, the badge message might be "passing" or "failing", reflecting the `R CMD check` status of its current development state, and then link to the actual log file.
25+
Or the badge could display the current test coverage, as a percentage of lines, and then link to a site where one can explore test coverage line-by-line.
26+
27+
<!-- badges: start -->
28+
[![R-CMD-check](https://github.com/r-lib/usethis/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/r-lib/usethis/actions/workflows/R-CMD-check.yaml)
29+
[![Codecov test coverage](https://codecov.io/gh/r-lib/usethis/branch/main/graph/badge.svg)](https://app.codecov.io/gh/r-lib/usethis?branch=main)
30+
<!-- badges: end -->
31+
32+
A key point is that the badge often presents *dynamic* information.
33+
34+
We'd like to improve the user experience for those consuming the README using assistive technology, such as a screen reader.
35+
36+
There are at least two ways that usethis can influence this:
37+
38+
* The construction of the hyperlinked badge. For example, we control the alt
39+
text.
40+
* The image itself. We can encourage the badge providers to build accessibility
41+
into their badge SVGs. If the "native" badge is not accessible, usethis can
42+
substitute an accessible badge from a 3rd party, such as
43+
[shields.io](https://shields.io/).
44+
45+
This article is meant to gather badge facts in one place and facilitate a dialogue with those using assistive technology.
46+
47+
## Markdown image link
48+
49+
usethis currently inserts badges in a special "badge block" in the README, fenced with HTML comment tags.
50+
Within the badge block, each badge is a hyperlinked image, with alt text.
51+
Here is the basic form:
52+
53+
```
54+
[![alt_text](http://path/to/the/badge/image)](http://path/to/more/details)
55+
```
56+
57+
Note that the `alt_text` should be a static label explaining the badge's purpose, whereas the dynamic information is baked into the externally-served image.
58+
59+
usethis definitely controls this `alt_text`, so that is something I'd like feedback on.
60+
61+
## Badge image
62+
63+
Most badges these days tend to be SVG files, which is fortunate, since SVGs can carry attributes to support accessibility.
64+
We demonstrate this with a custom badge generated via the [shields.io](https://shields.io/) web service.
65+
66+
I will request a badge with this URL:
67+
68+
```
69+
https://img.shields.io/badge/my__label-my__message-orange
70+
```
71+
72+
Here it is as a badge, with the hyperlink set to <https://shields.io/>.
73+
The badge is inside an HTML comment block, like usethis does for README badges.
74+
I've prefixed every field I can influence with "my"; there are 3 such fields:
75+
76+
1. The alt text.
77+
2. The label. This static text appears on the left side of the badge, on a grey
78+
background, and describes the badge.
79+
3. The message. This text appears on the right side of the badge, on a colored
80+
background. This is often the dynamic part, where both the color and the text
81+
convey a dynamic fact, e.g. "passing" on a green background or "failing" on a
82+
red background.
83+
84+
<!-- badges: start -->
85+
[![my_alt_text](https://img.shields.io/badge/my__label-my__message-orange)](https://shields.io/)
86+
<!-- badges: end -->
87+
88+
Now we inspect the badge SVG.
89+
I apologize in advance for the amount of data displayed here, but it seems good to show one badge in full gory detail.
90+
Later, we will display badge information very selectively.
91+
92+
```{r R.options = list(tidyverse.quiet = TRUE)}
93+
library(xml2)
94+
library(purrr)
95+
96+
inspect_badge <- function(badge) {
97+
badge %>%
98+
read_xml() %>%
99+
as_list() %>%
100+
pluck("svg")
101+
}
102+
103+
inspect_badge("https://img.shields.io/badge/my__label-my__message-orange")
104+
```
105+
106+
It is my understanding that the two main pieces of metadata are the `title` and the `aria-label` attribute.
107+
Here I reveal just those two items from the badge:
108+
109+
```{r}
110+
inspect_badge <- function(badge) {
111+
x <- badge %>%
112+
read_xml() %>%
113+
as_list() %>%
114+
pluck("svg")
115+
list(
116+
title = pluck(x, "title", 1),
117+
`aria-label` = pluck(x, attr_getter("aria-label"))
118+
)
119+
}
120+
121+
inspect_badge("https://img.shields.io/badge/my__label-my__message-orange")
122+
```
123+
124+
This badge carries the same information in the `title` and in `aria-label`, which is "my_label: my_message".
125+
I would be interested to learn more about why the same information is included twice and if that is a good or bad thing for the screen reader experience.
126+
127+
### shields.io badges are accessible today
128+
129+
One of the reasons I inspected a shields.io badge is that this may provide a usable alternative for any service whose official badge is not (yet?) screen-reader-friendly.
130+
131+
The custom badge above is completely static.
132+
But shields.io also supports custom dynamic badges, when the necessary information (label, message, color) is available from a suitable JSON endpoint.
133+
Finally, and most relevant to usethis, shields.io offers pre-configured dynamic badges for the most commonly "badged" services, including GitHub Actions and Codecov.
134+
135+
Here is a shields.io badge for usethis's `R CMD check` workflow on GitHub Actions:
136+
137+
<!-- badges: start -->
138+
[![my_alt_text-R-CMD-check](https://img.shields.io/github/workflow/status/r-lib/usethis/R-CMD-check?label=my_label-R-CMD-check)](https://github.com/r-lib/usethis/actions/workflows/R-CMD-check.yaml)
139+
<!-- badges: end -->
140+
141+
Again, I am indicating fields I control with `my_alt_text` and `my_label`, so it's easier to get feedback on what usethis should do.
142+
143+
Here is the `title` and `aria-label` of the badge above:
144+
145+
```{r}
146+
inspect_badge("https://img.shields.io/github/workflow/status/r-lib/usethis/R-CMD-check?label=my_label-R-CMD-check")
147+
```
148+
149+
Now we will take inventory of the main badges inserted by usethis and where things stand re: accessibility.
150+
151+
## `R CMD check` status
152+
153+
We generally obtain the current `R CMD check` status from a GitHub Actions workflow.
154+
155+
Here is the official badge provided by GitHub:
156+
157+
<!-- badges: start -->
158+
[![R-CMD-check](https://github.com/r-lib/usethis/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/r-lib/usethis/actions/workflows/R-CMD-check.yaml)
159+
<!-- badges: end -->
160+
161+
Here is the `title` and `aria-label` of the badge above:
162+
163+
```{r}
164+
inspect_badge("https://github.com/r-lib/usethis/actions/workflows/R-CMD-check.yaml/badge.svg")
165+
```
166+
167+
At the time of writing (late December 2021), the badge does not include such information.
168+
169+
I have requested this in GitHub's Actions and Packages Feedback forum and the response from GitHub is encouraging.
170+
Hopefully the native badge will gain improved accessibility early in 2022.
171+
172+
<https://github.com/github/feedback/discussions/8974>
173+
174+
In the meantime, one could use a shields.io badge to report `R CMD check` status, as demonstrated in the previous section.
175+
A maintainer could do this as a one-off or, if the GitHub badge upgrade is slow in coming, we could implement it in `usethis::use_github_actions_badge()`.
176+
177+
## Package lifecycle
178+
179+
`usethis::use_lifecycle_badge()` declares the developmental stage of a package, using the framework from <https://lifecycle.r-lib.org/articles/stages.html>.
180+
This function already inserts a shields.io badge:
181+
182+
<!-- badges: start -->
183+
[![Lifecycle: stable](https://img.shields.io/badge/lifecycle-stable-brightgreen.svg)](https://lifecycle.r-lib.org/articles/stages.html#stable)
184+
<!-- badges: end -->
185+
186+
Here is the `title` and `aria-label` of the badge above:
187+
188+
```{r}
189+
inspect_badge("https://img.shields.io/badge/lifecycle-stable-brightgreen.svg")
190+
```
191+
192+
It's possible that usethis should be using a badge "owned" by the lifecycle package.
193+
I think we don't do so now, because declaring the lifecycle stage of a whole package does not necessarily imply the need to take a formal dependency on the lifecycle package, which is usually what causes badges to be copied into the `man/figures/` directory.
194+
195+
Also, the badges shipped by the lifecycle package are _not_ currently accessible, which is another reason not to use them.
196+
But I have opened an issue about this (<https://github.com/r-lib/lifecycle/issues/117>).
197+
This should be a relatively easy fix, since these are static badges.
198+
Once done, package maintainers would need to update the SVGs that are stored in `man/figures/`.
199+
200+
## CRAN status
201+
202+
`usethis::use_cran_badge()` places a badge that indicates what package version is available on CRAN.
203+
This badge is served by METACRAN (<https://www.r-pkg.org>) and maintainer Gábor Csárdi has already incorporated `aria-label` into the badges (in [this commit](https://github.com/metacran/metacranweb/commit/8287a21e6dc2bc50a2d8a7b5a5a56904ae1d04ff)).
204+
All available badges are listed [here](https://www.r-pkg.org/services).
205+
206+
Here's the badge placed by `usethis::use_cran_badge()`:
207+
208+
<!-- badges: start -->
209+
[![CRAN status](https://www.r-pkg.org/badges/version/usethis)](https://CRAN.R-project.org/package=usethis)
210+
<!-- badges: end -->
211+
212+
Here is the `title` and `aria-label` of the badge above:
213+
214+
```{r}
215+
inspect_badge("https://www.r-pkg.org/badges/version/usethis")
216+
```
217+
218+
At the time of writing (late December 2021), `aria-label` is present, but `title` is not.
219+
I would be interested to know if this is a good situation for those using a screen reader.
220+
221+
## Code coverage
222+
223+
`usethis::use_coverage(type = c("codecov", "coveralls", ...)` calls the internal helper `usethis:::use_codecov_badge()` to insert a badge for either the Codecov or Coveralls service.
224+
225+
Here are examples of those two badges (note that usethis does not use Coveralls, so I'm using a different package to demo):
226+
227+
<!-- badges: start -->
228+
[![Codecov test coverage](https://codecov.io/gh/r-lib/usethis/branch/main/graph/badge.svg)](https://app.codecov.io/gh/r-lib/usethis?branch=main)
229+
[![Coveralls test coverage](https://coveralls.io/repos/github/trinker/sentimentr/badge.svg?branch=master)](https://coveralls.io/github/trinker/sentimentr?branch=master)
230+
<!-- badges: end -->
231+
232+
Here are the `title` and `aria-label` of those badges::
233+
234+
```{r}
235+
inspect_badge("https://codecov.io/gh/r-lib/usethis/branch/main/graph/badge.svg")
236+
237+
inspect_badge("https://coveralls.io/repos/github/trinker/sentimentr/badge.svg?branch=master")
238+
```
239+
240+
At the time of writing (late December 2021), neither badge offers a `title` or `aria-label`.
241+
242+
Here are badges from shields.io for Codecov and Coveralls:
243+
244+
<!-- badges: start -->
245+
[![Codecov test coverage](https://img.shields.io/codecov/c/github/r-lib/usethis?label=test%20coverage&logo=codecov)](https://app.codecov.io/gh/r-lib/usethis?branch=main)
246+
[![Coveralls test coverage](https://coveralls.io/repos/github/trinker/sentimentr/badge.svg?branch=master)](https://img.shields.io/coveralls/github/trinker/sentimentr?logo=coveralls)
247+
<!-- badges: end -->
248+
249+
Here are the `title` and `aria-label` of the shields.io badges::
250+
251+
```{r}
252+
inspect_badge("https://img.shields.io/codecov/c/github/r-lib/usethis?label=test%20coverage&logo=codecov")
253+
254+
inspect_badge("https://img.shields.io/coveralls/github/trinker/sentimentr?logo=coveralls")
255+
```
256+
257+
## Bioconductor
258+
259+
If a package is on Bioconductor, `usethis::use_bioc_badge()` can be used to insert a badge for its Bioconductor build status.
260+
261+
Here is such a badge:
262+
263+
<!-- badges: start -->
264+
[![BioC status](http://www.bioconductor.org/shields/build/release/bioc/biocthis.svg)](https://bioconductor.org/checkResults/release/bioc-LATEST/biocthis)
265+
<!-- badges: end -->
266+
267+
Here is the `title` and `aria-label` of that badge:
268+
269+
```{r}
270+
inspect_badge("http://www.bioconductor.org/shields/build/release/bioc/biocthis.svg")
271+
```
272+
273+
At the time of writing (late December 2021), the badge does not have a `title` or `aria-label`.
274+
275+
It's not immediately clear how to resolve this, but I suspect that Bioconductor would be receptive to a request to create more accessible badges.

0 commit comments

Comments
 (0)