Cómo Implementar Drag and Drop en Svelte
El drag and drop parece simple hasta que intentas construirlo. El navegador te proporciona una API nativa, pero viene con limitaciones reales: sin animaciones fluidas, soporte táctil inconsistente y comportamiento impredecible entre navegadores. Si alguna vez has visto elementos encajar de forma incómoda al soltarlos, conoces el problema.
Esta guía cubre dos enfoques prácticos para implementar drag and drop en Svelte — usando la API nativa HTML5 y usando una librería — para que puedas elegir la herramienta adecuada para lo que realmente estás construyendo.
Puntos Clave
- La API nativa HTML5 Drag and Drop funciona para reordenar listas simples sin dependencias, pero carece de animaciones fluidas, soporte táctil y comportamiento consistente entre navegadores.
- Los runes de Svelte 5 (
$state()) y la sintaxis de atributoondragstartsimplifican el drag and drop reactivo en comparación con Svelte 3/4. - Para drag and drop animado, multi-lista, compatible con táctil o accesible,
svelte-dnd-actiones una opción de librería práctica. - Los eventos de arrastre son solo del lado del cliente — en SvelteKit con SSR, protege la lógica de arrastre con
onMounto una verificaciónbrowser.
Entendiendo los Dos Enfoques
Antes de escribir cualquier código, ayuda entender entre qué estás eligiendo.
La API nativa HTML5 Drag and Drop usa eventos integrados en el navegador: dragstart, dragover, dragenter, dragleave y drop. No requiere dependencias y funciona bien para casos de uso simples. El compromiso es que las animaciones requieren trabajo manual, el soporte táctil es inconsistente entre dispositivos y la retroalimentación visual durante el arrastre es limitada. Puedes leer más sobre la API en la documentación de Drag and Drop de MDN.
Las soluciones basadas en librerías como svelte-dnd-action o Neodrag manejan las partes difíciles — animaciones FLIP fluidas, soporte táctil e interacciones accesibles — de forma predeterminada. Añaden un pequeño costo al bundle pero ahorran tiempo significativo de implementación para cualquier cosa más allá de una lista ordenable básica.
Implementando Drag and Drop en Svelte 5 con la API Nativa
Aquí hay un ejemplo limpio de reordenamiento de lista única usando la sintaxis de runes de Svelte 5:
<script>
let items = $state(['Svelte', 'SvelteKit', 'Vite', 'TypeScript']);
let dragIndex = $state(null);
function handleDragStart(event, index) {
dragIndex = index;
event.dataTransfer.effectAllowed = 'move';
}
function handleDragOver(event, index) {
event.preventDefault();
if (dragIndex === null || dragIndex === index) return;
const updated = [...items];
const [moved] = updated.splice(dragIndex, 1);
updated.splice(index, 0, moved);
items = updated;
dragIndex = index;
}
function handleDragEnd() {
dragIndex = null;
}
</script>
<ul>
{#each items as item, index (item)}
<li
draggable="true"
class:dragging={dragIndex === index}
ondragstart={(e) => handleDragStart(e, index)}
ondragover={(e) => handleDragOver(e, index)}
ondragend={handleDragEnd}
>
{item}
</li>
{/each}
</ul>
<style>
li {
padding: 10px 16px;
margin: 6px 0;
background: #f1f1f1;
cursor: grab;
list-style: none;
border-radius: 4px;
}
.dragging {
opacity: 0.4;
}
</style>
Algunas cosas que vale la pena notar sobre este patrón de Svelte 5:
$state()reemplaza las antiguas declaraciones de variables reactivas de Svelte 3/4.- Svelte 5 también soporta la sintaxis de atributo
ondragstartademás de la directiva de evento tradicionalon:dragstart. - La lista se actualiza durante el arrastre (en
dragover), no solo al soltar — esto proporciona retroalimentación visual en tiempo real a los usuarios.
Nota sobre SvelteKit: Los eventos de arrastre son solo del lado del cliente. Si estás usando SvelteKit con SSR, envuelve cualquier lógica relacionada con arrastre en onMount o protégela con una verificación browser de $app/environment.
Discover how at OpenReplay.com.
Cuándo Usar svelte-dnd-action en su Lugar
El enfoque nativo funciona para escenarios simples de reordenamiento de listas. Pero una vez que necesites cualquiera de lo siguiente, recurre a svelte-dnd-action:
- Animaciones FLIP fluidas entre posiciones de lista
- Drag and drop multi-lista (tableros estilo Kanban)
- Soporte táctil y móvil sin código extra
- Interacciones de teclado accesibles integradas
El patrón de svelte-dnd-action es directo — aplicas una acción use:dndzone a tu contenedor, pasas tu array de elementos y manejas los eventos consider y finalize para actualizar el estado. Cada elemento necesita una propiedad id única. Combínalo con la animación flip integrada de Svelte y obtienes interacciones de arrastre de calidad de producción en menos de 20 líneas.
| Necesidad | Usar |
|---|---|
| Reordenamiento simple de lista, sin animaciones | API Nativa |
| Animaciones fluidas, multi-lista, táctil | svelte-dnd-action |
| Arrastre de elementos de forma libre | Neodrag |
Conclusión
Para reordenamiento básico de listas con drag and drop en Svelte, la API nativa del navegador con los runes de Svelte 5 te lleva allí sin dependencias. Para cualquier cosa más compleja — tableros Kanban animados, soporte táctil o interacciones accesibles — svelte-dnd-action es la elección práctica. Comienza con el enfoque nativo para entender la mecánica, luego actualiza a una librería cuando tus requisitos lo demanden.
Preguntas Frecuentes
No de manera confiable. El soporte para eventos de arrastre en dispositivos táctiles es inconsistente entre navegadores móviles. Para soportar móviles adecuadamente, necesitas un polyfill como mobile-drag-drop o una librería como svelte-dnd-action que maneje interacciones táctiles de forma nativa.
Sí. svelte-dnd-action funciona con Svelte 5. Declaras tu array de elementos con $state() y lo actualizas dentro de los manejadores de eventos consider y finalize. La directiva use:dndzone permanece igual. Solo asegúrate de que cada elemento en tu array tenga una propiedad id única para que la librería pueda rastrear los elementos correctamente.
El navegador genera una imagen fantasma predeterminada a partir de la apariencia del elemento arrastrado. Tienes control limitado sobre esto con la API nativa. Puedes personalizarla usando event.dataTransfer.setDragImage() para proporcionar un elemento personalizado o una captura de canvas, pero para control visual completo durante el arrastre, una librería como svelte-dnd-action o Neodrag es una mejor opción.
El drag and drop multi-lista con la API nativa requiere rastrear contenedores de origen y destino manualmente, lo cual se vuelve complejo rápidamente. svelte-dnd-action simplifica esto permitiéndote aplicar use:dndzone a cada contenedor de lista y compartir el mismo tipo de elemento entre zonas. Los elementos se mueven entre listas automáticamente cuando se arrastran a través de contenedores.
Gain Debugging Superpowers
Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers. Check our GitHub repo and join the thousands of developers in our community.