Search code examples
cssrshinydrag-and-drop

Drag and drop elements between two drop zones in R shiny


I am trying to use shiny to drag and drop elements from one column to another in a dynamic document.

However, I could not identify a way:

  • to have the A, B, C elements in one of the boxes (drop zones) at launch
  • to make the boxes fill to the bottom of the webpage.

Below is the code I am using:

library(shiny)
library(shinyDND)

ui <- shinyUI(fillPage(
fillRow(
  sidebarLayout(
    sidebarPanel(
      h1("Side panel"),
      dropUI(
      "side_panel", row_n = 2, col_n = 1
    ),
    br(),
    verbatimTextOutput("side"),
    width = 6
    ),
    mainPanel(
      h1("Main panel"),
      div(dragUI("div6", "A"), style = "margin-left:-90%"),
      div(dragUI("div6", "B"), style = "margin-left:-90%"),
      div(dragUI("div5", "C"), style = "margin-left:-90%"),
      dropUI("main_panel", row_n = 2, col_n = 6),
      br(),
      verbatimTextOutput("main"),
      width = 6
    ),
    position = "right",
    fluid = FALSE
  )
)))

server = shinyServer(function(input, output,session) {
  observeEvent(input$main_panel,{
    output$main = renderText(
      paste("The main dropUI element currently contains:", input$main_panel, sep = " "))
  })
  observeEvent(input$side_panel,{
    output$side = renderText(
      paste("The side dropUI element currently contains:", input$side_panel, sep = " "))
  })
})

shinyApp(ui = ui, server = server)

Solution

  • As already indicated in the comments, I would suggest to use the sortable library for drag and drop in shiny. Below is one example where the requirement is fulfilled that the A, B and C elements are initially located in the right zone.

    Notice that for the GIF I added some CSS such that the style of the zones and elements looks similar to your given example and that I set the height style of the .rank-list selector to 30vh. You can fully customise this, in particular you can adjust it such that the boxes fill to the bottom of the webpage.

    enter image description here

    library(shiny)
    library(sortable)
    
    ui <- shinyUI(
        fillPage(
            tags$head(
                tags$style(HTML("
                                .rank-list {
                                    height:30vh;
                                    border:dashed;
                                }
                                
                                .rank-list-item {
                                    width:40px;
                                    margin-left:140px;
                                    margin-top:10px;
                                }
     
                                .default-sortable .rank-list.rank-list-empty {
                                    border-color: black
                                }
                                "))
            ),
            fillRow(sidebarLayout(
                sidebarPanel(
                    h1("Side panel"),
                    bucket_list(
                        header = NULL,
                        group_name = "bucket_list_group",
                        orientation = "horizontal",
                        add_rank_list(
                            text = "Drag items from here ...",
                            labels = list("A",
                                          "B",
                                          "C"),
                            input_id = "rank_list_1"
                        )
                    ),
                    br(),
                    verbatimTextOutput("results_2"),
                    width = 6
                ),
                mainPanel(
                    br(),
                    h1("Main panel"),
                    bucket_list(
                        header = NULL,
                        group_name = "bucket_list_group",
                        orientation = "horizontal",
                        add_rank_list(
                            text = "... to here",
                            labels = NULL,
                            input_id = "rank_list_2"
                        )
                    ),
                    br(),
                    verbatimTextOutput("results_1"),
                    width = 6
                ),
                position = "right",
                fluid = FALSE
            ))))
    
    server = shinyServer(function(input, output, session) {
        output$results_1 <-
            renderText(paste(
                "The main dropUI element contains:",
                paste(input$rank_list_2, collapse = ", ")
            ))
        
        output$results_2 <-
            renderText(paste(
                "The side dropUI element contains:",
                paste(input$rank_list_1, collapse = ", ")
            ))
    })
    
    shinyApp(ui = ui, server = server)