jasbner
jasbner

Reputation: 2283

R Shiny selectizeInput Accessibility Missing Form Label

Say for example, I have a very basic shiny application where you selectize a letter:

library(shiny)

ui <- fluidPage(
  fluidRow(
    column(3, selectizeInput("Letters", "Choose a Letter",
      choices = LETTERS, multiple = TRUE)
    )
  )
)

server <- function(input, output) {}
shinyApp(ui = ui, server = server)

Basic UI

I need this shiny application to be 508 compliant/accessible. If I run it through a web accessibility test like WAVE, I get an error about a Missing form label for this selectizeInput section.

Missing Form Label

I believe this is because of a random div that is added that does not have the same ID that the "Choose a letter" label references. The label is for Letters-selectized and the div that is showing an accessibility error has the ID Letters. Is there any way to fix this error? I know you can add render to the options for selectizeInput but I havent found a way to correct this particular div.

Based on comment from ismirsehregal If I try to add an additional label with tagQuery for the ID "Letters", I get a duplicate form label error. I believe this is because even though I specify "for" = "Letters" the output is still for = "Letters-selectized"

library(shiny)
library(htmltools)

ui <- fluidPage(
  {queryfluidRow <- tagQuery(fluidRow(
    column(3, selectizeInput("Letters", "Choose a Letter",
      choices = LETTERS, multiple = TRUE))
    )
  )
  queryfluidRow$find("#Letters")$parent()$prepend(tag("label hidden",list("class" = "control-label","for" = "Letters", "Custom Tag")))$allTags()}
)

server <- function(input, output) {}
shinyApp(ui = ui, server = server)

The added tagQuery label html looks like the following and produces additional errors. I probably do not understand the underlying html relationship between labels and form control selection. However, I would have assumed setting "for" = "Letters" in tagQuery would have assigned the label to the correct ID:

<label hidden="" class="control-label" for="Letters-selectized">Custom Tag</label>
<select id="Letters" class="form-control selectized shiny-bound-input" multiple="multiple" tabindex="-1" style="display: none;"></select>

Upvotes: 5

Views: 274

Answers (1)

I_O
I_O

Reputation: 6921

{shinyjs} allows you i. a. to execute javascript code client-side. You can thus query your label element via its id and set its for attribute like so:

library(shiny)
library(shinyjs)

ui <- fluidPage(
  useShinyjs(),  # include shinyjs
  fluidRow(
    column(3, selectizeInput("Letters", "Choose a Letter",
      choices = LETTERS, multiple = TRUE)
    )
  )
)

server <- function(input, output, session) {
  runjs('document.getElementById("Letters-label").setAttribute("for", "letters")')
}
shinyApp(ui = ui, server = server)

BTW, apart from above library, Shiny Awesome lists many more, well, awesome extensions for Shiny apps. Kudos to Nan Xiao.

Upvotes: 2

Related Questions