Search code examples
rshinyalignment

How to make multiple input boxes with inline text align to the right of a sidebarPanel


I have a sidebarPanel in my shiny ui that contains 5 switchInputs, each of which are preceded by a piece of inline text with varying lengths. The latter two switchInputs trigger a conditional numeric input, which works fine. Because the length of the inline text varies, I want to align the switchInput boxes to the right of the sidebarPanel. I want to achieve something like this:

enter image description here

I have tried doing so by using style="float:right" within each div() that contains a switchInput. However, for some reason this only works for the top switchInput as the lower ones are shifted to the left. When the conditionalPanel of the fourth switchInput is triggered, this nonetheless seems to correctly 'reset' the alignment of the switchInput below (see image below). Any ideas on achieving the above layout?

enter image description here

Here's my code:

library(shiny)
library(shinyWidgets)


ui <- fluidPage(
  sidebarLayout(
    sidebarPanel(
      div(style = "white-space: nowrap;",
          h5('Yes or no?',style="display:inline-block"),
          div(style="display: inline-block;float:right;",
              switchInput("switch1", onLabel="Yes", offLabel="No", size="mini",value=FALSE))
      ),
      div(style = "white-space: nowrap;",
          p("Hey there, having a good day?",style="display:inline-block"),
          div(style="display: inline-block;float:right;",
              switchInput("switch2", onLabel="Yes", offLabel="No", size="mini",value=FALSE))
      ),
      div(style = "white-space: nowrap;",
          h5("Would you like some apples?",style="display:inline-block"),
          div(style="display:inline-block; float:right",
              switchInput("switch3", onLabel="Yes", offLabel="No", size="mini",value=FALSE))
      ),
      div(style = "white-space: nowrap;",
          p("Have you ever had a fish tank at home?",style="display:inline-block"),
          div(style="display: inline-block; float:right",
              switchInput("switch4", onLabel="Yes", offLabel="No", size="mini",value=FALSE))
      ),
      conditionalPanel(
        condition = "input.switch4 == true",
        numericInput("numeric1", label = "If so, how many fish did it contain?", value = 300)
      ),
      div(style = "white-space: nowrap;",
          h5("Have you ever flown an airplane?",style="display:inline-block"),
          div(style="display: inline-block; float:right",
              switchInput("switch5", onLabel="Yes", offLabel="No", size="mini",value=FALSE))
      ),
      conditionalPanel(
        condition = "input.switch5 == true",
        numericInput("numeric2", label = "If so, how many flights?", value = 2.5)
      ),
    ),
    mainPanel()
  )
)

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

Solution

  • My recommendations:

    1. Use flexbox `display: flex; justify-content: space-between;" would do the job

    2. Avoid using inline css, consider adding classes to your elements and styling those. read more

    3. Try to reduce code duplication, it would make it easier to refactor in the future. You can do this by creating a function. read more

    Here is the code

      library(shiny)
      library(shinyWidgets)
      
      switch_container <- function(input_id, label) {
        div(
          class = "switch-container",
          label,
          switchInput(
            input_id,
            onLabel = "Yes",
            offLabel = "No",
            size = "mini",
            value = FALSE)
          )
      }
      
      ui <- fluidPage(
        sidebarLayout(
          sidebarPanel(
            tags$style(".switch-container {display: flex; justify-content: space-between;}"),
            switch_container("switch1", h5("Yes or no?")),
            switch_container("switch2", p("Hey there, having a good day?")),
            switch_container("switch3", h5("Would you like some apples?")),
            switch_container("switch4", p("Have you ever had a fish tank at home?")),
            conditionalPanel(
              condition = "input.switch4 == true",
              numericInput("numeric1", label = "If so, how many fish did it contain?", value = 300)
            ),
            switch_container("switch5", h5("Have you ever flown an airplane?")),
            conditionalPanel(
              condition = "input.switch5 == true",
              numericInput("numeric2", label = "If so, how many flights?", value = 2.5)
            ),
          ),
          mainPanel()
        )
      )
      
      server <- function(input, output) {}
      
      shinyApp(ui = ui, server = server)
    

    enter image description here