Adriana Huante
Adriana Huante

Reputation: 362

Add line break in checkboxGroupInput choices - Shiny

I want to add a line break in one choice because it is too long. Answers to a similar question about the label of a button say to wrap the string in HTML(), but the solution does not seem to work for choices in checkboxGroupInput().

Simple example code

library(shiny)

choices_vector <- c(
  'Choice 1',
  HTML('Choice 2 shoulde be<br />on two lines'),
  'Choice 3'
)

ui <- fluidPage(
  checkboxGroupInput(
    inputId = 'choices_selec',
    label = '',
    choices = choices_vector
  )
)

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

Original example code

This is older example code and is more complicated. It is left here because one answer uses many of the specifics of this example.

ui <- fluidPage(
  splitLayout(cellWidths = c(170,80,160),
              tagList(uiOutput("example")))
)

server <- function(input, output) {
  choices_vector <- c("choice 1","choice 2",HTML("I want a line break here <br/> since the label is too long"),"choice 4")
  output$example <- renderUI({
    checkboxGroupInput(inputId = "choices_selec",
                       label = "", choices = choices_vector, selected = F)
  })
}

# Run the application 
shinyApp(ui = ui, server = server)

I also tried using using paste0 and collapse (see the following code) and changing uiOutput for htmlOutput but the results are the same

server <- function(input, output) {
  choices_vector <- c("choice 1","choice 2",paste0(c("I want a line break here ", "since the label is too long"), collapse = "<p/>"),"choice 4")
  output$example <- renderUI({
    checkboxGroupInput(inputId = "choices_selec",
                       label = "", choices = choices_vector, selected = F)
  })
}

Upvotes: 4

Views: 581

Answers (2)

randy
randy

Reputation: 1081

choiceNames vs. choices

The documentation for checkboxGroupInput() explains:

The advantage of using [choiceNames and choiceValues] over a named list for choices is that choiceNames allows any type of UI object to be passed through (tag objects, icons, HTML code, ...), instead of just simple text.

In other words, this works:

checkboxGroupInput(
    inputId = 'InputCorrect',
    label = 'Correct',
    choiceNames = list(
      'Choice 1',
      HTML('Choice 2 is<br />on two lines'),
      'Choice 3'
    ),
    choiceValues = 1:3,
  )

but this does not:

  checkboxGroupInput(
    inputId = 'InputIncorrect',
    label = 'Incorrect',
    choices = list(
      'Choice 1',
      HTML('Choice 2 is<br />not on two lines'),
      'Choice 3'
    )
  )

Don’t use vectors

Extra complications to keep in mind when passing a previously-defined list to choiceNames:

First, use list() instead of c() when defining the choiceNames. Elements of a vector must be the same type. Thus, c('A', HTML('B'), 'C') does not actually have any HTML elements. Also, I think R does not support vectors of HTML elements, anyway.

Second, when placing the HTML() in the list manually is not feasible/desirable, make a character vector and then use lapply() to change every element to HTML:

choices_vector = c('Choice 1', 'Choice 2 is<br />not on two lines', 'Choice 3')
choices_vector = lapply(choices_vector, HTML)

Working example

(Note the use of lapply)

library(shiny)

choices_vector = c(
  'Choice 1',
  'Choice 2 is<br />on two lines',
  'Choice 3'
)

ui = fluidPage(
  checkboxGroupInput(
    inputId = 'InputExistingList',
    label = 'Also correct',
    choiceNames = lapply(choices_vector, HTML),
    choiceValues = 1:length(choices_vector),
  )
)
server = function(input, output) {}
shinyApp(ui = ui, server = server)

Upvotes: 0

lz100
lz100

Reputation: 7330

The problem is checkboxGroupInput only accepts strings as choices. There is nothing we can do unless you change the Shiny source code. Try to think out of the box, why do we need to do it at R preprocessing level. We can use js to post-process it on the client-side (browser).

Here's how, do as usual, but just add this very simple js code after the checkbox:

library(shiny)
ui <- fluidPage(
  splitLayout(cellWidths = c(170,80,160),
              tagList(uiOutput("example")))
)

server <- function(input, output) {
  choices_vector <- c("choice 1"="c1","choice 2"="c2", "I want a line break here<br/> since the label is too long"="c3","choice 4"="c4")
  output$example <- renderUI({
    tagList(
      checkboxGroupInput(inputId = "choices_selec",
                         label = "", choices = choices_vector, selected = F),
      tags$script(
        "
        $('#choices_selec .checkbox label span').map(function(choice){
            this.innerHTML = $(this).text();
        });
        "
      )
    )
  })
  
  observe({
    print(input$choices_selec)
  })
}

# Run the application 
shinyApp(ui = ui, server = server)

enter image description here

This code will allow you to use any HTML tag as string input. The HTML will be parsed once the check box is rendered.

I also add names to the choice vector, so you will have a better way on the server side to know what choices are selected.

Upvotes: 3

Related Questions