[Svelte] DragDropProvider briefly initializes default sensors before applying the sensors prop, causing draggables to bind stale sensors permanently
- Dominant language
- TypeScript
- Stars
- 17.6k
- Forks
- 924
- Avg merge
- 2d 10h
- Merged PRs (30d)
- 2
Description
Bug summary
When using from @dnd-kit/svelte without also passing a pre-built manager prop, the internal manager is constructed as new DragDropManager({}) (empty input) in DragDropProvider.svelte. Because the constructor input has no sensors, DragDropManager falls back to defaultPreset.sensors ([PointerSensor, KeyboardSensor]) — regardless of what the caller passed via the sensors prop.
The custom sensors prop is only applied afterwards, inside a $effect:
const manager = managerProp ?? new DragDropManager({}); // <-- always default sensors here
```
$effect(() => {
manager.sensors = resolveCustomizable(sensors, defaultPreset.sensors); // applied too late
});
```
This would be harmless if it only affected the manager's own sensor registry, but each Draggable/Sortable binds sensors at mount time, reading manager.sensors synchronously in its own registration effect (dom/index.js, Draggable effects block):
```
const sensors = this.sensors?.map(descriptor) ?? [...manager2.sensors];
const unbindFunctions = sensors.map((entry) => {
const sensorInstance = ...;
return sensorInstance.bind(this, options); // binds keydown listener for KeyboardSensor
});
```
If any draggable registers before the provider's $effect corrects manager.sensors, that draggable's KeyboardSensor binding (e.g. a real keydown listener on the handle) is created and persists — it is only removed when that draggable itself unmounts, not when manager.sensors is later updated. So even though the manager's sensor list is correctly fixed a moment later, the affected draggables keep a live keyboard-activation listener for their entire lifetime.
Observed impact
Passing sensors={[PointerSensor.configure(...)]} (deliberately excluding KeyboardSensor) does not actually disable keyboard-triggered drag activation — pressing Enter on a focused draggable handle still starts a drag operation, because the KeyboardSensor was bound before the corrected sensor list took effect.
Reproduction
1. Render with a Sortable/Draggable item inside, without passing a manager prop.
2. Focus a draggable handle and press Enter.
3. Observe that a drag operation starts, even though KeyboardSensor was never included in sensors.
Expected behavior
The sensors (and plugins/modifiers) prop should be applied before any child Draggable/Sortable registers and binds its sensors — e.g. by constructing the manager with the initial prop values (new DragDropManager({ sensors, plugins, modifiers })) instead of new DragDropManager({}), so there is never a window where the default preset's sensors are live.
Workaround
Build the DragDropManager manually with the desired sensors up front and pass it via the manager prop instead of relying on the sensors prop:
const manager = new DragDropManager({ sensors: [PointerSensor], plugins: [...] });
svelte
...
Environment
- @dnd-kit/svelte, @dnd-kit/dom, @dnd-kit/abstract (please fill in exact versions from your package-lock.json/node_modules)
- Svelte 5
Contributor guide
Research direction
Start in DragDropProvider.svelte, where the internal DragDropManager is created, then read the Draggable registration effects in dom/index.js to trace when manager.sensors is read and bindings are created. Verify the reproduction with a custom sensors prop that excludes KeyboardSensor; done means child draggables never bind default sensors before the requested sensors are applied.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- frontend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100