Handle and Acceptance
comins-sortable@0.1.6
Playground paths below are local routes for the module repository’s development server. They are not live routes on this documentation site.
Use selectors to control activation and callbacks to control destinations.
Complete example
Section titled “Complete example”import { useState } from 'react';import { SortableArea, SortableRoot } from 'comins-sortable/react';
type Item = { id: string; label: string };
export function HandleExample() { const [items, setItems] = useState<Item[]>([ { id: 'task-1', label: 'Plan' }, { id: 'task-2', label: 'Build' }, ]);
return ( <SortableRoot<Item>> <SortableArea areaId="tasks" items={items} itemKey="id" handle=".drag-handle" ignore="a, input, textarea, select" activationDistance={4} accept={(context) => context.source.areaId !== 'locked'} onItemsChange={(next) => setItems([...next])} > {(item) => ( <div> <button type="button" className="drag-handle" aria-label={`Drag ${item.label}`} > ⠿ </button> <span className="card-label">{item.label}</span> </div> )} </SortableArea> </SortableRoot> );}.drag-handle { touch-action: none; -webkit-user-select: none; user-select: none;}
.card-label { -webkit-user-select: text; user-select: text;}An explicit handle takes precedence over ignore. Use a real button for an
accessible handle and provide a descriptive label. activationDistance
prevents small pointer movement from immediately starting a drag.
For cards with selectable text, start moves only from the handle. Set the body’s
user-select and -webkit-user-select to text, and the handle’s to none.
Apply touch-action: none to the handle to preserve default touch behavior in
the body. The Playground uses this pattern by default and suppresses body
selection only during an active drag. Selection becomes available again after
completion or cancellation. With multiDrag, use modifier keys with handle
clicks to select items. Input outside the handle or on ignored content does not
change item selection.
Omit handle to start dragging anywhere on an item except default ignored
inputs, buttons, links, editable elements, and other ignored targets. A selector
such as handle=".card-title" restricts activation to that descendant. The
Drag start areas example compares dedicated handle, title, and whole-card
modes. Whole-card mode uses body drags for sorting; returning to handle mode
restores body-text selection. Other examples retain their default handles.
Version 0.1.4 uses effective editability for the default exclusion:
contenteditable="", "true", "plaintext-only", and inherited editable
content are protected. A contenteditable="false" descendant is not excluded
solely because its parent is editable. A custom ignore replaces the default
exclusions, and an explicit matching handle still takes precedence.
Known Safari limitation (2026-09-22): In native Safari 26.6.2, the React Playground title-only mode can leave body text selected after reordering. It reproduces from a fresh page and is not fixed by switching back to handle mode. Dedicated handle mode remains the recommended example for selectable body text. Whole-card mode intentionally uses body drags for sorting. See the reproduction and verification scope. This observation does not establish the same failure in every adapter or browser.
A handle confines pointer activation; a labelled button does not add keyboard
sorting. Active-drag text-selection suppression is the Playground’s styling and
lifecycle choice, not a global user-select rule installed by the package. If
an application needs it, scope it to that widget and release it in onAfterDrag
and on unmount.
Core prevents native browser dragstart only while processing an accepted mouse
sorting attempt, so an existing text selection cannot steal the gesture. It
does not clear the selection range. After moving a card, users can select just
the value they need and copy it. Body or link input that was not accepted as a
sorting attempt is outside this guard.
accept(context) controls a candidate destination. Group put controls which
source groups may enter. disabled blocks a source or destination area at
runtime and cancels an active owner drag.
While the pointer is over a rejected destination or a non-sortable sibling in
the same host, the target and drag preview expose
data-comins-sortable-rejection. The default styles.css applies a red outline
and a not-allowed cursor. Override them with
--comins-sortable-rejection-outline and
--comins-sortable-rejection-outline-offset. The state is removed when the
pointer returns to a valid destination or the drag ends.
Playground:
/examples/handle/react/examples/accept/react
Touch verification scope
Section titled “Touch verification scope”Browser tests send native Chromium touch input for handle sorting, body scrolling,
empty-list transfers, secondary pointers, cancellation and auto-scroll in all four
adapters. Dedicated handles use touch-action: none; the body remains available
for scrolling and text selection. Whole-card mode intentionally reserves its
body for dragging. These tests are not physical Galaxy or native Safari results.