Skip to main content

A Python library to add sortable functionality to Shiny UI elements

Project description

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)
    

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

shiny_sortable-0.1.4.tar.gz (4.9 kB view details)

Uploaded Source

Built Distribution

shiny_sortable-0.1.4-py3-none-any.whl (5.7 kB view details)

Uploaded Python 3

File details

Details for the file shiny_sortable-0.1.4.tar.gz.

File metadata

  • Download URL: shiny_sortable-0.1.4.tar.gz
  • Upload date:
  • Size: 4.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.12.4

File hashes

Hashes for shiny_sortable-0.1.4.tar.gz
Algorithm Hash digest
SHA256 db34cb6e7c118c817d79a07a526586a4cb07b905c1b0c2d358d4ea994a7ef30b
MD5 e2a681d04cfaf45e685f669f806a9c8e
BLAKE2b-256 360121b84566ee8952d155f3b7c2ae8837107fe76de184b87206e68867e1d025

See more details on using hashes here.

File details

Details for the file shiny_sortable-0.1.4-py3-none-any.whl.

File metadata

File hashes

Hashes for shiny_sortable-0.1.4-py3-none-any.whl
Algorithm Hash digest
SHA256 21f4a6eb51d27bd849c3bd643506ff21542be35a145c2959f7b39104758e7210
MD5 322538d9274b1dacca020a25b5c4810c
BLAKE2b-256 5fd53e09ffbd21569b23a6b670fe23ed274dd64a90297fd3cd22caa6252ebb53

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page