This component is available on GitHub.

Stimulus Sortable

A Stimulus controller to reorder lists with drag-and-drop.

This controller is using SortableJS behind the scene.


$ yarn add stimulus-sortable

And use it in your JS file:

// Probably in app/javascript/controllers/index.js

import { Application } from '@hotwired/stimulus'
import Sortable from 'stimulus-sortable'

const application = Application.start()
application.register('sortable', Sortable)

πŸ‘€ Demo

See demo


In your model:

class Todo < ApplicationRecord
  acts_as_list # Or with a custom position system.

In your controller:

class TodosController < ApplicationController
  def update
    # Do what you want with todo_params.


  def todo_params

In your views:

Basic usage

<ul data-controller="sortable" data-sortable-animation-value="150">
  <li>Pet the cat</li>
  <li>Get the groceries</li>

With custom handler

<ul data-controller="sortable" data-sortable-handle-value=".handle">
    <svg class="handle"></svg>
    Pet the cat

    <svg class="handle"></svg>
    Get the groceries

With AJAX call

If you're using Rails UJS in your application, you can add an url as data-attribute on every items to perform an AJAX call to update the new position.

<ul data-controller="sortable" data-sortable-resource-name-value="todo">
  <%= @todos.each do |todo| %>
    <!-- <li data-sortable-update-url="/todos/1">Pet the cat</li> -->
    <li data-sortable-update-url="<%= todo_path(todo) %>"><%= todo.description %></li>
  <% end %>

By default, position will be used as param in a PATCH request. You can change it with the data-sortable-param-name-value attribute.

If you use data-sortable-resource-name-value, the name will be used. For instance, todo[position].


data-sortable-resource-name-valueundefinedName of the resource to use as AJAX param.βœ…
data-sortable-param-name-valuepositionName of the attribute to use as AJAX param.βœ…
data-sortable-response-kind-valuehtmlThe response kind you want for @rails/request.js.βœ…
data-sortable-animation-value150Animation speed moving items when sorting in milliseconds. 0 to disable.βœ…
data-sortable-handle-valueundefinedDrag handle selector within list items.βœ…

πŸŽ› Extending Controller

You can use inheritance to extend the functionality of any Stimulus component:

import Sortable from 'stimulus-sortable'

export default class extends Sortable {
  connect() {
    console.log('Do what you want here.')

    // The sortable.js instance.

    // Your options

    // Your default options

  // You can override the `end` method here.
  end({ item, newIndex }) {
    super.end({ item, newIndex })

  // You can set default options in this getter for all sortable elements.
  get defaultOptions() {
    return {
      animation: 500,

This controller will automatically have access to targets defined in the parent class.

If you override the connect, disconnect or any other methods from the parent, you'll want to call super.method() to make sure the parent functionality is executed.

β˜•οΈ Sponsors

Stimulus Component is an MIT licensed open source project and completely free to use. However, the amount of effort needed to maintain and develop new features for the project is not sustainable without proper financial backing. You can support Stimulus Components development on Github Sponsors. πŸ™

πŸ‘· Contributing

Do not hesitate to contribute to the project by adapting or adding features ! Bug reports or pull requests are welcome.

Don’t forget to drop a 🌟 on Github to support the project.

πŸ“ License

This project is released under the MIT license.