Applications Shiny accessibles : étiquettes, ARIA, clavier et contraste pour WCAG
Faites fonctionner une application Shiny pour les utilisateurs au clavier et de lecteur d’écran et réussissez un audit WCAG 2.1 AA : de vraies étiquettes d’entrée, ARIA et aria-live seulement là où le HTML est insuffisant, une pleine utilisabilité au clavier, un contraste des couleurs suffisant avec bslib, et des graphiques et tableaux accessibles.
Rendez une application Shiny utilisable par tout le monde et réussissez un audit WCAG 2.1 AA, Section 508 ou European Accessibility Act. Donnez à chaque entrée une vraie étiquette, n’ajoutez ARIA et une région aria-live que là où le HTML est insuffisant, gardez toute l’application utilisable au clavier, respectez les minimums de contraste des couleurs avec bslib et ne signalez jamais par la couleur seule, et rendez les graphiques et les tableaux compatibles avec les lecteurs d’écran grâce au texte alternatif et à un tableau de données de repli.
- Chaque entrée a besoin d’une vraie étiquette visible. L’argument
labelde Shiny rend déjà un<label>en bonne et due forme, lié à l’entrée — passez donc une vraie étiquette, jamais un simple placeholder. Ici, l’essentiel de l’accessibilité ne consiste pas à lutter contre le framework. - Ne recourez à ARIA que là où le HTML est insuffisant. Le cas majeur est une région
aria-livepour qu’un lecteur d’écran annonce un résultat qui a changé sans déplacer le focus ;tagAppendAttributes()ajouteroleetaria-*à n’importe quelle balise. - Tout doit fonctionner au clavier. Un ordre de focus logique, un anneau de focus visible, aucun contrôle réservé à la souris — les contrôles Shiny natifs sont utilisables au clavier par défaut, donc les échecs viennent des widgets personnalisés que vous ajoutez.
- Respectez le contraste minimum et ne signalez jamais par la couleur seule.
bslib::bs_theme()définit des couleurs accessibles en un seul endroit ; ajoutez du texte, une icône ou une forme pour qu’un indice rouge/vert ne soit pas le seul indice. - Rendez les graphiques et les tableaux perceptibles. Donnez un
altàrenderPlot(), proposez un tableau de données de repli pour les chiffres, et balisez les tableaux avec un<caption>etscope. Une application rapide et fluide est en soi plus accessible — la leçon sur les performances est l’autre moitié de cette paire.
Introduction
Un utilisateur au clavier appuie sur Tab pour entrer dans votre application et ne peut jamais atteindre le filtre — celui-ci ne répond qu’à un clic de souris. Un utilisateur de lecteur d’écran arrive sur la zone de recherche et entend « zone d’édition, vide », parce que la seule étiquette du champ est un placeholder gris qui disparaît dès qu’il tape. Votre tableau de bord recalcule un chiffre clé et il n’apprend jamais qu’il a changé, parce que rien ne l’a annoncé. Chacun de ces utilisateurs est désormais exclu de la seule chose pour laquelle votre application existe.
L’accessibilité, c’est ainsi que vous cessez de les exclure — et pour un nombre croissant d’applications, c’est aussi la loi. WCAG (Web Content Accessibility Guidelines), actuellement en version 2.1, est le standard de référence, publié par le W3C. Il définit trois niveaux de conformité — A, AA et AAA — et AA (le niveau intermédiaire) est celui que visent les réglementations et celui que vous devriez viser. Aux États-Unis, la Section 508 impose la conformité WCAG aux agences fédérales et à leurs prestataires ; dans l’Union européenne, l’European Accessibility Act (Directive 2019/882) étend les obligations d’accessibilité à un large éventail de produits et services numériques du secteur privé à partir de juin 2025. ARIA (Accessible Rich Internet Applications) est la spécification W3C complémentaire — les attributs HTML supplémentaires qui décrivent les widgets personnalisés et les changements dynamiques aux technologies d’assistance quand le HTML simple ne le peut pas ; ses modèles pratiques figurent dans le WAI-ARIA Authoring Practices Guide.
Bonne nouvelle pour les développeurs Shiny : vous partez plus près de la conformité que vous ne le pensez. Les entrées standard de Shiny produisent déjà un HTML correct et étiqueté. L’accessibilité consiste surtout à ne pas casser cela, et à ajouter délibérément quelques éléments — ARIA là où c’est vraiment nécessaire, l’utilisabilité au clavier pour tout ce qui est personnalisé, un contraste suffisant et du texte alternatif. Cette leçon est cette liste de contrôle, dans l’ordre où vous l’appliquez.
Le code ci-dessous est de l’interface (UI) et de la logique server Shiny — il a besoin d’une session R active et d’une application en fonctionnement, ce qu’une page web statique ne peut pas héberger. Rien ne s’exécute donc sur cette page : copiez n’importe quel bloc dans une vraie application et exécutez-le localement. La preuve est dans l’exécution — parcourez l’application avec Tab, la souris débranchée, activez un lecteur d’écran, et lancez un audit automatisé ; the runtime is the judge de son accessibilité réelle.
À qui s’adresse l’accessibilité
WCAG organise chaque exigence selon quatre principes — leur acronyme anglais est POUR (perceivable, operable, understandable, robust) — et il est utile d’avoir la vue d’ensemble avant de se plonger dans les correctifs, car chaque correctif ci-dessous en sert un :
| Principe | Ce que cela signifie | À quoi cela ressemble dans Shiny |
|---|---|---|
| Perceptible | Les utilisateurs peuvent percevoir le contenu, quels que soient leurs sens | Des étiquettes lisibles par un lecteur d’écran, du texte alternatif sur les graphiques, un contraste suffisant |
| Utilisable | Les utilisateurs peuvent utiliser l’interface, quelle que soit leur façon de naviguer | Chaque contrôle atteignable et utilisable au clavier |
| Compréhensible | L’interface se comporte de façon prévisible et s’explique d’elle-même | Des étiquettes claires, des mises à jour annoncées, des messages d’erreur bienveillants |
| Robuste | Les technologies d’assistance peuvent interpréter le balisage de façon fiable | Un HTML valide et sémantique et un ARIA correct |
Vous ne concevez pas pour un cas marginal. Un contenu perceptible et utilisable aide les utilisateurs malvoyants et aveugles, les personnes ayant un handicap moteur qui ne touchent jamais une souris, les utilisateurs daltoniens et — parce qu’une bonne structure, des légendes et des réponses rapides aident tout le monde — chaque utilisateur sur un téléphone en plein soleil ou avec une connexion lente. Visez AA ; considérez AAA comme un bonus sur des critères spécifiques, pas comme un objectif général.
Commencez par des entrées étiquetées et sémantiques
L’échec d’accessibilité le plus courant, c’est une entrée qu’un lecteur d’écran ne peut pas nommer. Shiny vous offre le correctif gratuitement : chaque entrée standard produit un vrai <label> lié au contrôle dès que vous passez son argument label. Ceci :
selectInput("region", "Region", choices = c("North", "South", "East", "West"))produit un balisage avec une étiquette correcte et associée :
<label class="control-label" id="region-label" for="region">Region</label>
<select id="region" class="shiny-input-select">…</select>Le for="region" de l’étiquette, mis en correspondance avec l’id="region" de l’entrée, est exactement ce qu’un lecteur d’écran lit à voix haute — « Region, zone de liste modifiable ». (Le selectInput de Shiny embarque même un plugin d’accessibilité selectize.) La règle est donc simple : donnez toujours à une entrée un label significatif.
L’anti-modèle consiste à utiliser un placeholder à la place d’une étiquette :
# BAD: no label — a screen reader announces "edit text, blank"
textInput("q", label = NULL, placeholder = "Search products")Le texte du placeholder n’est pas une étiquette : il disparaît dès que l’utilisateur tape, il échoue au contraste minimum dans la plupart des thèmes, et beaucoup de lecteurs d’écran l’ignorent. Si votre design ne peut vraiment pas afficher d’étiquette visible, donnez plutôt à l’entrée un nom accessible avec aria-label — mais une étiquette visible vaut mieux pour tout le monde, alors préférez-la :
# If a visible label truly can't be shown, name the INPUT itself with aria-label.
# tagAppendAttributes() targets textInput()'s outer <div> by default, so pass
# .cssSelector = "input" to put the name on the control a screen reader reads.
textInput("q", label = NULL) |>
tagAppendAttributes(.cssSelector = "input", `aria-label` = "Search products")Un aria-label sur le <div> englobant ne nommerait pas l’entrée — le nom accessible doit se poser sur l’élément <input> lui-même, ce que sélectionne précisément .cssSelector = "input".
Le même piège guette les boutons à icône seule — un bouton loupe sans texte est un bouton vide pour un lecteur d’écran. Nommez-le :
actionButton("go", label = "", icon = icon("magnifying-glass"),
`aria-label` = "Search")Cela produit <button … aria-label="Search">, si bien que le contrôle annonce « Search, bouton » au lieu de rien.
N’ajoutez ARIA que là où le HTML est insuffisant
Les éléments HTML natifs — un <label>, un <button>, un <nav> — portent leur sens gratuitement, et vous devriez les utiliser avant de recourir à ARIA. La première règle d’ARIA est n’utilisez pas ARIA si un simple élément HTML fait déjà l’affaire. Mais deux situations en ont réellement besoin dans une application Shiny.
Une région live pour une sortie dynamique. Quand Shiny recalcule une sortie, le DOM change en silence — les utilisateurs voyants voient le nouveau chiffre, mais un lecteur d’écran ne dit rien à moins que vous ne marquiez la région comme live. Une région aria-live="polite" demande à la technologie d’assistance d’annoncer les mises à jour sans voler le focus. Enveloppez la sortie (ou un message de statut dédié) dans une telle région :
# UI: a polite live region. Use "visually-hidden" if you don't want it shown.
div(class = "visually-hidden", `aria-live` = "polite",
textOutput("status_msg"))
# server: updating the text triggers the announcement
output$status_msg <- renderText({
paste(nrow(filtered()), "rows match your filter")
})Désormais, chaque fois que le filtre change le nombre de lignes, le lecteur d’écran annonce « 142 lignes correspondent à votre filtre ». Utilisez "polite" pour les mises à jour de routine (elle attend une pause) et "assertive" uniquement pour de véritables alertes qui méritent d’interrompre, comme une erreur — le guide MDN sur les régions live ARIA traite de la distinction.
Des attributs sur une balise quelconque. Quand vous construisez un balisage personnalisé, tagAppendAttributes() ajoute n’importe quel attribut role ou aria-* à une balise :
div(id = "notice") |>
tagAppendAttributes(role = "status", `aria-live` = "polite")
#> <div id="notice" role="status" aria-live="polite"></div>Utilisez-le pour ajouter un role de repère, un aria-describedby pointant vers un texte d’aide, ou un aria-label — mais seulement là où un élément natif ou la sortie propre de Shiny ne véhiculerait pas déjà le sens.
Gardez toute l’application utilisable au clavier
Chaque interaction doit fonctionner sans souris — c’est le critère Clavier (2.1.1) de WCAG, et c’est ainsi que les utilisateurs au clavier seul, ceux qui emploient un dispositif de commande (switch) et les utilisateurs de lecteur d’écran pilotent une application. Ici encore, Shiny aide : actionButton(), selectInput(), les liens et les autres contrôles standard sont des éléments natifs et focusables que Tab atteint et qu’Entrée ou Espace activent par défaut. Les échecs viennent de ce que vous ajoutez :
- Ne construisez pas de contrôles réservés à la souris. Un
<div>cliquable doté d’un gestionnaire JavaScriptonclicksans équivalent clavier est inatteignable par Tab. Utilisez plutôt un vraiactionButton()ou un<a>— ils sont focusables et utilisables gratuitement. - Gardez un anneau de focus visible. Jamais d’
outline: nonedans votre CSS sans remplacement ; l’anneau de focus, c’est ainsi qu’un utilisateur au clavier sait où il se trouve. Si vous restylez le focus, rendez le nouvel état clairement visible. - Préservez un ordre logique. Le focus suit l’ordre du DOM, alors disposez l’interface dans l’ordre où les utilisateurs devraient la parcourir, et évitez les valeurs
tabindexpositives (elles détournent l’ordre). N’utiliseztabindex = "0"que pour rendre focusable un contrôle véritablement personnalisé, ettabindex = "-1"pour déplacer le focus par programmation.
Un lien d’évitement — le premier élément focusable, qui permet aux utilisateurs au clavier de sauter par-dessus la navigation directement vers le contenu — est un ajout modeste et à forte valeur :
ui <- fluidPage(
tags$a(href = "#main", class = "visually-hidden-focusable",
"Skip to main content"),
# … navigation …
tags$main(id = "main",
# … app content …
)
)La classe visually-hidden-focusable garde le lien hors de vue jusqu’à ce qu’il reçoive le focus, puis le révèle — le modèle standard du lien d’évitement.
Respectez le contraste minimum, et ne signalez jamais par la couleur seule
Deux règles de couleur, toutes deux AA, toutes deux faciles à rater avec une palette de marque.
Contraste. Le critère Contraste (minimum) (1.4.3) de WCAG exige un ratio de 4.5:1 pour le texte normal et de 3:1 pour le grand texte et les composants d’interface par rapport à leur arrière-plan. Définissez les couleurs de votre application en un seul endroit avec bslib::bs_theme(), qui accepte des arguments de couleur nommés :
library(bslib)
ui <- fluidPage(
theme = bs_theme(
bg = "#ffffff", # page background
fg = "#212529", # body text — ~16:1 on white, comfortably AA
primary = "#0067b8" # links and primary buttons — meets 4.5:1 on white
),
# … app UI …
)Vérifiez chaque paire premier plan/arrière-plan avant de la livrer — le vérificateur de contraste WebAIM vous donne le ratio et un verdict réussite/échec au regard de AA. Un placeholder gris pâle ou un lien bleu clair sur blanc est le coupable habituel qui échoue. Le guide de thématisation de bslib couvre l’ensemble des variables de couleur et de typographie.
N’utilisez jamais la couleur comme seul signal. Le critère Utilisation de la couleur (1.4.1) de WCAG signifie qu’un utilisateur daltonien doit obtenir la même information que tout le monde. Un statut affiché uniquement sous forme de point rouge ou vert leur est invisible — associez la couleur à du texte, une icône ou une forme :
# BAD: colour is the only cue
span(style = "color:red;", "●")
# GOOD: colour + text + icon — the meaning survives without colour
span(class = "text-danger", icon("triangle-exclamation"), " Failed")Le même principe s’applique à l’intérieur de vos graphiques : distinguez les groupes par la forme ou le type de trait autant que par la couleur, et appuyez-vous sur des palettes adaptées au daltonisme (viridis, ou l’Okabe-Ito de ggplot2) plutôt que sur du rouge/vert brut.
Rendez les graphiques et les tableaux perceptibles
Un graphique est une image — pour un lecteur d’écran, ce n’est rien tant que vous ne le décrivez pas. Le Shiny moderne donne à renderPlot() un argument alt précisément pour cela :
output$trend <- renderPlot(
{
ggplot(sales, aes(month, revenue)) + geom_line()
},
alt = "Monthly revenue rising steadily from 1.2M in January to 3.4M in December 2024."
)Cela définit l’attribut alt sur l’image générée, si bien que la technologie d’assistance lit votre description au lieu de sauter un graphique vide. Décrivez les données et la tendance, pas « un graphique en courbes » — et notez qu’alt peut être une fonction, ce qui vous permet de la générer à partir des mêmes données réactives qui ont dessiné le graphique, en gardant les deux synchronisés.
Le texte alternatif transmet la forme des données, pas les chiffres. Pour les valeurs réelles, proposez un tableau de données de repli — les données sous-jacentes sous forme de vrai tableau que l’utilisateur peut lire ligne par ligne, ce qui fait aussi office de fonctionnalité que tout le monde apprécie :
output$trend_data <- renderTable(sales) # the numbers behind the chart
# … expose it under the plot, e.g. in a collapsible panel or a details/summaryPour les tableaux eux-mêmes, un balisage sémantique les rend navigables. Un <caption> nomme le tableau et les attributs scope indiquent à un lecteur d’écran quel en-tête régit chaque cellule :
tags$table(
tags$caption("Revenue by region, 2024"),
tags$thead(
tags$tr(
tags$th(scope = "col", "Region"),
tags$th(scope = "col", "Revenue")
)
),
tags$tbody(
tags$tr(tags$th(scope = "row", "North"), tags$td("1.2M")),
tags$tr(tags$th(scope = "row", "South"), tags$td("0.9M"))
)
)Si vous produisez un tableau interactif, DT accepte un argument caption (datatable(df, caption = "Revenue by region")) et reactable émet de l’ARIA pour ses colonnes triables — les deux sont plus accessibles qu’un tableau fait main, mais donnez-leur tout de même une légende et vérifiez-les avec l’audit ci-dessous.
Testez — trois passes
L’accessibilité se vérifie, elle ne se présume pas. Effectuez ces passes dans l’ordre ; chacune détecte ce que les autres manquent.
- Clavier seul. Débranchez la souris (ou refusez simplement de l’utiliser) et parcourez toute l’application avec Tab. Pouvez-vous atteindre et utiliser chaque contrôle ? L’anneau de focus est-il visible à chaque étape ? Entrée/Espace activent-ils les boutons, et Échap ferme-t-elle une fenêtre modale ? Tout ce que vous ne pouvez pas atteindre est un point bloquant.
- Un lecteur d’écran. Activez-en un et écoutez : VoiceOver est livré avec macOS (Cmd+F5), et NVDA est un lecteur Windows gratuit et excellent. Chaque champ annonce-t-il une étiquette ? Les mises à jour dynamiques sont-elles annoncées via votre région live ? Un graphique lit-il son texte alternatif ?
- Un audit automatisé. Lancez axe DevTools (une extension de navigateur) ou la catégorie accessibilité du Lighthouse intégré à Chrome. Ils signalent instantanément les échecs mécaniques — étiquettes manquantes, contraste faible, repères manquants, ARIA invalide.
Les outils automatisés sont rapides mais partiels : ils détectent qu’une étiquette est manquante, pas si une étiquette est pertinente, et ils ne peuvent pas vous dire si l’application est réellement utilisable. Ils complètent les passes manuelles ; ils ne les remplacent pas. Faites les trois.
Problèmes fréquents
Un lecteur d’écran lit votre entrée comme « vide » ou « sans étiquette ». Vous avez mis label = NULL, généralement pour vous reposer sur un placeholder. Le texte du placeholder n’est pas un nom accessible — il disparaît à la frappe et les lecteurs le sautent souvent. Donnez à l’entrée un label réel et visible ; si le design l’interdit vraiment, ajoutez un nom accessible sur le contrôle avec tagAppendAttributes(.cssSelector = "input", `aria-label` = "…") — sans .cssSelector, l’attribut atterrit sur le <div> englobant, pas sur l’<input>, et le champ reste sans nom. Un bouton à icône seule se nomme de la même façon, mais sur le bouton lui-même.
Votre résultat se met à jour en silence pour les utilisateurs de lecteur d’écran. Un textOutput() ou plotOutput() normal change le DOM sans l’annoncer. Enveloppez la sortie — ou un court message de statut à côté — dans une région aria-live="polite" pour que la technologie d’assistance énonce le changement. Réservez "assertive" aux vraies alertes (une erreur), car elle interrompt ce que l’utilisateur est en train de faire.
Lighthouse signale un contraste faible alors même que vous avez défini les couleurs de votre marque. Une couleur primaire de marque ou un placeholder pâle échoue souvent au ratio 4.5:1 pour le texte normal. Testez la paire premier plan/arrière-plan exacte dans le vérificateur WebAIM et assombrissez jusqu’à ce qu’elle passe — en vous rappelant que le grand texte et les composants d’interface n’ont besoin que de 3:1, si bien qu’un gros titre peut passer là où le texte courant sur la même couleur échoue.
Questions fréquentes
En partie, et plus que la plupart des frameworks. Les entrées standard de Shiny produisent de vrais éléments <label> liés à leurs contrôles, selectInput() embarque un plugin d’accessibilité, et les boutons et liens natifs sont utilisables au clavier par défaut — une application simple part donc en assez bon état. Mais rien ne la maintient accessible : les entrées sans étiquette (une étiquette à NULL avec un placeholder), les boutons à icône seule, les indices de statut par la seule couleur, les mises à jour dynamiques non annoncées et les widgets personnalisés réservés à la souris la cassent tous. Vous atteignez WCAG 2.1 AA en suivant la liste de contrôle délibérément, pas en vous fiant aux valeurs par défaut.
Chaînez tagAppendAttributes() sur n’importe quelle balise et passez l’attribut : actionButton("go", "", icon = icon("play")) |> tagAppendAttributes(`aria-label` = "Run report") donne un nom accessible à un bouton à icône seule (cela fonctionne parce qu’actionButton() renvoie directement le <button>). Les entrées, c’est différent : textInput() renvoie un <div> englobant, alors ciblez le contrôle avec … |> tagAppendAttributes(.cssSelector = "input", `aria-label` = "…") — ne passez pas aria-* directement dans textInput() (cela provoque une erreur). Utilisez aria-label quand un contrôle n’a pas de texte visible ; préférez un label réel et visible sur les entrées dès que le design le permet, puisqu’il aide aussi les utilisateurs voyants. Ne recourez à ARIA que là où le HTML natif ou la sortie propre de Shiny ne véhicule pas déjà le sens.
Donnez à renderPlot() son argument alt : renderPlot({ … }, alt = "Revenue rising from 1.2M to 3.4M across 2024"). Cela définit le texte alternatif sur l’image du graphique pour qu’un lecteur d’écran décrive le graphique au lieu de sauter une image vide — décrivez les données et la tendance, pas « un graphique », et passez une fonction si vous voulez que la description soit générée à partir des mêmes données réactives. Comme le texte alternatif ne peut pas transmettre chaque chiffre, proposez aussi un tableau de données de repli (produisez les données sous-jacentes sous forme de vrai tableau) pour que les utilisateurs puissent lire les valeurs exactes.
Shiny vous donne tout ce qu’il faut pour atteindre WCAG 2.1 AA — des entrées étiquetées, des contrôles natifs utilisables au clavier, des points d’accroche ARIA et bslib pour une thématisation accessible — mais la conformité est une propriété de votre application, pas du framework. Une application Shiny peut être pleinement conforme AA ou gravement inaccessible selon la façon dont elle est construite. Suivez la liste de contrôle (de vraies étiquettes, ARIA au besoin, l’utilisabilité au clavier, le contraste, le texte alternatif) et vérifiez avec une passe au clavier, un lecteur d’écran et un audit automatisé ; c’est cette vérification qui définit vraiment « être conforme à WCAG ».
Le critère Contraste (minimum) (1.4.3, niveau AA) de WCAG exige 4.5:1 pour le texte normal et 3:1 pour le grand texte (environ 18 pt, ou 14 pt gras) et les composants d’interface par rapport à leur arrière-plan. Définissez vos couleurs une fois avec bslib::bs_theme(bg =, fg =, primary =, …) et testez chaque paire premier plan/arrière-plan dans le vérificateur de contraste WebAIM. Les échecs habituels sont un lien de marque clair sur blanc et un texte de placeholder gris pâle ; assombrissez-les jusqu’à ce que la paire passe.
Testez vos connaissances
Cet extrait comporte trois bugs d’accessibilité — un champ sans étiquette, un bouton à icône seule sans nom, et un résultat qui se met à jour en silence :
ui <- fluidPage(
textInput("q", label = NULL, placeholder = "Search products"),
actionButton("go", label = NULL, icon = icon("magnifying-glass")),
textOutput("count")
)Retravaillez l’UI pour que (1) le champ de recherche et le bouton à icône seule aient tous deux des noms accessibles, et (2) le décompte des résultats soit annoncé aux lecteurs d’écran chaque fois qu’il se met à jour.
Donnez au champ un label réel et visible (le mieux) ou un aria-label. Donnez au bouton un aria-label pour son icône. Enveloppez textOutput("count") dans un div portant aria-live = "polite" pour que la technologie d’assistance annonce le nouveau décompte.
ui <- fluidPage(
textInput("q", label = "Search products"), # a real, visible label
actionButton("go", label = "",
icon = icon("magnifying-glass"),
`aria-label` = "Search"), # name the icon-only button
div(`aria-live` = "polite", # announce updates politely
textOutput("count"))
)Donner à textInput() un vrai label produit un <label for="q"> en bonne et due forme, si bien que le champ annonce « Search products, zone d’édition » au lieu de « vide ». L’aria-label du bouton donne au contrôle loupe le nom accessible « Search ». Et envelopper la sortie dans une région aria-live="polite" fait qu’à chaque changement du décompte, un lecteur d’écran énonce la nouvelle valeur sans que l’utilisateur ait à la chercher. Une étiquette visible l’emporte sur un aria-label quand le design le permet, parce qu’elle aide aussi les utilisateurs voyants.
Vous ajoutez un texte alternatif à un graphique avec renderPlot({ … }, alt = "Revenue rising across 2024"). Qu’est-ce que cela accomplit ?
A. Cela fait s’afficher le graphique plus vite.
B. Cela définit l’attribut alt sur l’image du graphique, pour qu’un lecteur d’écran puisse décrire le graphique.
C. Cela met le graphique en cache pour que le second tracé soit instantané.
D. Cela ajoute une légende visible sous le graphique.
B. L’argument alt de renderPlot() définit le texte alternatif sur l’<img> générée, si bien que la technologie d’assistance lit votre description au lieu de sauter un graphique vide. Le texte n’est pas visible sur la page (ce serait une légende, donc D est faux), il n’a rien à voir avec la vitesse (A) ni la mise en cache (C — c’est bindCache(), traité dans la leçon sur les performances). Comme le texte alternatif ne peut pas transmettre chaque chiffre, associez-le à un tableau de données de repli pour les valeurs exactes.
Conclusion
Une application Shiny accessible naît d’une liste de contrôle courte et ordonnée, dont l’essentiel consiste à ne pas casser ce que Shiny fait déjà bien. Donnez à chaque entrée une étiquette réelle et visible — Shiny produit le bon balisage pour vous. N’ajoutez ARIA que là où le HTML est insuffisant, avant tout une région aria-live pour que les résultats dynamiques soient annoncés. Gardez tout utilisable au clavier, appuyez-vous sur les contrôles natifs, et ne masquez jamais l’anneau de focus. Respectez le contraste minimum de 4.5:1 avec bslib::bs_theme() et ne laissez jamais la couleur être le seul signal. Donnez aux graphiques un alt et un tableau de données de repli, et balisez les tableaux avec une légende et scope. Puis vérifiez — une passe au clavier, un lecteur d’écran et un audit automatisé, dans cet ordre. Visez WCAG 2.1 AA, et rappelez-vous qu’une application rapide et réactive est en soi plus accessible : l’accessibilité et les performances sont les deux moitiés d’une application qui fonctionne pour tout le monde.
Leçons connexes
- À associer avec : la leçon sur les performances est l’autre moitié — une application rapide et fluide est en soi plus accessible, et les deux sont ce qui rend une application utilisable dans des conditions réelles. Côté thématisation, thématisation et CSS couvre
bslib::bs_theme()en détail, et contrôles de saisie couvre les entrées étiquetées sur lesquelles cette leçon s’appuie. - Allez plus loin : Applications web Shiny — tout le cursus Shiny. · Science computationnelle et IA — le pilier.
Prouvez que vous savez le faire. Maîtrisez toute la série Performance Shiny — suivez votre parcours, construisez des projets et obtenez un certificat.
Passez à Pro — Prova illimité sur vos propres données et un certificat vérifiable qui atteste la compétence.
dès 15 $/mois facturé annuellement
✓ Vous êtes Pro — continuez. The runtime is the judge.
Réutilisation
Citation
@online{2026,
author = {},
title = {Applications Shiny accessibles : étiquettes, ARIA, clavier et
contraste pour WCAG},
date = {2026-07-16},
url = {https://www.datanovia.com/learn/programming/shiny/performance/accessibility-performance},
langid = {fr}
}