Skip to main content

Shiny-sortable

A Python library to add sortable functionality to Shiny UI elements.

Basic Usage

The easiest way to build a sortable shiny widget is to use the @make() decorator.

The @make() decorator has three optional arguments:

  1. ID (str): The keyword argument name to extract the input ID from, defaults to 'inputID', if not found, defaults to the first argument.
  2. dataID (str): The attribute used to store data-id on sortable items.
  3. updatable (bool): Whether the sortable items should be updatable.

Let's use an ordered list as an example:

from shiny import *
import shiny_sortable as sortable

@sortable.make()
def sortable_list(inputID): # add `inputID` as the first argument
    list = ui.tags.ol(
        ui.tags.li("Item 1", **{'data-id': '1'}),
        ui.tags.li("Item 2", **{'data-id': '2'}),
        ui.tags.li("Item 3", **{'data-id': '3'}),
        id=inputID
    )
    return list

This allows a sortable list when it is added to the UI:

app_ui = ui.page_fluid(
    sortable_list("list"),
)
app = App(app_ui, None)

The list will look like this:

A sortable list

Alternatively, you can use your own keyword arguments:

@sortable.make(ID="SomeRandomID", dataID="SomeDataId")
def sortable_list(SomeRandomID): # use `SomeRandomID` as the first argument
    list = ui.tags.ol(
        ui.tags.li("Item 1", SomeDataId = '1'),
        ui.tags.li("Item 2", SomeDataId = '2'),
        ui.tags.li("Item 3", SomeDataId = '3'),
        id=SomeRandomID
    )
    return list

The order of the items can be retrieved as a Shiny input:

from shiny import *
import shiny_sortable as sortable

@sortable.make()
def sortable_list(inputID):
    list = ui.tags.ol(
        ui.tags.li("Item 1", **{'data-id': '1'}),
        ui.tags.li("Item 2", **{'data-id': '2'}),
        ui.tags.li("Item 3", **{'data-id': '3'}),
        id=inputID
    )
    return list

app_ui = ui.page_fluid(
    sortable_list("list"),
    ui.output_text_verbatim(id = "text")
)

def server(input, output, session):
    list_order = reactive.value("")
    @output
    @render.text
    def text():
        return list_order()

    @reactive.effect
    @reactive.event(input.list)
    def _():
        list_order.set(input.list())

app = App(app_ui, server)

This mini-app runs like this: alt text

Moreover, we can make the sortable widget updatable by passing updatable=True to the @make() decorator. This allows the order to be updated by using the update() function.

For example, we can add a "Reset" button to the UI which will reset the list order to the initial state of 123.

from shiny import *
import shiny_sortable as sortable

@sortable.make(updatable=True)
def sortable_list(inputID):
    list = ui.tags.ol(
        ui.tags.li("Item 1", **{'data-id': '1'}),
        ui.tags.li("Item 2", **{'data-id': '2'}),
        ui.tags.li("Item 3", **{'data-id': '3'}),
        id=inputID
    )
    return list

app_ui = ui.page_fluid(
    sortable_list("list"),
    ui.output_text_verbatim(id = "text"),
    ui.input_action_button("reset", "Reset")
)

def server(input, output, session):
    list_order = reactive.value("")
    @output
    @render.text
    def text():
        return list_order()

    @reactive.effect
    @reactive.event(input.list)
    def _():
        list_order.set(input.list())

    @reactive.effect
    @reactive.event(input.reset)
    async def _():
        await sortable.update(session, "list", ["1", "2", "3"])


app = App(app_ui, server)

This mini-app runs like this:

alt text

Not that for updating the sortable widget, async and await are required, since session.send_custom_message() is used behind the scenes.

Custom Usage

There are also three internally used functions which can be used to create custom widgets.

  • dep(): Creates and returns a SortableJS HTML dependency. Behind the scenes, it does:
    sortable_dep = HTMLDependency(
         name="SortableJS",
         version="1.15.3",
         source={
             "href": "https://cdnjs.cloudflare.com/ajax/libs/Sortable/1.15.3"
         },
         script={"src": "Sortable.min.js"},
     )
     return sortable_dep
    
  • input(): Returns a script tag for initializing a Sortable instance on an element. The tag looks like:
    script = f"""
     var el_{inputID} = document.getElementById('{inputID}');
     if (el_{inputID}) {{
         var sortable_{inputID} = new Sortable(el_{inputID}, {{
             dataIdAttr: '{dataID}',
             animation: 150,
             ghostClass: 'sortable-ghost',
             chosenClass: 'sortable-chosen',
             onSort: function (evt) {{
                 var order = sortable_{inputID}.toArray();
                 Shiny.setInputValue("{inputID}", order);
             }}
         }});
     }} else {{
         console.error("Element with id '{inputID}' not found");
     }}
     """
     return tags.script(script)
    
  • output(): Returns a script tag for handling updates to the Sortable instance order. The tag looks like:
    script = f"""
     Shiny.addCustomMessageHandler("sortable_update_{outputID}", function(message) {{
         if (typeof sortable_{outputID} !== 'undefined') {{
             sortable_{outputID}.sort(message.order);
             Shiny.setInputValue("{outputID}", message.order);
         }} else {{
             console.error("sortable_{outputID} is not defined. Cannot update order.");
         }}
     }});
     """
     return tags.script(script)
    

Metadata

Release files for shiny-sortable 0.1.4

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for shiny-sortable 0.1.4
File Size Uploaded
shiny_sortable-0.1.4.tar.gz 4.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for shiny-sortable 0.1.4
File Interpreter ABI Platform
shiny_sortable-0.1.4-py3-none-any.whl Python 3 none any Details

Total release size: 10.6 kB

Release files / shiny_sortable-0.1.4.tar.gz

Download URL shiny_sortable-0.1.4.tar.gz
Size 4.9 kB
Tags Source
SHA-256 checksum
How to use checksums
db34cb6e7c118c817d79a07a526586a4cb07b905c1b0c2d358d4ea994a7ef30b
BLAKE2b-256 checksum
How to use checksums
360121b84566ee8952d155f3b7c2ae8837107fe76de184b87206e68867e1d025
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/5.1.1 CPython/3.12.4

Release files / shiny_sortable-0.1.4-py3-none-any.whl

Download URL shiny_sortable-0.1.4-py3-none-any.whl
Size 5.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
21f4a6eb51d27bd849c3bd643506ff21542be35a145c2959f7b39104758e7210
BLAKE2b-256 checksum
How to use checksums
5fd53e09ffbd21569b23a6b670fe23ed274dd64a90297fd3cd22caa6252ebb53
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/5.1.1 CPython/3.12.4

Release history Release notifications | RSS feed

This release

0.1.4 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page