sdittmar
sdittmar

Reputation: 365

Set focus in Shiny app to a specific UI element on load

After my R Shiny app has loaded, I would like to set focus to the selectInput element, so that the user can immediately select an item by up-down arrows and hit enter.

I was trying to capture the JavaScript load event, send it to R and than use the Shiny.addCustomMessageHandler to set focus of the selectInput element.

As an intermediate step, I was also trying, to use the click event from an actionButton to trigger the element focus. Although I think most parts should be in the code, the load event does not get transmitted to the server and the focus part does get picked up by JavaScript.

This post focusing the cursor in textArea after clicking an action button in shiny also did not help me enough to get it to the finish line.

This is what I have so far:

library(shiny)
ui <- fluidPage(
  tags$head(tags$script('
    window.addEventListener("load", function(){
      alert("Loaded");
      Shiny.setInputValue("loaded", 1) // new identical function to Shiny.onInputChange
    });
 ')),
  tags$head(tags$script('
    Shiny.addCustomMessageHandler("focus", function(null) {
      document.getElementById("select").focus()
    });  
 ')),
  headerPanel("Focus",  windowTitle = "Focus"),
  fluidRow(
    column(width = 2, class = "panel",
           selectInput("select", label = "Your Choice", choices = c("Choice 1", "Choice 2"), selectize = TRUE),
           actionButton("click", "Click")
    ),
    column(width = 10,
           textOutput("text")
    )
  )
)

server = function(input, output, session) {

  observeEvent(input$loaded, {
    session$sendCustomMessage("focus",list(NULL))
    print("Loaded")
  })

  observeEvent(input$select, {
    print("Selected")
  })

  observeEvent(input$click, {
    session$sendCustomMessage("focus",list(NULL))
    print("Clicked")
  })

  output$text <- renderText({

  })
}

shinyApp(ui = ui, server = server)

Thank you for your help.

Upvotes: 3

Views: 1387

Answers (1)

St&#233;phane Laurent
St&#233;phane Laurent

Reputation: 84649

Open the console (Ctrl+Shift+i with Chrome), you will see there are some errors in your JS code.

The main one is that shiny is not ready yet when you open the app, so the function Shiny.setInputValue is not found.

To be sure shiny is ready, use:

$(document).on("shiny:connected", function(){
  ......
});

Now, after some multiple trials, I found that the element to be "focused" is not the entire select element. It is its div subelement with class selectize-input, that you can select with $("#select ~ .selectize-control > .selectize-input").

Finally, the good action to perform is not focus, it is click. Here is the full app:

library(shiny)

js <- '
$(document).on("shiny:connected", function(){
  alert("Loaded");
  Shiny.setInputValue("loaded", 1);
  Shiny.addCustomMessageHandler("focus", function(x){
    $("#select ~ .selectize-control > .selectize-input").click();
  });
});
'

ui <- fluidPage(
  tags$head(tags$script(HTML(js))),
  headerPanel("Focus",  windowTitle = "Focus"),
  fluidRow(
    column(width = 2, class = "panel",
           selectInput("select", label = "Your Choice", 
                       choices = c("Choice 1", "Choice 2"), selectize = TRUE),
           actionButton("click", "Click")
    ),
    column(width = 10,
           textOutput("text")
    )
  )
)

server = function(input, output, session) {

  observeEvent(input$loaded, {
    session$sendCustomMessage("focus", list(NULL))
    print("Loaded")
  })

  observeEvent(input$select, {
    print("Selected")
  })

  observeEvent(input$click, {
    session$sendCustomMessage("focus", list(NULL))
    print("Clicked")
  })

  output$text <- renderText({

  })
}

shinyApp(ui = ui, server = server)

Upvotes: 7

Related Questions