Build Interactive Draggable Layouts With JavaScript – Swapy

Category: Javascript , Layout , Recommended | January 19, 2025
AuthorTahaSh
Last UpdateJanuary 19, 2025
LicenseMIT
Views886 views
Build Interactive Draggable Layouts With JavaScript – Swapy

Swapy is a  JavaScript library for creating dynamic and interactive layouts on the web.

Your users can easily rearrange elements within your layout using drag’n’drop or touch gestures.

Imagine a project management dashboard where users can rearrange tasks according to priority or a personalized news feed where users can prioritize content sources.

Compatible with various frameworks, including Vanilla JavaScript, React, Vue.js, and Svelte.js.

How to use it:

1. Install and import Swapy using a package manager:

# Yarn
$ yarn add swapy
# NPM
$ npm install swapy
# PNPM
$ pnpm install swapy
import { createSwapy } from 'swapy'

2. Or include the UMD version directly in your HTML file:

<script src="/dist/swapy.min.js"></script>

3. Select the container element holding the grid items you want to make draggable and pass it to the createSwapy() function:

<div class="container example">
  <div class="slot a" data-swapy-slot="1">
    <div class="item a" data-swapy-item="a">
      <div class="handle" data-swapy-handle></div>
      <div>A</div>
    </div>
  </div>
  <div class="second-row">
    <div class="slot b" data-swapy-slot="2">
      <!-- <div class="item b" data-swapy-item="b">
        <div>B</div>
      </div> -->
    </div>
    <div class="slot c" data-swapy-slot="3">
      <div class="item c" data-swapy-item="c">
        <div>C</div>
      </div>
    </div>
  </div>
  <div class="slot d" data-swapy-slot="4">
    <div class="item d" data-swapy-item="d">
      <div>D</div>
    </div>
  </div>
</div>
// ES Module
const swapy = createSwapy(document.querySelector('.example'), {
  // options here
})
// Browser
const swapy = Swapy.createSwapy(document.querySelector('.example'), {
  // options here
})

4. Exclude certain items to improve performance using the ‘data-swapy-exclude’ attribute:

<div data-swapy-item="5">
  <div data-swapy-no-drag></div>
  <button data-swapy-no-drag></button>
</div>

5. Set the swapping modes: hover, stop, and drop.

const swapy = createSwapy(document.querySelector('.example'), {
  swapMode: 'drop'
})

6. Configure the animation style:

const swapy = createSwapy(document.querySelector('.example'), {
  // or 'spring', 'none'
  animation: 'dynamic'
})

7. Start the drag session after clicking and holding for a moment.

const swapy = createSwapy(document.querySelector('.example'), {
  dragOnHold: true
})

8. Enable the page auto-scroll when dragging an item near the edge.

const swapy = createSwapy(document.querySelector('.example'), {
  autoScrollOnDrag: true
})

9. Lock the drag axis to horizontal, vertical, or both.

const swapy = createSwapy(document.querySelector('.example'), {
  dragAxis: 'both', // or 'y', 'x'
})

10. Make the Swapy instance start as disabled or enabled.

const swapy = createSwapy(document.querySelector('.example'), {
  enabled: false
})

11. Track changes in element order using the following event listeners.

swapy.onSwap((event) => {
  console.log(event.newSlotItemMap.asObject)
  // {
  //   'foo': 'a',
  //   'bar': 'b',
  //   'baz': 'c'
  // }
  console.log(event.newSlotItemMap.asArray)
  // [
  //   { slot: 'foo', item: 'a' },
  //   { slot: 'bar', item: 'b' },
  //   { slot: 'baz', item: 'c' }
  // ]
  console.log(event.newSlotItemMap.asMap)
  // Map(3) {
  // 'foo' => 'a',
  // 'bar' => 'b',
  // 'baz' => 'c'
  // }
  console.log(event.fromSlot)
  // 'foo'
  console.log(event.toSlot)
  // 'bar'
  console.log(event.draggingItem)
  // 'b'
  console.log(event.swappedWithItem)
  // 'a'
});
swapy.onSwapStart(event) => {
  console.log(event.slotItemMap.asObject)
  // {
  //   'foo': 'a',
  //   'bar': 'b',
  //   'baz': 'c'
  // }
  console.log(event.slotItemMap.asArray)
  // [
  //   { slot: 'foo', item: 'a' },
  //   { slot: 'bar', item: 'b' },
  //   { slot: 'baz', item: 'c' }
  // ]
  console.log(event.slotItemMap.asMap)
  // Map(3) {
  // 'foo' => 'a',
  // 'bar' => 'b',
  // 'baz' => 'c'
  // }
  console.log(event.fromSlot)
  // 'foo'
  console.log(event.draggingItem)
  // 'a'
});
swapy.onSwapEnd(event) => {
  console.log(event.slotItemMap.asObject)
  // {
  //   'foo': 'a',
  //   'bar': 'b',
  //   'baz': 'c'
  // }
  console.log(event.slotItemMap.asArray)
  // [
  //   { slot: 'foo', item: 'a' },
  //   { slot: 'bar', item: 'b' },
  //   { slot: 'baz', item: 'c' }
  // ]
  console.log(event.slotItemMap.asMap)
  // Map(3) {
  // 'foo' => 'a',
  // 'bar' => 'b',
  // 'baz' => 'c'
  // }
  console.log(event.hasChanged)
  // false
});
swapy.onBeforeSwap(event) => {
  console.log(event.fromSlot)
  // 'foo'
  console.log(event.toSlot)
  // 'bar'
  console.log(event.draggingItem)
  // 'b'
  console.log(event.swappedWithItem)
  // 'a'
  return event.toSlot !== 'foo'
});

