Sortable
<quiet-sortable>
Enables drag and drop sorting of arbitrary elements.
Sortable enables drag-and-drop reordering of its direct child elements using mouse, touch, and keyboard inputs. As an item is dragged, its siblings smoothly shift to make room at the new position. Every direct child element is sortable by default.
<quiet-sortable id="sortable__basic"> <div class="item"> <img alt="Sir Fluffington III" src="https://images.unsplash.com/photo-1514888286974-6c03e2ca1dba?q=80&w=256&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"> <div> <div class="name">Sir Fluffington III</div> <div class="description">Professional napper and treat connoisseur</div> </div> </div> <div class="item"> <img alt="Meowy McGee" src="https://images.unsplash.com/photo-1529778873920-4da4926a72c2?q=80&w=256&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"> <div> <div class="name">Meowy McGee</div> <div class="description">Freedom's just another word for nothing left to lose</div> </div> </div> <div class="item"> <img alt="Whisker Doodle" src="https://images.unsplash.com/photo-1574158622682-e40e69881006?q=80&w=256&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"> <div> <div class="name">Whisker Doodle</div> <div class="description">Part-time philosopher, full-time lap cat</div> </div> </div> <div class="item"> <img alt="Chairman Meow" src="https://images.unsplash.com/photo-1569591159212-b02ea8a9f239?q=80&w=256&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"> <div> <div class="name">Chairman Meow</div> <div class="description">Demands belly rubs on his own terms</div> </div> </div> <div class="item"> <img alt="Purrlock Holmes" src="https://images.unsplash.com/photo-1526336024174-e58f5cdd8e13?q=80&w=256&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"> <div> <div class="name">Purrlock Holmes</div> <div class="description">Solves the mystery of the missing treats</div> </div> </div> </quiet-sortable> <style> #sortable__basic { gap: 0.5rem; .item { display: flex; align-items: center; gap: 0.75rem; padding: 0.75rem 1rem; background-color: var(--quiet-paper-color); border: var(--quiet-border-style) var(--quiet-border-width) var(--quiet-neutral-stroke-softer); border-radius: var(--quiet-border-radius-md); box-shadow: var(--quiet-shadow-softer); color: var(--quiet-neutral-text-on-soft); } img { flex: 0 0 auto; width: 48px; height: 48px; border-radius: var(--quiet-border-radius-circle); object-fit: cover; } .name { font-weight: var(--quiet-font-weight-semibold); } .description { font-size: 0.875rem; color: var(--quiet-text-muted); } } </style>
Examples Jump to heading
Using handles Jump to heading
By default, the entire item is draggable. To restrict dragging to a specific element, set the
handles attribute to a CSS selector that matches the handle elements within each item. Any
valid CSS selector works with the handles attribute, for example
handles=".grip" will target a handle with class="grip" and
handles="quiet-icon" will target <quiet-icon> elements.
Handle elements must be inside the sortable item. Elements matching the selector that exist outside of an item will be ignored. If multiple elements within an item match the selector, clicking any of them will start a drag.
<quiet-sortable handles=".handle" id="sortable__handles"> <div class="item"> <quiet-icon class="handle" name="grip-vertical"></quiet-icon> <span>Feed the cats</span> </div> <div class="item"> <quiet-icon class="handle" name="grip-vertical"></quiet-icon> <span>Change the litter box</span> </div> <div class="item"> <quiet-icon class="handle" name="grip-vertical"></quiet-icon> <span>Buy catnip</span> </div> <div class="item"> <quiet-icon class="handle" name="grip-vertical"></quiet-icon> <span>Schedule vet appointment</span> </div> <div class="item"> <quiet-icon class="handle" name="grip-vertical"></quiet-icon> <span>Playtime</span> </div> </quiet-sortable> <style> #sortable__handles { gap: 0.5rem; .item { display: flex; align-items: center; gap: 0.75rem; padding: 0.75rem 1rem; background-color: var(--quiet-paper-color); border: var(--quiet-border-style) var(--quiet-border-width) var(--quiet-neutral-stroke-softer); border-radius: var(--quiet-border-radius-md); box-shadow: var(--quiet-shadow-softer); color: var(--quiet-neutral-text-on-soft); quiet-icon { font-size: 1.25em; } } .handle { cursor: grab; color: var(--quiet-text-muted); &:active { cursor: grabbing; } } } </style>
When handles are set, the container's default grab cursor is suppressed. You should add your own
cursor: grab styles to handle elements so users know where to click to drag.
For more advanced handle logic, you can set the handles property to a callback function
instead. The function receives each element in the event path and the direct child item, and should return
true for elements that are valid drag handles.
sortable.handles = (el, item) => { return el.classList.contains('grip'); };
Grouping Jump to heading
Items can be dragged between sortable containers that share the same group attribute. This is
useful for kanban-style boards and similar interfaces.
To Do
Done
<div id="sortable__grouping"> <div class="column"> <h4>To Do</h4> <quiet-sortable group="tasks"> <div class="item">Research competitors</div> <div class="item">Write specifications</div> <div class="item">Design mockups</div> </quiet-sortable> </div> <div class="column"> <h4>Done</h4> <quiet-sortable group="tasks"> <div class="item">Set up repository</div> <div class="item">Create project plan</div> </quiet-sortable> </div> </div> <style> #sortable__grouping { display: flex; gap: 2rem; @media (max-width: 480px) { flex-direction: column; } .column { flex: 1 1 0; h4 { margin: 0 0 0.75rem; } } .column + .column { border-left: var(--quiet-border-style) var(--quiet-border-width) var(--quiet-neutral-stroke-softer); padding-left: 2rem; @media (max-width: 480px) { border-left: none; padding-left: 0; border-top: var(--quiet-border-style) var(--quiet-border-width) var(--quiet-neutral-stroke-softer); padding-top: 2rem; } } quiet-sortable { gap: 0.5rem; min-height: 100px; border-radius: var(--quiet-border-radius-xs); outline-offset: 0.5rem; } .item { padding: 0.75rem 1rem; background-color: var(--quiet-paper-color); border: var(--quiet-border-style) var(--quiet-border-width) var(--quiet-neutral-stroke-softer); border-radius: var(--quiet-border-radius-md); box-shadow: var(--quiet-shadow-softer); color: var(--quiet-neutral-text-on-soft); } } </style>
When using groups, it's a good idea to set a min-height on each container so it remains a
visible drop target even when all of its items have been dragged out.
Drop validation Jump to heading
When using groups, you can control which containers accept which items by setting the
accepts property on the target container. The callback receives the dragged item and the source
container, and should return true to accept or false to reject.
Containers that reject the item receive the drop-invalid CSS state at drag start, letting you
style them to indicate they won't accept the item. Containers that accept receive the
drop-target state.
sortable.accepts = (item, sourceContainer) => { return item.dataset.priority === 'high'; };
In this example, the second container only accepts high-priority items.
All Tasks
High Priority Only
<div id="sortable__accepts"> <div class="column"> <h4>All Tasks</h4> <quiet-sortable group="validated" id="sortable__accepts-all"> <div class="item" data-priority="high">High priority task</div> <div class="item" data-priority="low">Low priority task</div> <div class="item" data-priority="high">Another high priority</div> <div class="item" data-priority="low">Another low priority</div> </quiet-sortable> </div> <div class="column"> <h4>High Priority Only</h4> <quiet-sortable group="validated" id="sortable__accepts-high"> </quiet-sortable> </div> </div> <script> const highOnly = document.getElementById('sortable__accepts-high'); highOnly.accepts = (item, sourceContainer) => { return item.dataset.priority === 'high'; }; </script> <style> #sortable__accepts { display: flex; gap: 2rem; @media (max-width: 480px) { flex-direction: column; } .column { flex: 1 1 0; h4 { margin: 0 0 0.75rem; } } .column + .column { border-left: var(--quiet-border-style) var(--quiet-border-width) var(--quiet-neutral-stroke-softer); padding-left: 2rem; @media (max-width: 480px) { border-left: none; padding-left: 0; border-top: var(--quiet-border-style) var(--quiet-border-width) var(--quiet-neutral-stroke-softer); padding-top: 2rem; } } quiet-sortable { gap: 0.5rem; min-height: 100px; border-radius: var(--quiet-border-radius-md); outline-offset: 0.25rem; } .item { padding: 0.75rem 1rem; background-color: var(--quiet-paper-color); border-radius: var(--quiet-border-radius-md); } .item[data-priority="low"] { background: var(--quiet-primary-fill-soft); color: var(--quiet-primary-text-on-soft); } .item[data-priority="high"] { background: var(--quiet-destructive-fill-soft); color: var(--quiet-destructive-text-on-soft); } } </style>
Filtering items Jump to heading
Use the filter property to control which items can be dragged. Set it to a function that
receives the item element and returns true to allow dragging or false to prevent
it.
sortable.filter = (item) => { return !item.classList.contains('locked'); };
In this example, items with the locked class cannot be dragged.
<quiet-sortable id="sortable__can-drag"> <div class="item">Draggable item</div> <div class="item locked">Locked item</div> <div class="item">Draggable item</div> <div class="item locked">Locked item</div> <div class="item">Draggable item</div> </quiet-sortable> <script> const filterSortable = document.getElementById('sortable__can-drag'); filterSortable.filter = (item) => { return !item.classList.contains('locked'); }; </script> <style> #sortable__can-drag { gap: 0.5rem; .item { display: flex; align-items: center; padding: 0.75rem 1rem; background-color: var(--quiet-paper-color); border: var(--quiet-border-style) var(--quiet-border-width) var(--quiet-neutral-stroke-softer); border-radius: var(--quiet-border-radius-md); box-shadow: var(--quiet-shadow-softer); color: var(--quiet-neutral-text-on-soft); &.locked { opacity: 0.5; cursor: not-allowed; } } } </style>
It's usually a good idea to apply cursor: not-allowed to locked items via CSS.
Scrollable containers Jump to heading
When dragging items inside a scrollable container, the container will automatically scroll as the pointer approaches its edges. The closer the pointer gets to an edge, the faster it scrolls.
<quiet-sortable id="sortable__scrollable"> <div class="item">Astronomy</div> <div class="item">Biology</div> <div class="item">Chemistry</div> <div class="item">Dentistry</div> <div class="item">Engineering</div> <div class="item">Forestry</div> <div class="item">Geography</div> <div class="item">History</div> <div class="item">Immunology</div> <div class="item">Journalism</div> <div class="item">Kinesiology</div> <div class="item">Linguistics</div> </quiet-sortable> <style> #sortable__scrollable { max-height: 200px; overflow-y: auto; gap: 0.5rem; padding: 1rem; margin: -1rem; background-color: var(--quiet-neutral-fill-softest); border-radius: var(--quiet-border-radius-md); .item { padding: 0.75rem 1rem; background-color: var(--quiet-paper-color); border: var(--quiet-border-style) var(--quiet-border-width) var(--quiet-neutral-stroke-softer); border-radius: var(--quiet-border-radius-md); box-shadow: var(--quiet-shadow-softer); color: var(--quiet-neutral-text-on-soft); } } </style>
Copying items Jump to heading
By default, dragging an item between grouped containers moves it. To copy items instead, set the
copy property on the source container. This callback receives the dragged item and returns a
new element to insert at the drop position. Return a falsy value to fall back to normal move behavior.
sortable.copy = (item) => { return item.cloneNode(true); };
The source item never leaves its container. A visual ghost follows the pointer and the copy animates into place on drop. The source container is inert during a copy drag, so its items won't rearrange and dropping back on it cancels the drag.
Since you control what the callback returns, you can return any element: a modified clone or a completely different element.
sortable.copy = (item) => { const el = document.createElement('div'); el.className = 'card'; el.textContent = `Copy of ${item.textContent}`; el.dataset.sourceId = item.id; return el; };
Try dragging items from the components palette into the page.
Components
Page
<div id="sortable__copy"> <div class="column"> <h4>Components</h4> <quiet-sortable group="builder" id="sortable__palette"> <div class="item">Button</div> <div class="item">Input</div> <div class="item">Card</div> </quiet-sortable> </div> <div class="column"> <h4>Page</h4> <quiet-sortable group="builder" id="sortable__canvas"> </quiet-sortable> </div> </div> <script> const copyPalette = document.getElementById('sortable__palette'); let copyCount = 1; copyPalette.copy = (item) => { const clone = item.cloneNode(true); clone.textContent = `${item.textContent} ${copyCount++}`; return clone; }; </script> <style> #sortable__copy { display: flex; gap: 2rem; .column { flex: 1 1 0; h4 { margin: 0 0 0.75rem; } } quiet-sortable { gap: 0.5rem; min-height: 100px; padding: 0.75rem; background-color: var(--quiet-neutral-fill-softest); border-radius: var(--quiet-border-radius-md); } .item { padding: 0.75rem 1rem; background-color: var(--quiet-paper-color); border: var(--quiet-border-style) var(--quiet-border-width) var(--quiet-neutral-stroke-softer); border-radius: var(--quiet-border-radius-md); box-shadow: var(--quiet-shadow-softer); color: var(--quiet-neutral-text-on-soft); } } </style>
Horizontal layout Jump to heading
Apply flex-direction: row to the sortable container for horizontal sorting.
<quiet-sortable id="sortable__horizontal"> <div class="box" style="background-color: #f05655;">1</div> <div class="box" style="background-color: #f0803a;">2</div> <div class="box" style="background-color: #5dbb56;">3</div> <div class="box" style="background-color: #4b97f4;">4</div> <div class="box" style="background-color: #937cfb;">5</div> </quiet-sortable> <style> #sortable__horizontal { flex-direction: row; gap: 1rem; .box { display: flex; align-items: center; justify-content: center; width: 80px; height: 80px; border-radius: var(--quiet-border-radius-md); color: white; font-size: 1.25rem; font-weight: var(--quiet-font-weight-semibold); } } </style>
Horizontal flex layout Jump to heading
To arrange sortable items horizontally with wrapping, apply flex-direction: row and
flex-wrap: wrap to the host element.
<quiet-sortable id="sortable__horizontal-flex"> <span class="tag" style="background-color: #f05655;">Tabby</span> <span class="tag" style="background-color: #f0803a;">Calico</span> <span class="tag" style="background-color: #e89b25;">Siamese</span> <span class="tag" style="background-color: #48b873;">Persian</span> <span class="tag" style="background-color: #4b97f4;">Maine Coon</span> <span class="tag" style="background-color: #ae76f6;">Sphynx</span> </quiet-sortable> <style> #sortable__horizontal-flex { flex-direction: row; flex-wrap: wrap; gap: 0.5rem; .tag { padding: 0.5rem 1rem; border-radius: var(--quiet-border-radius-pill); color: white; font-weight: var(--quiet-font-weight-semibold); } } </style>
Grid layout Jump to heading
Sortable works with CSS grid layouts as well.
<quiet-sortable id="sortable__grid"> <div class="tile" style="background-color: #f05655;">1</div> <div class="tile" style="background-color: #f0803a;">2</div> <div class="tile" style="background-color: #e89b25;">3</div> <div class="tile" style="background-color: #5dbb56;">4</div> <div class="tile" style="background-color: #48b873;">5</div> <div class="tile" style="background-color: #20b9bd;">6</div> <div class="tile" style="background-color: #4b97f4;">7</div> <div class="tile" style="background-color: #937cfb;">8</div> <div class="tile" style="background-color: #e468b0;">9</div> </quiet-sortable> <style> #sortable__grid { display: grid; grid-template-columns: repeat(3, 100px); @media (max-width: 480px) { grid-template-columns: repeat(auto-fill, minmax(100px, 1fr)); } gap: 1rem; .tile { display: flex; align-items: center; justify-content: center; height: 80px; border-radius: var(--quiet-border-radius-md); color: white; font-size: 1.25rem; font-weight: var(--quiet-font-weight-semibold); } } </style>
Block layout Jump to heading
Block containers work as expected. The component defaults to a column flex layout, but you can set
display: block on the host element to use block layout instead.
<quiet-sortable id="sortable__block"> <div class="item">Item 1</div> <div class="item">Item 2</div> <div class="item">Item 3</div> <div class="item">Item 4</div> </quiet-sortable> <style> #sortable__block { display: block; .item { padding: 0.75rem 1rem; margin-block-end: 0.5rem; background-color: var(--quiet-paper-color); border: var(--quiet-border-style) var(--quiet-border-width) var(--quiet-neutral-stroke-softer); border-radius: var(--quiet-border-radius-md); box-shadow: var(--quiet-shadow-softer); color: var(--quiet-neutral-text-on-soft); } } </style>
Custom animation Jump to heading
Set the --duration and --easing custom properties to control the rearrangement
animation. The default duration is 0.15s with an ease timing function.
<quiet-sortable id="sortable__animation" style="--duration: 0.5s; --easing: cubic-bezier(0.34, 1.56, 0.64, 1);"> <div class="item">Slow and bouncy</div> <div class="item">Try reordering</div> <div class="item">These items</div> <div class="item">To see the effect</div> </quiet-sortable> <style> #sortable__animation { gap: 0.5rem; .item { padding: 0.75rem 1rem; background-color: var(--quiet-paper-color); border: var(--quiet-border-style) var(--quiet-border-width) var(--quiet-neutral-stroke-softer); border-radius: var(--quiet-border-radius-md); box-shadow: var(--quiet-shadow-softer); color: var(--quiet-neutral-text-on-soft); } } </style>
Disabling animations Jump to heading
Add the without-animation attribute to disable all rearrangement animations. Items will still
be dragged and reordered, but siblings won't animate into their new positions.
<quiet-sortable without-animation id="sortable__without-animation"> <div class="item">No animation</div> <div class="item">Items still reorder</div> <div class="item">But without transitions</div> <div class="item">Try dragging these</div> </quiet-sortable> <style> #sortable__without-animation { gap: 0.5rem; .item { padding: 0.75rem 1rem; background-color: var(--quiet-paper-color); border: var(--quiet-border-style) var(--quiet-border-width) var(--quiet-neutral-stroke-softer); border-radius: var(--quiet-border-radius-md); box-shadow: var(--quiet-shadow-softer); color: var(--quiet-neutral-text-on-soft); } } </style>
Disabled Jump to heading
Add the disabled attribute to prevent sorting.
<quiet-sortable disabled id="sortable__disabled"> <div class="item">Can't drag me</div> <div class="item">Or me</div> <div class="item">Or me either</div> </quiet-sortable> <style> #sortable__disabled { gap: 0.5rem; .item { padding: 0.75rem 1rem; background-color: var(--quiet-paper-color); border: var(--quiet-border-style) var(--quiet-border-width) var(--quiet-neutral-stroke-softer); border-radius: var(--quiet-border-radius-md); box-shadow: var(--quiet-shadow-softer); color: var(--quiet-neutral-text-on-soft); } } </style>
Listening to events Jump to heading
The quiet-sort-start event is dispatched when a drag begins. You can call
event.preventDefault() to prevent it. As the item is dragged, quiet-sort-move is
dispatched each time it moves to a new position.
When an item is dropped, quiet-before-sort-end is dispatched before the move is finalized and
is cancelable. Call event.preventDefault() to prevent the move and return the item to its
source. After the drop animation completes, quiet-sort-end is dispatched as confirmation.
If the drag is canceled via Esc, dropping outside a container, or calling
cancel() programmatically, the item returns to its source and quiet-sort-cancel is
dispatched.
<div id="sortable__events"> <quiet-sortable> <div class="item">Item 1</div> <div class="item">Item 2</div> <div class="item">Item 3</div> <div class="item">Item 4</div> </quiet-sortable> <p><small>Try dragging an item and check the console for events.<small></p> </div> <script> const eventsContainer = document.getElementById('sortable__events'); const eventsSortable = eventsContainer.querySelector('quiet-sortable'); eventsSortable.addEventListener('quiet-sort-start', event => { console.log('sort-start:', event.detail); }); eventsSortable.addEventListener('quiet-sort-move', event => { console.log('sort-move:', event.detail); }); eventsSortable.addEventListener('quiet-before-sort-end', event => { console.log('before-sort-end:', event.detail); }); eventsSortable.addEventListener('quiet-sort-end', event => { console.log('sort-end:', event.detail); }); eventsSortable.addEventListener('quiet-sort-cancel', event => { console.log('sort-cancel:', event.detail); }); </script> <style> #sortable__events { quiet-sortable { gap: 0.5rem; margin-block-end: 0.5rem; } .item { padding: 0.75rem 1rem; background-color: var(--quiet-paper-color); border: var(--quiet-border-style) var(--quiet-border-width) var(--quiet-neutral-stroke-softer); border-radius: var(--quiet-border-radius-md); box-shadow: var(--quiet-shadow-softer); color: var(--quiet-neutral-text-on-soft); } } </style>
Keyboard support Jump to heading
Items can be reordered using the keyboard. Use Tab to focus an item, then press Space or Enter to grab it. While grabbed, use ↑ ↓ to move the item, then press Space or Enter to drop it in place. Press Escape to cancel and return the item to its original position.
| Key | Not grabbed | Grabbed |
|---|---|---|
| ↑ ← | Focus previous item | Move item up |
| ↓ → | Focus next item | Move item down |
| Home | Focus first item | Move item to first position |
| End | Focus last item | Move item to last position |
| Space / Enter | Grab focused item | Drop item |
| Escape | — | Cancel reorder |
The component announces actions to screen readers via a live region. When an item is grabbed, moved, dropped, or canceled, a description of the action and the item's position is announced.
To style the grabbed item, use the data-grabbed attribute which is applied to the item while
it's being reordered via keyboard.
quiet-sortable [data-grabbed] { outline: solid 2px var(--quiet-focus-color); outline-offset: -2px; }
Keyboard reordering operates within a single group. Cross-container keyboard moves (e.g., between grouped sortable containers) are not currently supported.
API Jump to heading
Importing Jump to heading
The autoloader is the recommended way to import components but, if you prefer to do it manually, the following code snippets will be helpful.
To manually import <quiet-sortable> from the CDN, use the following code.
import 'https://cdn.quietui.org/v4.0.0/components/sortable/sortable.js';
To manually import <quiet-sortable> from a self-hosted distribution, use the
following code. Remember to replace /path/to/quiet with the appropriate local path.
import '/path/to/quiet/components/sortable/sortable.js';
Slots Jump to heading
Sortable supports the following slots. Learn more about using slots
| Name | Description |
|---|---|
| (default) | The elements to sort. Every direct child will be sortable. |
Properties Jump to heading
Sortable has the following properties that can be set with corresponding attributes. In many cases, the attribute's name is the same as the property's name. If an attribute is different, it will be displayed after the property. Learn more about attributes and properties
| Property | Description | Reflects | Type | Default |
|---|---|---|---|---|
disabled
|
Disables sorting. When disabled, items cannot be dragged. |
|
boolean
|
false
|
withoutAnimation
without-animation
|
Disables all drag and drop animations when present. Items will still rearrange, but without animated transitions. |
|
boolean
|
false
|
group
|
An optional group name. Sortable containers with the same group allow items to be dragged between them. |
|
string
|
''
|
handles
|
An optional handle selector or callback that restricts which elements can initiate a drag. When set
to a CSS selector string, only clicks originating from matching elements within an item will start a
drag. When set to a callback, the function receives each element in the event path and the direct
child item, and should return true
for elements that are valid drag handles.
|
|
string
|
''
|
dragThreshold
drag-threshold
|
The distance in pixels the pointer must move before a drag starts. |
|
number
|
5
|
scrollEdgeSize
scroll-edge-size
|
The size of the edge zone in pixels where auto-scrolling activates during drag. |
|
number
|
40
|
scrollMaxSpeed
scroll-max-speed
|
The maximum scroll speed in pixels per frame during auto-scrolling. |
|
number
|
15
|
filter
|
An optional callback that determines whether a specific child element can be dragged. Return
false to prevent the item from being dragged. Property only.
|
|
((item: HTMLElement) => boolean)
|
null
|
accepts
|
An optional callback set on a target container that determines whether it will accept a specific
dragged item. Return false to reject the item. Evaluated at drag start for all grouped
containers. Property only.
|
|
((item: HTMLElement, sourceContainer: QuietSortable) => boolean)
|
null
|
copy
|
An optional callback that enables copy-on-drag behavior. Called when a drag starts. Return an element to use as the copy, or return a falsy value to fall back to normal move behavior. The source container is inert during a copy drag — its items won't rearrange and it won't accept drops from other containers. Property only. |
|
((item: HTMLElement) => HTMLElement
|
null
|
Methods Jump to heading
Sortable supports the following methods. You can obtain a reference to the element and call them like functions in JavaScript. Learn more about methods
| Name | Description | Arguments |
|---|---|---|
cancel() |
Programmatically cancels the current drag, returning the item to its original position with animation. |
Events Jump to heading
Sortable dispatches the following custom events. You can listen to them the same way was native events. Learn more about custom events
| Name | Description |
|---|---|
quiet-sort-start |
Emitted when a drag starts. Cancel this event to prevent dragging. |
quiet-sort-move |
Emitted when the dragged item moves to a new position. |
quiet-before-sort-end |
Emitted immediately when the user drops an item, before the drop animation. Cancel this event to prevent the move and return the item to its source position. |
quiet-sort-end |
Emitted after the drop animation completes. This is a confirmation event. |
quiet-sort-cancel |
Emitted when a drag is canceled, after the item is returned to its source position. |
CSS custom properties Jump to heading
Sortable supports the following CSS custom properties. You can style them like any other CSS property. Learn more about CSS custom properties
| Name | Description | Default |
|---|---|---|
--duration |
The duration of the rearrangement animation. |
0.15s
|
--easing |
The easing function for the rearrangement animation. |
ease
|
Custom States Jump to heading
Sortable has the following custom states. You can target them with CSS using the selectors shown below. Learn more about custom states
| Name | Description | CSS selector |
|---|---|---|
disabled |
Applied when the component is disabled. |
:state(disabled)
|
sorting |
Applied when a drag is in progress. |
:state(sorting)
|
drag-source |
Applied to the source container for the entire duration of a drag. |
:state(drag-source)
|
drop-target |
Applied to compatible grouped containers that accept the dragged item. |
:state(drop-target)
|
drop-invalid |
Applied to compatible grouped containers that rejected the dragged item via accepts. |
:state(drop-invalid)
|
drag-over |
Applied to a grouped container when an item from another container is dragged over it. |
:state(drag-over)
|
copy-source |
Applied to the source container during a copy drag. |
:state(copy-source)
|
has-handles |
Applied when the handles property is set. |
:state(has-handles)
|
keyboard-reordering |
Applied when an item is grabbed via keyboard and is being reordered. |
:state(keyboard-reordering)
|