DragSelect Documentation
website·Indexed 32 days ago
https://dragselect.com/A professional, cross-platform library with no dependencies that adds selection and drag-and-drop functionality to web elements. It features a pub/sub event pattern, customizable settings, support for drop zones, and built-in accessibility and mobile/touch compatibility. The library provides a comprehensive API including methods for selection handling, custom filters, and integration examples for React.
What's inside DragSelect
- DragSelect is a lightweight, dependency-free JavaScript library that replicates operating system drag-selection behavior in the browser. It is designed for high performance, capable of selecting over 15,000 elements, and supports SVG, mobile touch interactions, and all major browsers. Key capabilities include accessibility (a11y) support, the use of modifier keys for multiple independent selections, and the ability to select, drag, and drop via keyboard.
Add selectable elements and event listeners in React components
Use theuseDragSelecthook to access the DragSelect instance. To make an element selectable, pass the DOM reference tods.addSelectables(). To listen for events, useds.subscribe()and ensure you callds.unsubscribe()in the cleanup function of theuseEffecthook to prevent memory leaks.import React, { useEffect, useRef } from "react"; import { useDragSelect } from "./DragSelectContext"; export const SomeOtherComponentsThatNeedsDragSelect = () => { const ds = useDragSelect(); const inputEl = useRef(null); // adding a selectable element useEffect(() => { const element = inputEl.current as unknown as HTMLElement; if (!element || !ds) return; ds.addSelectables(element); }, [ds, inputEl]); // subscribing to a callback useEffect(() => { if (!ds) return; const id = ds.subscribe("DS:end", (e) => { console.log(e); }); return () => ds.unsubscribe("DS:end", null, id!); }, [ds]); return ( <button ref={inputEl} aria-labelledby="Selectable"> Selectable </button> ); };Implement a DragSelect Context Provider for React
To use DragSelect in a 'React way', create a Context Provider that manages the instantiation and cleanup of theDragSelectinstance. This ensures the instance is available throughout the component tree and is properly stopped when the provider unmounts.import React, { createContext, useState, useEffect, useContext } from "react"; import DragSelect, { DSInputElement } from "dragselect"; type ProviderProps = { children: React.ReactNode; settings?: ConstructorParameters<typeof DragSelect<DSInputElement>>[0]; }; const Context = createContext<DragSelect<DSInputElement> | undefined>( undefined ); function DragSelectProvider({ children, settings = {} }: ProviderProps) { const [ds, setDS] = useState<DragSelect<DSInputElement>>(); useEffect(() => { setDS((prevState) => { if (prevState) return prevState; return new DragSelect({}); }); return () => { if (ds) { ds.stop(); setDS(undefined); } }; }, [ds]); useEffect(() => { ds?.setSettings(settings); }, [ds, settings]); return <Context.Provider value={ds}>{children}</Context.Provider>; } function useDragSelect() { return useContext(Context); } export { DragSelectProvider, useDragSelect };Install DragSelect via npm
DragSelect is a dependency-free library that can be installed via npm, Yarn, CDN, or by downloading binary files.npm i -S dragselectInitialize DragSelect with basic settings
DragSelect can be initialized by passing a configuration object to the constructor. All properties are optional; you can pass an empty object and update settings later.const ds = new DragSelect({ selectables: document.querySelectorAll('.selectable'), });Integrate an external drag-and-drop library using `.stop()`
To use a third-party drag-and-drop library alongside DragSelect, use the
ds.stop()method within theDS:start:preevent. This prevents DragSelect from handling the drag operation, allowing your custom library to take over. You must callds.start()once the external library has finished the operation to restore DragSelect functionality.If the external library lacks a 'finished' callback, use
setTimeout(ds.start)to debounce the restart, ensuring all scheduled callbacks complete before DragSelect reactivates.// 1. Setup DragSelect const ds = new DragSelect({ keyboardDragSpeed: 0, keyboardDrag: false, // other settings... }); // 2. Setup external library const myCustomDrag = new MyCustomDrag({ /* settings */ }); // 3. Stop DragSelect and hand over to custom library ds.subscribe('DS:start:pre', ({ items, isDragging }) => { if(isDragging) { ds.stop(false, false); myCustomDrag.start(items); } }); // 4. Restart DragSelect when finished myCustomDrag.subscribe('finished', () => ds.start());Implement keyboard accessibility for DragSelect selectables
DragSelect is accessible by default, but to ensure keyboard users can select items, all
selectablesmust be pressable/clickable elements. The recommended approach is to use buttons withtype="button".Keyboard interactions include:
- Selection: Use the default select keys (typically Space or Enter). Multi-selection is supported when using a modifier key simultaneously.
- Dragging: Use the Arrow keys to drag elements. This action scrolls the area by default.
- Fast Dragging: Use
Shift+Arrow Key(e.g.,Shift+ArrowRight) to move elements 4x faster and disable automatic area scrolling.
<!-- Ensure selectables are buttons for keyboard accessibility --> <button type="button">Item to select</button>Subscribe to DragSelect public events
DragSelect uses a PubSub pattern to emit events during selection processes. You can subscribe to these events using the
ds.subscribemethod.If you need a callback to execute before the internal DragSelect logic for a specific event, append the
:prepostfix to the event name (e.g.,DS:start:pre).const ds = new DragSelect({}); // Standard subscription ds.subscribe('<event_name>', (callback_object) => { // Handle event }); // Subscription that runs before internal logic ds.subscribe('DS:start:pre', (callback_object) => { // Handle event before internal start logic });Customize selection logic using the `filterSelected` override
To modify the selection process in DragSelect, you can override the
ds.Selection.filterSelectedmethod. This method is executed after elements have been collected for selection/deselection but before the actual selection state is applied. It is particularly useful for filtering out specific elements (e.g., parent elements or elements with specific styles) that should not be selected despite being within the selector rectangle.Warning: Overriding internal methods modifies core behavior. Verify this implementation when updating the library, as internal changes may affect the override.
// Initialize DragSelect const ds = new DragSelect({ /* config */ }); // Override the internal filterSelected method ds.Selection.filterSelected = ({ selectorRect, select: _select, unselect: _unselect }: { select: Map<DSElement, DSBoundingRect>, unselect: Map<DSElement, DSBoundingRect>, selectorRect: DSBoundingRect }) => { // Create new Maps to avoid mutating the original arguments directly const select = new Map(_select); const unselect = new Map(_unselect); // Example: Filter out elements with red text if more than 5 elements are selected select.forEach((boundingRect, element) => { if (element.style.color === 'red' && select.size > 5) { select.delete(element); unselect.set(element, boundingRect); } }); // Return the modified maps to determine final selection state return { select, unselect }; };Use DragSelect in saleable products or SDKs
An Enterprise license is required if DragSelect is included in any product that end-users are charged for. This includes:
- Software Development Kits (SDKs)
- Web application builders or website builders
- Downloadable/installable products (e.g., WordPress themes, HTML templates)
- Any product that produces copies that each use DragSelect.
Note: DragSelect cannot be used in a product where it contributes to the core value of the product being sold, and it may not be used for re-selling, sub-licensing, or redistribution on its own.
Use DragSelect under an open source license
DragSelect can be used for free if you are creating an open source application under a license compatible with the GNU GPL license v3 (GPLv3). This generally applies to non-commercial projects.Manage event subscriptions in DragSelect using Pub/Sub
DragSelect implements a publish/subscribe (pub/sub) pattern for event handling. Developers should prioritize subscribing to public events (documented in the Events API) over internal events to ensure long-term stability. To unsubscribe from an event, you must provide either the original callback handler or the subscription ID returned during the subscription process; using the subscription ID is the more performant method.const ds = new DragSelect({/* options */}); // Option 1: Unsubscribe using the subscription ID (Recommended for performance) const subscriptionId = ds.subscribe('DS:end', (callback_object) => { console.log('Selection ended', callback_object); }); ds.unsubscribe('DS:end', null, subscriptionId); // Option 2: Unsubscribe using the handler function const callbackHandler = (callback_object) => { console.log('Selection ended', callback_object); }; ds.subscribe('DS:end', callbackHandler); ds.unsubscribe('DS:end', callbackHandler); // Manually trigger an event ds.publish('DS:end', { foo: 'bar' });