Sortable Draggable Accordion In jQuery

Sortable Draggable Accordion In jQuery
File Size: 5.99 KB
Views Total: 882
Last Update:
Publish Date:
Official Website: Go to website
License: MIT
   

A tiny jQuery script to create a sortable accordion widget where you can reorder accordion items via drag and drop. 

How to use it:

1. The accordion script requires jQuery UI's accordion widget and sortable interaction.

<link rel="stylesheet" href="/path/to/cdn/jquery-ui.css" />
<script src="/path/to/cdn/jquery.min.js"></script>
<script src="/path/to/cdn/jquery-ui.min.js"></script>

2. Create an accordion widget from unordered lists as follows.

<div id="accordion">
  <div class="group" data-section-id="1">
    <h3>Accordion 1</h3>
    <div>
      <ul class="sortable" data-list-id="1">
        <li data-item-id="1"><span class="draggable"></span>Item 1</li>
        <li data-item-id="2"><span class="draggable"></span>Item 2</li>
        <li data-item-id="3"><span class="draggable"></span>Item 3</li>
        ...
      </ul>
    </div>
  </div>
  <div class="group" data-section-id="2">
    <h3>Accordion 2</h3>
    <div>
      <ul class="sortable" data-list-id="2">
        <li data-item-id="11"><span class="draggable"></span>Item 11</li>
        <li data-item-id="12"><span class="draggable"></span>Item 12</li>
        <li data-item-id="13"><span class="draggable"></span>Item 13</li>
        ...
      </ul>
    </div>
  </div>
  ...
</div>

3. Initialize the accordion widget.

$("#accordion").accordion({
  header: "> div > h3",
  event: "click",
  active: false,
  collapsible: true
}).sortable({
  items: "> div",
  handle: "h3",
  revert: false,
  stop: function(e, ui) {
    var sectionList = $(this).sortable("toArray", { attribute: "data-section-id" });
    var sectionId = ui.item.context.dataset.sectionId;
    var index = ui.item.index();
    updateData({sectionId, sectionList});
    ui.item.children("h3").triggerHandler("focusout");
    $(this).accordion("refresh");
  }
});

4. Make the accordion sortable.

$(".sortable").sortable({
  items: "> li",
  handle: ".draggable",
  revert: true,
  revertDuration: 50,
  placeholder: "ui-sortable-placeholder",
  sort: function(event, ui){ ui.item.addClass("selected"); },
  stop: function(event, ui){ ui.item.removeClass("selected"); },
  update: function(e, ui) {
    var questionList = $(this).sortable("toArray", { attribute: "data-item-id" });
    var sectionId = e.target.dataset.listId;
    var questionId = ui.item.context.dataset.itemId;
    var index = ui.item.index();
    updateData({sectionId, questionId, questionList});
  }
});

function updateData(obj) {
  var data = JSON.stringify(obj, null, 2);
  $('.data').text(data);
}

5. Output the updated data.

<div class="display">
  <details>
    <summary>View updated data</summary>
    <pre class="data">{}</pre>
  </details>
</div>

6. Additional CSS styles for the accordion widget.

:root {
  --item-bg: #e9e9e9;
  --item-bg-hover: #f9f9f9;
  --item-border: #ccc;
  --placeholder-border:#c1780e;
  --placeholder-bg: #ffe8af;
  --ontrack-green: #b3c022;
  --ontrack-green-light: #99CD3D;
  --ontrack-green-dark: #616900;
  --draggable-icon: url(../images/draggable.gif);
  --body-padding: 40px;
}

/*************/
/* Accordion */
/*************/

#accordion {
  width: calc(50vmax - 2 * var(--body-padding));
  max-width: 400px;
  float: left;
}

#accordion > div > div {
  padding: 0;
  background-color: var(--item-border);
}

#accordion > div > h3 {
  margin: 5px 0 0 0;
}

#accordion > div > h3[aria-selected=true] {
  color: #fff !important;
  border: 1px solid var(--ontrack-green-dark);
  background: var(--ontrack-green);
  transition: all 0.15s ease;
}

#accordion > div > h3[aria-selected=false] {
  color: #454545 !important;
  transition: all 0.15s ease;
}

@media only screen and (max-width: 640px) {
  #accordion {
    width: 100%;
  }
}

/*********/
/* Items */
/*********/

ul.sortable { 
  list-style-type: none; 
  margin: 0; 
  padding: 0; 
  width: auto;
  overflow-y: hidden;
}

ul.sortable li {
  background-color: var(--item-bg);
  padding: 10px 10px 10px 15px; 
  font-size: 1rem;
  transition: background-color 0.15s ease;
}

ul.sortable li:hover {
  background-color: var(--item-bg-hover);
  transition: background-color 0.15s ease;
}

ul.sortable li:not(:last-child) {
  margin: 0 0 1px 0; 
}

.draggable {
  background-image: var(--draggable-icon);
  display: block;
  width: 18px;
  height: 18px;
  float: left;
  margin: 1px 5px 0 0;
  cursor: move;
}

.selected {
  border: 1px solid var(--item-border);
  /* box-shadow: 0px 0px 5px 2px #00000033; */
}

.ui-sortable-placeholder {
  border: 2px dashed var(--placeholder-border);
  background-color: var(--placeholder-bg) !important;
  height: 16px;
}

.ui-widget-content {
  border: 1px solid var(--item-border) !important;
}

Changelog:

2020-12-19

  • Added connected sortable list

2020-12-10

  • Code refactor

This awesome jQuery plugin is developed by rolandjlevy. For more Advanced Usages, please check the demo page or visit the official website.