Como Implementar Drag and Drop em Svelte
Drag and drop parece simples até você tentar construí-lo. O navegador fornece uma API nativa, mas ela vem com limitações reais: sem animações suaves, suporte inconsistente ao toque e comportamento imprevisível entre navegadores. Se você já viu itens se encaixarem de forma estranha ao serem soltos, você conhece o problema.
Este guia cobre duas abordagens práticas para implementar drag and drop em Svelte — usando a API nativa HTML5 e usando uma biblioteca — para que você possa escolher a ferramenta certa para o que está realmente construindo.
Pontos-Chave
- A API nativa HTML5 Drag and Drop funciona para reordenação simples de listas sem dependências, mas carece de animações suaves, suporte ao toque e comportamento consistente entre navegadores.
- Os runes do Svelte 5 (
$state()) e a sintaxe de atributoondragstartsimplificam o drag and drop reativo em comparação com Svelte 3/4. - Para drag and drop animado, multi-lista, compatível com toque ou acessível,
svelte-dnd-actioné uma escolha prática de biblioteca. - Eventos de drag são apenas do lado do cliente — no SvelteKit com SSR, proteja a lógica de drag com
onMountou uma verificaçãobrowser.
Entendendo as Duas Abordagens
Antes de escrever qualquer código, é útil entender entre o que você está escolhendo.
API nativa HTML5 Drag and Drop usa eventos integrados ao navegador: dragstart, dragover, dragenter, dragleave e drop. Não requer dependências e funciona bem para casos de uso simples. A desvantagem é que animações requerem trabalho manual, o suporte ao toque é inconsistente entre dispositivos e o feedback visual durante o arrasto é limitado. Você pode ler mais sobre a API na documentação de Drag and Drop do MDN.
Soluções baseadas em bibliotecas como svelte-dnd-action ou Neodrag lidam com as partes difíceis — animações FLIP suaves, suporte ao toque e interações acessíveis — prontas para uso. Elas adicionam um pequeno custo ao bundle, mas economizam tempo significativo de implementação para qualquer coisa além de uma lista ordenável básica.
Implementando Drag and Drop em Svelte 5 com a API Nativa
Aqui está um exemplo limpo de reordenação de lista única usando a sintaxe de runes do 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>
Algumas coisas que vale a pena notar sobre este padrão do Svelte 5:
$state()substitui as antigas declarações de variáveis reativas do Svelte 3/4.- O Svelte 5 também suporta a sintaxe de atributo
ondragstartalém da diretiva de evento tradicionalon:dragstart. - A lista é atualizada durante o arrasto (em
dragover), não apenas ao soltar — isso dá aos usuários feedback visual em tempo real.
Nota sobre SvelteKit: Eventos de drag são apenas do lado do cliente. Se você estiver usando SvelteKit com SSR, envolva qualquer lógica relacionada a drag em onMount ou proteja-a com uma verificação browser de $app/environment.
Discover how at OpenReplay.com.
Quando Usar svelte-dnd-action em Vez Disso
A abordagem nativa funciona para cenários simples de reordenação de lista. Mas uma vez que você precise de qualquer um dos seguintes, recorra ao svelte-dnd-action:
- Animações FLIP suaves entre posições da lista
- Drag and drop multi-lista (quadros estilo Kanban)
- Suporte ao toque e mobile sem código extra
- Interações de teclado acessíveis integradas
O padrão svelte-dnd-action é direto — você aplica uma action use:dndzone ao seu container, passa seu array de itens e manipula os eventos consider e finalize para atualizar o estado. Cada item precisa de uma propriedade id única. Combine-o com a animação flip integrada do Svelte e você obtém interações de drag com qualidade de produção em menos de 20 linhas.
| Necessidade | Use |
|---|---|
| Reordenação simples de lista, sem animações | API Nativa |
| Animações suaves, multi-lista, toque | svelte-dnd-action |
| Arrasto livre de elementos | Neodrag |
Conclusão
Para reordenação básica de lista com drag and drop em Svelte, a API nativa do navegador com runes do Svelte 5 te leva lá sem dependências. Para qualquer coisa mais complexa — quadros Kanban animados, suporte ao toque ou interações acessíveis — svelte-dnd-action é a escolha prática. Comece com a abordagem nativa para entender a mecânica, depois atualize para uma biblioteca quando seus requisitos exigirem.
Perguntas Frequentes
Não de forma confiável. O suporte para eventos de drag em dispositivos touch é inconsistente entre navegadores móveis. Para suportar mobile adequadamente, você precisa de um polyfill como mobile-drag-drop ou uma biblioteca como svelte-dnd-action que lida com interações touch nativamente.
Sim. svelte-dnd-action funciona com Svelte 5. Você declara seu array de itens com $state() e o atualiza dentro dos manipuladores de eventos consider e finalize. A diretiva use:dndzone permanece a mesma. Apenas certifique-se de que cada item em seu array tenha uma propriedade id única para que a biblioteca rastreie os elementos corretamente.
O navegador gera uma imagem fantasma padrão a partir da aparência do elemento arrastado. Você tem controle limitado sobre isso com a API nativa. Você pode personalizá-la usando event.dataTransfer.setDragImage() para fornecer um elemento personalizado ou snapshot de canvas, mas para controle visual completo durante o arrasto, uma biblioteca como svelte-dnd-action ou Neodrag é uma opção melhor.
Drag and drop multi-lista com a API nativa requer rastreamento manual de containers de origem e destino, o que fica complexo rapidamente. svelte-dnd-action simplifica isso permitindo que você aplique use:dndzone a cada container de lista e compartilhe o mesmo tipo de item entre zonas. Os itens se movem entre listas automaticamente quando arrastados através de containers.
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.