| Type: | Package |
| Title: | Drag-and-Drop in 'shiny' Apps with 'SortableJS' |
| Version: | 0.6.0 |
| Description: | Enables drag-and-drop behaviour in Shiny apps, by exposing the functionality of the 'SortableJS'https://sortablejs.github.io/Sortable/ JavaScript library as an 'htmlwidget'. You can use this in Shiny apps and widgets, 'learnr' tutorials as well as R Markdown. In addition, provides a custom 'learnr' question type - 'question_rank()' - that allows ranking questions with drag-and-drop. |
| License: | MIT + file LICENSE |
| URL: | https://rstudio.github.io/sortable/ |
| BugReports: | https://github.com/rstudio/sortable/issues |
| Imports: | assertthat, cli, htmltools, htmlwidgets, jsonlite, learnr (≥0.10.0), rlang (≥ 1.0.0), shiny (≥ 1.9.0), utils |
| Suggests: | base64enc, covr, knitr, magrittr, rmarkdown, shinytest2,spelling, testthat (≥ 2.1.0), webshot, withr |
| VignetteBuilder: | knitr |
| Config/testthat/edition: | 3 |
| Encoding: | UTF-8 |
| Language: | en-US |
| RoxygenNote: | 7.3.3 |
| NeedsCompilation: | no |
| Packaged: | 2025-12-14 08:14:06 UTC; andrie |
| Author: | Andrie de Vries [cre, aut], Barret Schloerke [aut], Kenton Russell [aut, ccp] (Original author), Posit [cph, fnd], Lebedev Konstantin [cph] ('SortableJS', https://sortablejs.github.io/Sortable/) |
| Maintainer: | Andrie de Vries <apdevries@gmail.com> |
| Repository: | CRAN |
| Date/Publication: | 2025-12-14 10:50:02 UTC |
sortable: Drag-and-Drop in 'shiny' Apps with 'SortableJS'
Description

Enables drag-and-drop behaviour in Shiny apps, by exposing the functionality of the 'SortableJS'https://sortablejs.github.io/Sortable/ JavaScript library as an 'htmlwidget'. You can use this in Shiny apps and widgets, 'learnr' tutorials as well as R Markdown. In addition, provides a custom 'learnr' question type - 'question_rank()' - that allows ranking questions with drag-and-drop.
A new html widget
sortable_js()is a low-level function that adds theSortableJSto your widgets.
Important functions
The important functions in this package are:
rank_list()creates a drag-and-drop, rank listbucket_list()lets you add multiplerank_listobjects in columns
Custom question types forlearnr
You can also use new question types in yourlearnr tutorials:
Author(s)
Maintainer: Andrie de Vriesapdevries@gmail.com
Authors:
Barret Schloerkebarret@posit.co
Kenton Russellkent.russell@timelyportfolio.com (Original author) [conceptor]
Other contributors:
Posit [copyright holder, funder]
Lebedev Konstantin ('SortableJS', https://sortablejs.github.io/Sortable/) [copyright holder]
See Also
Useful links:
Add a rank list inside bucket list.
Description
Since abucket_list can contain more than onerank_list, you needan easy way to define the contents of each individual rank list. Thisfunction serves as a specification of a rank list.
Usage
add_rank_list(text, labels = NULL, input_id = NULL, css_id = input_id, ...)Arguments
text | Text to appear at top of list. |
labels | A character vector with the text to display inside the widget.This can also be a list of html tag elements. The text content of eachlabel or label name will be used to set the shiny |
input_id | output variable to read the plot/image from. |
css_id | This is the css id to use, and must be unique in your shinyapp. This defaults to the value of |
... | Other arguments passed to |
Value
A list of classadd_rank_list
See Also
bucket_list(),rank_list() andupdate_rank_list()
Create a bucket list.
Description
A bucket list can contain more than onerank_list and allows drag-and-dropof items between the different lists.
Usage
bucket_list( header = NULL, ..., group_name, css_id = group_name, group_put_max = rep(Inf, length(labels)), options = sortable_options(), class = "default-sortable", orientation = c("horizontal", "vertical"))Arguments
header | Text that appears at the top of the bucket list. (This isencoded as an HTML |
... | One or more specifications for a rank list, and must be defined byadd_rank_list. |
group_name | Passed to |
css_id | This is the css id to use, and must be unique in your shinyapp. This defaults to the value of |
group_put_max | Not yet implemented |
options | Options to be supplied tosortable_js object. Seesortable_options for more details |
class | A css class applied to the bucket list and rank lists. This canbe used to define custom styling. |
orientation | Either |
Value
A list with classbucket_list
See Also
Examples
## -- example-bucket-list ---------------------------------------------## bucket listif(interactive()) { bucket_list( header = "This is a bucket list. You can drag items between the lists.", add_rank_list( text = "Drag from here", labels = c("a", "bb", "ccc") ), add_rank_list( text = "to here", labels = NULL ) )}## bucket list with three columnsif(interactive()) { bucket_list( header = c("Sort these items into Letters and Numbers"), add_rank_list( text = "Drag from here", labels = sample(c(1:3, letters[1:2])) ), add_rank_list( text = "Letters" ), add_rank_list( text = "Numbers" ) )}## drag items between bucket listsif(interactive()) { ui <- shiny::fluidPage( shiny::column(4, bucket_list(NULL, group_name = "foo", add_rank_list( text = "Drag from here...", labels = sample(c(1:3, letters[1:2])) ) )), shiny::column(4, "Some empty space"), shiny::column(4, bucket_list(NULL, group_name = "foo", add_rank_list( text = "...To here" ) )) ) server <- function(input, output, session) {} shiny::shinyApp(ui, server)}## Example of a shiny appif (interactive()) { app <- system.file( "shiny/bucket_list/app.R", package = "sortable" ) shiny::runApp(app)}Chain multiple JavaScript events
Description
SortableJS does not have an event based system. To be able to call multipleJavaScript events under the same event execution, they need to be executedone after another.
Usage
chain_js_events(...)Arguments
... | JavaScript functions defined byhtmlwidgets::JS |
Value
A single JavaScript function that will call all methods provided withthe event
See Also
Other JavaScript functions:sortable_js_capture_input()
Check if shiny modules are enabled forsortable.
Description
Due to an early (regrettable) design decision,sortable in versions <= 0.5.0did not support shiny modules.To usesortable with shiny modules, you have to opt in to differentbehaviour, by callingenable_modules().
Usage
is_modules_enabled()enable_modules(enable = TRUE)Arguments
enable | If |
Value
Logical value indicating whether shiny modules are enabled or not.
Check if object is sortable options.
Description
Check if object is sortable options.
Usage
is_sortable_options(x)Arguments
x | Object to test |
Value
Logical vector. TRUE if the object inherits fromsortable_options
Examples
is_sortable_options("foo") # returns FALSERanking question for learnr tutorials.
Description
Add interactive ranking tasks to yourlearnr tutorials. The student candrag-and-drop the answer options into the desired order.
Usage
question_rank( text, ..., correct = "Correct!", incorrect = "Incorrect", loading = c("**Loading:** ", text, "<br/><br/><br/>"), submit_button = "Submit Answer", try_again_button = "Try Again", allow_retry = FALSE, random_answer_order = TRUE, options = sortable_options())Arguments
text | Question or option text |
... | parameters passed onto |
correct | For |
incorrect | Text to print for an incorrect answer (defaults to"Incorrect") when |
loading | Loading text to display as a placeholder while the question isloaded. If not provided, generic "Loading..." or placeholder elements willbe displayed. |
submit_button | Label for the submit button. Defaults to |
try_again_button | Label for the try again button. Defaults to |
allow_retry | Allow retry for incorrect answers. Defaults to |
random_answer_order | Display answers in a random order. |
options | Options to be supplied tosortable_js object. Seesortable_options for more details |
Details
Each set of answer options must contain the same set of answer options. Whenthe question is completed, the first correct answer will be displayed.
Note that, by default, the answer order is randomized.
Value
A customlearnr question, withtype = sortable_rank.Seelearnr::question().
Examples
## Example of rank problem inside a learnr tutorialif (interactive()) { learnr::run_tutorial("question_rank", package = "sortable")}Create a ranking item list.
Description
Creates a ranking item list using theSortableJS framework,and generates anhtmlwidgets element. The elements of this list can bedragged and dropped in any order.
You can embed a ranking question inside alearnr tutorial, usingquestion_rank().
To embed arank_list inside a shiny app, see the Details section.
Usage
rank_list( text = "", labels, input_id, css_id = input_id, options = sortable_options(), orientation = c("vertical", "horizontal"), class = "default-sortable")Arguments
text | Text to appear at top of list. |
labels | A character vector with the text to display inside the widget.This can also be a list of html tag elements. The text content of eachlabel or label name will be used to set the shiny |
input_id | output variable to read the plot/image from. |
css_id | This is the css id to use, and must be unique in your shinyapp. This defaults to the value of |
options | Options to be supplied tosortable_js object. Seesortable_options for more details |
orientation | Set this to "horizontal" to get horizontal orientation ofthe items. |
class | A css class applied to the rank list. This can be used todefine custom styling. |
Details
You can embed arank_list inside a Shiny app, to capture the preferredranking order of your user.
The widget automatically updates a Shiny output, with the matchinginput_id.
See Also
update_rank_list,sortable_js,bucket_list andquestion_rank
Examples
## - example-rank-list ------------------------------------------------if (interactive()) { rank_list( text = "You can drag, drop and re-order these items:", labels = c("one", "two", "three", "four", "five"), input_id = "example_2" )}## - example-rank-list-multidrag ------------------------------------------if (interactive()) { rank_list( text = "You can select multiple items and drag as a group:", labels = c("one", "two", "three", "four", "five"), input_id = "example_2", options = sortable_options( multiDrag = TRUE ) )}## - example-rank-list-swap -----------------------------------------------if (interactive()) { rank_list( text = "You can re-order these items, and notice the swapping behaviour:", labels = c("one", "two", "three", "four", "five"), input_id = "example_2", options = sortable_options( swap = TRUE ) )}## Example of a shiny appif (interactive()) { app <- system.file("shiny/rank_list/app.R", package = "sortable") shiny::runApp(app)}Widget render function for use in Shiny.
Description
Widget render function for use in Shiny.
Usage
render_sortable(expr, env = parent.frame(), quoted = FALSE)Arguments
expr | An expression |
env | The environment in which to evaluate |
quoted | Is |
Creates an htmlwidget with embedded 'SortableJS' library.
Description
Creates anhtmlwidget that providesSortableJS to use fordrag-and-drop interactivity in Shiny apps and R Markdown.
Usage
sortable_js( css_id, options = sortable_options(), width = 0, height = 0, elementId = NULL, preRenderHook = NULL)Arguments
css_id |
|
options | Options to be supplied tosortable_js object. Seesortable_options for more details |
width | Fixed width for widget (in css units). The default is |
height | Fixed height for widget (in css units). The default is |
elementId | Use an explicit element ID for the widget (rather than anautomatically generated one). Useful if you have other JavaScript thatneeds to explicitly discover and interact with a specific widget instance. |
preRenderHook | A function to be run on the widget, just prior torendering. It accepts the entire widget object as input, and should returna modified widget object. |
See Also
Examples
## -- example-sortable-js -------------------------------------------------# Simple example of sortable_js.# Important: set the tags CSS `id` equal to the sortable_js `css_id`if (interactive()) { if (require(htmltools)) { html_print( tagList( tags$p("You can drag and reorder the items in this list:"), tags$ul( id = "example_1", tags$li("Move"), tags$li("Or drag"), tags$li("Each of the items"), tags$li("To different positions") ), sortable_js(css_id = "example_1") ) ) }}Construct JavaScript method to capture Shiny inputs on change.
Description
This captures the state of asortable list. It will look for adata-rank-idattribute of the first child for each element. If no? attribute exists forthat particular item's first child, the inner text will be used as anidentifier.
Usage
sortable_js_capture_input(input_id)sortable_js_capture_bucket_input(input_id, input_ids, css_ids)Arguments
input_id | Shiny input name to set |
input_ids | Set of Shiny input ids to set corresponding to the provided |
css_ids | Set of SortableJS |
Details
This method is used with theonSort option ofsortable_js. Seesortable_options().
Value
A character vector with classJS_EVAL. Seehtmlwidgets::JS().
See Also
sortable_js andrank_list.
Other JavaScript functions:chain_js_events()
Examples
## -- example-sortable-js-capture -----------------------------------------# Simple example of sortable_js_capture.# Important: set the tags CSS `id` equal to the sortable_js `css_id`if(interactive()) { library(shiny) library(sortable) ui <- fluidPage( div( id = "sortable", div(id = 1, `data-rank-id` = "HELLO", class = "well", "Hello"), div(id = 2, `data-rank-id` = "WORLD", class = "well", "world") ), verbatimTextOutput("chosen"), sortable_js( css_id = "sortable", options = sortable_options( onSort = sortable_js_capture_input(input_id = "selected") ) ) ) server <- function(input, output){ output$chosen <- renderPrint(input$selected) } shinyApp(ui, server)}## ------------------------------------# For an example, see the Shiny app atsystem.file("shiny/drag_vars_to_plot/app.R", package = "sortable")Define options to pass to a sortable object.
Description
Use this function to define the options forsortable_js andrank_list,which will pass these in turn to theSortableJS JavaScript library.
Usage
sortable_options( ..., swap = NULL, multiDrag = NULL, group = NULL, sort = NULL, delay = NULL, disabled = NULL, animation = NULL, handle = NULL, filter = NULL, draggable = NULL, swapThreshold = NULL, invertSwap = NULL, direction = NULL, scrollSensitivity = NULL, scrollSpeed = NULL, onStart = NULL, onEnd = NULL, onAdd = NULL, onUpdate = NULL, onSort = NULL, onRemove = NULL, onFilter = NULL, onMove = NULL, onLoad = NULL)Arguments
... | other arguments passed onto |
swap | If |
multiDrag | If |
group | To drag elements from one list into another, both lists musthave the same group value. SeeSortable#group-optionfor more details. [ |
sort | Boolean that allows sorting inside a list. [ |
delay | Time in milliseconds to define when the sorting should start.[ |
disabled | Boolean that disables the |
animation | Millisecond duration of the animation of items when sorting[ |
handle | CSS selector used for the drag handle selector within listitems. [ |
filter | CSS selector or JS function used for elements that cannot bedragged. [ |
draggable | CSS selector of which items inside the element should bedraggable. [ |
swapThreshold | Percentage of the target that the swap zone will takeup, as a number between |
invertSwap | Set to |
direction | Direction of |
scrollSensitivity | Number of pixels the mouse needs to be to an edge tostart scrolling. [ |
scrollSpeed | Number of pixels for the speed of scrolling. [ |
onStart,onEnd | JS function called when an element dragging starts or ends |
onAdd | JS function called when an element is dropped into the list fromanother list |
onUpdate | JS function called when the sorting is changed within a list |
onSort | JS function called by any change to the list (add / update /remove) |
onRemove | JS function called when an element is removed from the listinto another list |
onFilter | JS function called when an attempt is made to drag a filteredelement |
onMove | JS function called when an item is moved in a list or betweenlists |
onLoad | JS function dispatched on the "next tick" after SortableJS hasinitialized |
Details
Many of theSortableJS options will accept a JavaScript function. You cando this using thehtmlwidgets::JS function.
Value
A list with classsortable_options
References
https://github.com/sortablejs/Sortable/
See Also
Examples
sortable_options(sort = FALSE)Widget output function for use in Shiny.
Description
Widget output function for use in Shiny.
Usage
sortable_output(input_id, width = "0px", height = "0px")Arguments
input_id | output variable to use for the sortable object |
width | Fixed width for widget (in css units). The default is |
height | Fixed height for widget (in css units). The default is |
Change the value of a bucket list.
Description
You can only update theheader of thebucket_list.To update any of the labels or rank list text, useupdate_rank_list()instead.
Usage
update_bucket_list( css_id, header = NULL, session = shiny::getDefaultReactiveDomain())Arguments
css_id | This is the css id to use, and must be unique in your shinyapp. This defaults to the value of |
header | Text that appears at the top of the bucket list. (This isencoded as an HTML |
session | The |
See Also
Examples
## Example of a shiny app that updates a bucket list and rank listif (interactive()) { app <- system.file( "shiny/update/app.R", package = "sortable" ) shiny::runApp(app)}Change the text or labels of a rank list.
Description
Change the text or labels of a rank list.
Usage
update_rank_list( css_id, text = NULL, labels = NULL, session = shiny::getDefaultReactiveDomain())Arguments
css_id | This is the css id to use, and must be unique in your shinyapp. This defaults to the value of |
text | Text to appear at top of list. |
labels | A character vector with the text to display inside the widget.This can also be a list of html tag elements. The text content of eachlabel or label name will be used to set the shiny |
session | The |
See Also
Examples
## Example of a shiny app that updates a bucket list and rank listif (interactive()) { app <- system.file( "shiny/update_rank_list/app.R", package = "sortable" ) shiny::runApp(app)}