Arrastar e Soltar
Regras
- Use
@dnd-kit/core + @dnd-kit/sortable — biblioteca DnD moderna, acessível e amigável ao toque
- Listas classificáveis: envolva em
<SortableContext>, cada item usa o hook useSortable()
- Quadros Kanban:
<DndContext> com múltiplos contêineres <SortableContext> — um por coluna
- Zonas de soltar arquivos:
react-dropzone ou nativo onDragOver/onDrop com e.dataTransfer.files
- Suporte a toque: dnd-kit lida com toque nativamente — use
TouchSensor e PointerSensor com restrições de ativação
- Acessibilidade: dnd-kit fornece DnD por teclado pronto para uso —
KeyboardSensor com sortableKeyboardCoordinates
- Reordenamento otimista: atualize o estado imediatamente ao soltar, persista no servidor em segundo plano, reverta em caso de erro
- Sobreposição de arrasto: use
<DragOverlay> para uma prévia flutuante do item arrastado — melhor feedback visual
Padrões
import { DndContext, closestCenter, DragOverlay } from "@dnd-kit/core";
import { SortableContext, verticalListSortingStrategy, useSortable } from "@dnd-kit/sortable";
import { CSS } from "@dnd-kit/utilities";
function SortableItem({ id, children }: { id: string; children: React.ReactNode }) {
const { attributes, listeners, setNodeRef, transform, transition } = useSortable({ id });
const style = { transform: CSS.Transform.toString(transform), transition };
return (
<div ref={setNodeRef} style={style} {...attributes} {...listeners}>
{children}
</div>
);
}
function SortableList({ items }: { items: Item[] }) {
const [activeId, setActiveId] = useState<string | null>(null);
return (
<DndContext
collisionDetection={closestCenter}
onDragStart={({ active }) => setActiveId(active.id)}
onDragEnd={handleDragEnd}
>
<SortableContext items={items.map((i) => i.id)} strategy={verticalListSortingStrategy}>
{items.map((item) => (
<SortableItem key={item.id} id={item.id}>{item.name}</SortableItem>
))}
</SortableContext>
<DragOverlay>{activeId ? <ItemPreview id={activeId} /> : null}</DragOverlay>
</DndContext>
);
}
Evite
- Usar a API HTML5 de arrastar diretamente — suporte ruim para toque/mobile/acessibilidade
- Esquecer a acessibilidade pelo teclado — sempre inclua
KeyboardSensor
- Mutar o estado durante o arrasto — atualize apenas em
onDragEnd
- Esquecer o
DragOverlay — sem ele, o item original desaparece durante o arrasto sem feedback visual