12. Enable & disable the draggable functionality.

swapy.enable(true)
swapy.enable(false)

13. Update the instance.

swapy.update()

14. Get current slotItemMap from a Swapy instance.

const currentSlotItemMap = swapy.slotItemMap()
console.log(currentSlotItemMap.asObject)
// {
//   'foo': 'a',
//   'bar': 'b',
//   'baz': 'c'
// }
console.log(currentSlotItemMap.asArray)
// [
//   { slot: 'foo', item: 'a' },
//   { slot: 'bar', item: 'b' },
//   { slot: 'baz', item: 'c' }
// ]
console.log(currentSlotItemMap.asMap)
// Map(3) {
// 'foo' => 'a',
// 'bar' => 'b',
// 'baz' => 'c'
// }

15. Destroy the instance.

swapy.destroy()

See Also:

Changelog:

v1.0.5 (01/19/2025)

  • Fix hasChanged in swapEnd event for manualSwap
  • Fix dragging handle with nested children

v1.0.3 (12/20/2024)

  • Allow scroll on non-handle elements.

v1.0.2 (12/16/2024)

  • Bugfixes

v1.0.1 (12/14/2024)

  • Fix click interactions in items.

v1.0.0 (12/14/2024)

  • Minor API Tweaks – Some event objects have been updated for better consistency and clarity. Check out the events section to learn about them.
  • Zero Dependencies – Swapy is now fully written in pure JS with no external dependencies (without Veloxi).
  • New Config Options – Added dragOnHold, dragAxis, and enabled to give you more control over your setup.
  • Non-Draggable Areas – You can now specify areas in your items that are not draggable. Check out no-drag attribute.
  • Dynamic Updates – Use the new update method to refresh your Swapy instance dynamically as the DOM changes.
  • Swap Control – Now you can easily enable or disable swaps dynamically with onBeforeSwap.
  • Custom Drag Styling – Customize your drag item styles using the new [data-swapy-dragging] CSS selector.
  • Easier Framework Integration – New utility functions to seamlessly integrate with frameworks and dynamically add/remove items.

v0.4.2 (10/08/2024)

  • Clean up event listeners when swapping with manualSwap.

v0.4.1 (09/30/2024)

  • Fix hasChanged in swapEnd event

v0.4.0 (09/30/2024)

  • Enabling autoScrollOnDrag in Swapy’s config options will cause the page or container to auto-scroll when dragging an item near the edge.
  • The swapEnd event object now includes a new parameter, hasChanged, which indicates whether any items were swapped during the drag session.
  • Bugfixes.

v0.3.1 (09/22/2024)

  • Fix conflict between drop swap mode and continuous mode.

v0.3.0 (09/21/2024)

  • Swapy now has 3 different swapping modes: hover, stop, and drop.
  • New swap events
  • Bugfixes

v0.2.1 (09/09/2024)

  • Fix calling swapy.setData() error when the Swapy instance is being installed.
  • Add missing TypeScript types.

v0.2.0 (09/08/2024)

  • You can allow your framework to manage the swaps by using the manualSwap option.
  • Swapy now includes a destroy method for cleanup.
  • Allow scrolling if the item has a handle

v0.1.2 (08/28/2024)

  • Support dynamic slots
  • Fix drag position after scroll

v0.1.1 (08/05/2024)

  • Improve performance

v0.1.0 (07/28/2024)

  • Continuous Mode
  • Improve performance for large datasets with data-swapy-exclude
  • Disable scale animation for text
  • Bugfixes

v0.0.6 (07/24/2024)

  • Update root element type in createSwapy to allow for null
  • Passing null to createSwapy will throw an error.

You Might Be Interested In:


Leave a Reply