Documentação/API
DnDProvider
O componente que controla o arraste — entrada, o overlay, a seleção, a rolagem automática e a live region — para tudo o que é renderizado dentro dele.
Esta página foi traduzida por IA e pode conter imprecisões. Ler o original em inglês
const DnDProvider: Component<DnDProviderProps>;Controla os arrastes de tudo o que é renderizado dentro dele: a entrada, o overlay, a seleção, a rolagem automática e os anúncios para leitores de tela (veja DnDProviderProps).
<script setup lang="ts">
import { DnDProvider } from '@vue-dnd-kit/core';
</script>
<template>
<DnDProvider :animation="{ duration: 200 }" @drag-end="save">
<RouterView />
<template #overlay="{ items, over, accepted }">
<!-- optional: a custom overlay for every drag -->
</template>
</DnDProvider>
</template>
Todo composable precisa rodar em um componente renderizado dentro de um provider. O objetivo
é um único provider para o app inteiro: partes da página ganham regras próprias com
makeDragArea. Veja o guia do provider.
A maioria das props é lida quando o provider precisa dela: mude uma, e o próximo arraste já a usa.
Carregando a demo…
<script setup lang="ts">
import { computed, ref } from 'vue';
import { DnDProvider, type ActivationOptions } from '@vue-dnd-kit/core';
import PropRow from './PropRow.vue';
import DensityList from './DensityList.vue';
const ACTIVATIONS: Record<string, ActivationOptions | undefined> = {
default: undefined,
'{ mouse: { delay: 300 } }': { mouse: { delay: 300, tolerance: 5 } },
};
const overlayFit = ref<'slot' | 'source'>('slot');
const activation = ref('default');
const keyboard = ref<'true' | 'false'>('true');
const copyModifier = ref<'Alt' | 'Shift' | 'null'>('Alt');
// The provider reads its props when it needs them: a change applies to the next drag.
const props = computed(() => ({
overlayFit: overlayFit.value,
activation: ACTIVATIONS[activation.value],
// `false` turns keyboard drags off; an object sets their keys and steps.
keyboard: keyboard.value === 'true' ? undefined : (false as const),
copyModifier: copyModifier.value === 'null' ? null : copyModifier.value,
}));
const compact = ref([
{ id: 'copy', title: 'Write copy' },
{ id: 'login', title: 'Fix login' },
]);
const roomy = ref([
{ id: 'sprint', title: 'Plan the sprint' },
{ id: 'review', title: 'Review the PR' },
]);
</script>
<template>
<DnDProvider v-bind="props">
<div class="demo">
<div class="props" role="group" aria-label="DnDProvider props">
<PropRow v-model="overlayFit" name="overlay-fit" :options="['slot', 'source']" />
<PropRow v-model="activation" name=":activation" :options="Object.keys(ACTIVATIONS)" />
<PropRow v-model="keyboard" name=":keyboard" :options="['true', 'false']" />
<PropRow v-model="copyModifier" name="copy-modifier" :options="['Alt', 'Shift', 'null']" />
</div>
<div class="lists">
<DensityList v-model="compact" title="Compact" compact />
<DensityList v-model="roomy" title="Roomy" />
</div>
</div>
</DnDProvider>
</template>
<style scoped>
/* Room for every row in one list: the lists grow downward and nothing moves under the pointer. */
.demo {
display: flex;
flex-direction: column;
align-items: center;
gap: 18px;
min-height: 430px;
}
.props {
display: grid;
grid-template-columns: auto auto;
align-items: center;
gap: 6px 14px;
max-width: 100%;
padding: 12px 14px;
border: 1px solid color-mix(in srgb, currentColor 12%, transparent);
border-radius: 12px;
background: color-mix(in srgb, currentColor 3%, Canvas);
}
.lists {
display: flex;
flex-wrap: wrap;
align-items: flex-start;
justify-content: center;
gap: 14px;
}
@media (max-width: 480px) {
.props {
grid-template-columns: minmax(0, 1fr);
}
}
</style>Onde o overlay é renderizado
overlayTo tira o overlay do body: para dentro de um <dialog> modal, que fica acima de todo o
resto da página. Desligue a chave, e as linhas que você arrasta somem embaixo do dialog. O
guia do overlay explica quando isso é
necessário.
Carregando a demo…
<script setup lang="ts">
import { computed, ref, useTemplateRef } from 'vue';
import { DnDProvider } from '@vue-dnd-kit/core';
import ColumnList from './ColumnList.vue';
const columns = ref(['Name', 'Status', 'Owner', 'Due date', 'Priority']);
const dialog = useTemplateRef<HTMLDialogElement>('dialog');
const open = ref(false);
const intoDialog = ref(true);
// A modal <dialog> sits on the top layer, above everything in <body>, the overlay
// included. While it is open, the overlay renders inside it.
const overlayTo = computed(() => (open.value && intoDialog.value ? '#columns-dialog' : 'body'));
const show = () => {
dialog.value?.showModal();
open.value = true;
};
</script>
<template>
<DnDProvider :overlay-to="overlayTo">
<div class="sheet">
<table>
<thead>
<tr>
<th v-for="column in columns" :key="column">{{ column }}</th>
</tr>
</thead>
<tbody>
<tr v-for="row in 2" :key="row">
<td v-for="column in columns" :key="column"><span class="skeleton" /></td>
</tr>
</tbody>
</table>
<button type="button" class="primary" @click="show">Edit columns</button>
</div>
<dialog id="columns-dialog" ref="dialog" @close="open = false">
<h3>Columns</h3>
<p>Drag to change their order.</p>
<ColumnList v-model:columns="columns" />
<footer>
<label class="switch">
<input v-model="intoDialog" type="checkbox" />
Overlay inside the dialog
</label>
<button type="button" class="primary" @click="dialog?.close()">Done</button>
</footer>
</dialog>
</DnDProvider>
</template>
<style scoped>
.sheet {
display: flex;
flex-direction: column;
align-items: center;
gap: 16px;
width: 100%;
}
table {
width: min(100%, 520px);
border-collapse: collapse;
font-size: 12px;
}
th {
padding: 8px;
border-bottom: 1px solid color-mix(in srgb, currentColor 15%, transparent);
font-weight: 600;
text-align: left;
white-space: nowrap;
}
td {
padding: 10px 8px;
border-bottom: 1px solid color-mix(in srgb, currentColor 8%, transparent);
}
.skeleton {
display: block;
height: 8px;
border-radius: 4px;
background: color-mix(in srgb, currentColor 10%, transparent);
}
button {
padding: 7px 14px;
border: 0;
border-radius: 8px;
font: 600 12px/1.2 system-ui, sans-serif;
cursor: pointer;
}
.primary {
background: #42b883;
color: #04130c;
}
button:focus-visible {
outline: 2px solid #42b883;
outline-offset: 2px;
}
/* No transform on the dialog: it would move the overlay's fixed position. */
dialog {
width: min(340px, calc(100vw - 32px));
box-sizing: border-box;
margin: auto;
padding: 18px;
border: 1px solid color-mix(in srgb, currentColor 14%, transparent);
border-radius: 16px;
background: Canvas;
color: CanvasText;
box-shadow: 0 30px 60px -20px rgb(0 0 0 / 0.6);
}
dialog::backdrop {
background: rgb(0 0 0 / 0.45);
}
h3 {
margin: 0;
font-size: 15px;
}
p {
margin: 4px 0 14px;
font-size: 12px;
opacity: 0.6;
}
footer {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
margin-top: 16px;
}
.switch {
display: flex;
align-items: center;
gap: 6px;
font-size: 12px;
}
.switch input {
accent-color: #42b883;
}
</style>Props
Props de DnDProvider. A maioria é lida quando o provider precisa delas: mude uma, e o próximo arraste a usa.
CollisionDetectionComo o alvo sob o arraste é escolhido. Padrão pointerFirst; outro embutido (closestCorners) ou um seu.
Modifier[]Modificadores para todo arraste, aplicados primeiro: os das áreas de arraste, dos draggables e das listas vêm depois.
LayoutAnimationAnimação FLIP padrão para as listas ordenáveis.
DropAnimationComo o overlay pousa no drop e volta ao lugar no cancelamento, quando nada mais próximo define um: primeiro vem o overDropAnimation do alvo de drop, depois o do próprio item arrastado (ou o da lista dele) e, por fim, este.
AutoAnimationanimateChanges padrão das listas e árvores ordenáveis: mudanças nos itens delas que nenhum arraste fez. Desligado por padrão.
boolean | AutoScrollOptionsRola os contêineres e a página quando um arraste se aproxima das bordas deles. Padrão true; opções o ajustam, false o desliga. Listas, árvores e áreas de arraste podem sobrescrevê-lo.
ActivationOptionsO que um pressionamento precisa fazer antes de virar um arraste, por tipo de ponteiro (veja ActivationOptions para os padrões). Áreas de arraste, listas, árvores, itens e draggables podem sobrescrevê-lo.
KeyboardOptions | falseArrastes por teclado: as teclas e o passo deles. false os desliga; Escape continua cancelando qualquer arraste.
Sensor[]O que transforma entrada em arrastes. Padrão [pointerSensor, keyboardSensor]: deixe um de fora, envolva-o ou substitua-o, ou adicione os seus (defineSensor). O sensor de teclado também cancela qualquer arraste com Escape; keyboard: false desliga os arrastes dele mas mantém isso. A lista pode mudar a qualquer momento: os sensores que saem dela param, cancelando o seu arraste.
boolean | HapticsOptionsVibração para arrastes por toque. Padrão: uma curta quando um arraste começa depois do toque longo; um objeto acrescenta outras (enter, drop, refuse); false desliga todas.
string | nullTecla (KeyboardEvent.key) que transforma um movimento em cópia. Padrão 'Alt'; null desativa.
string | HTMLElementOnde o overlay é renderizado: um seletor ou um elemento. Padrão 'body'. Um <dialog> modal fica acima do resto da página: arrastes dentro de um precisam do overlay ali.
'slot' | 'source'Tamanho do overlay durante o arraste. 'slot' (padrão): ele acompanha a posição onde o item vai pousar, então, sobre outra lista, assume o tamanho dos itens dessa lista, e o drop não precisa de redimensionamento. Ele se redimensiona ao redor do ponteiro, que fica na mesma fração da caixa. 'source': ele mantém o tamanho do elemento arrastado. O conteúdo padrão do overlay é diagramado de novo no novo tamanho; ele nunca é escalado.
number | 'all'Multi-drag: quantos itens arrastados ganham um clone no início do arraste, o pego e os outros ao lado dele na ordem do drop. Padrão 5; 'all' clona todos os que estão renderizados. O overlay padrão mostra os clones e conta o resto (+N); em um layout próprio, DragPreview renderiza o seu slot para um item sem clone. Todo clone voa: de volta ao seu item em um cancelamento, para a sua posição em um drop, para dentro da zona em que um drop entra, um depois do outro. Os clones são feitos juntos, com um só layout por passada de snapshot para todos, mas cada um custa a leitura dos seus estilos: cuidado com itens longos em celulares lentos.
boolean | TransitionPropsComo o overlay muda de um componente para outro durante um arraste (o overOverlay de um alvo de drop assume, um ref de overlay é trocado): true (padrão) faz um crossfade entre eles em 150 ms, false os troca na hora, e um objeto são as props de um <Transition> do Vue em volta da raiz do conteúdo (name, mode, hooks JS para GSAP ou motion). Sem mode: 'out-in', os dois aparecem ao mesmo tempo: dê ao que sai position: absolute (.<name>-leave-active) para que fiquem empilhados na caixa.
string | Record<string, boolean> | Array<string | Record<string, boolean>>Classes para o conteúdo do overlay ([data-dnd-overlay-content]), o elemento que preenche a caixa do overlay: o que deve ser animado como um todo enquanto a biblioteca move e redimensiona a caixa. Uma transição nele roda a partir de @starting-style no início do arraste, e de volta quando ele pousa ([data-dnd-overlay='dropping']): o drop espera por ela. CSS puro o alcança fora de <style scoped> (ou com :global(...)), o Tailwind com starting: e in-data-[dnd-overlay=dragging]:.
Partial<Announcements> | falseTextos próprios para alguns eventos (veja Announcements); false mantém a live region em silêncio.
stringComo arrastar com o teclado, lido pelos leitores de tela para cada draggable (o aria-describedby dele). Padrão: instruções em inglês para Espaço, Enter, as setas e Escape.
booleanInjeta a aparência padrão: CSS em camadas, de especificidade zero, que esmaece os placeholders e os itens que um multi-drag deixa no lugar (opacity: 0.4). Padrão true; false deixa a aparência com você. O que os arrastes precisam é injetado de qualquer forma: sem seleção de texto e sem scroll anchoring durante o arraste (as listas virtuais dependem disso), o cursor de arraste (--dnd-cursor) e sem o menu de link em um toque longo no iOS.
Eventos
| Evento | Payload | Quando |
|---|---|---|
drag-start | DnDEvent | Um arraste começou (depois da ativação). |
drag-move | DnDEvent | O ponteiro se moveu durante um arraste (no máximo uma vez por frame). |
drag-over | DnDEvent | O alvo sob o arraste mudou. |
drag-end | DnDEndEvent | Um drop foi concluído e gravado. |
drag-cancel | DnDEvent | O arraste foi cancelado ou o drop, recusado. |
drag-resume | DnDEvent | onBeforeDrop respondeu 'continue': não houve drop, e o arraste continua. |
drag-settle | DnDEndEvent ou DnDEvent | O overlay do arraste pousou: o que drag-end ou drag-cancel recebeu. |
Os mesmos eventos, mais onBeforeDrop, estão disponíveis em qualquer lugar sob o
provider com useDnDMonitor. Os payloads deles estão na
página de eventos.
Slot #overlay
Renderiza o que segue o ponteiro, para todo arraste que não tem um componente de overlay próprio (veja o guia do overlay). Se não renderizar nada, volta a usar o clone.
O que o overlay mostra: as props do slot #overlay do provider e dos componentes de overlay (opção overlay de draggables, itens ordenáveis, listas e árvores).
ActiveO arraste.
DragItem[]Todos os itens arrastados, começando pelo principal: um único overlay para o multi-drag inteiro.
Over | nullO alvo de drop sob o arraste. Enquanto um drop decidido é animado, o alvo em que ele pousa (como estava no drop); null enquanto um arraste cancelado volta ao lugar.
booleanSe over aceita os itens arrastados; false quando não há nada embaixo.
DnDStatus'dragging', depois 'dropping' enquanto o overlay pousa (ou volta ao lugar).
DragModeO que um drop faria agora (veja DnDEvent.mode): por exemplo, mostrar um sinal de mais enquanto copia.
DropDestination | nullOnde um drop colocaria os itens arrastados agora, em uma lista ou árvore ordenável: por exemplo, pinte o overlay conforme a pasta em que um arraste na árvore entraria. Fora de qualquer alvo, é o lugar da posição, onde dropOutside: 'placeholder' (o padrão) os mantém. null quando o drop não os colocaria em nenhuma lista: sobre um alvo de drop simples, sobre uma lista que os recusa, fora com dropOutside: 'cancel' ou 'remove'. Enquanto um drop já decidido é animado, o lugar em que ele pousa.
Teclado
Arrastes por teclado (o keyboard do provider): as teclas deles e o passo dos arrastes livres.
{ start?: string[]; drop?: string[]; cancel?: string[] }As teclas que pegam (start), soltam e cancelam, como KeyboardEvent.code ('Space', 'KeyW') ou .key ('Enter', 'w'). Padrão: Espaço e Enter pegam e soltam, Escape cancela. As setas sempre movem.
numberPixels por toque de seta nos arrastes livres (não ordenáveis). Padrão 25.
Rolagem automática
Como os contêineres rolam quando um arraste se aproxima das bordas deles (o autoScroll do provider).
numberZona da borda como fração do tamanho do contêiner. Padrão 0.2 (limitado a 24–96px).
numberVelocidade máxima em px por frame de 16ms.
numberVelocidade em px por frame com o ponteiro na borda do contêiner: mais devagar dentro da zona da borda, mais rápido além da borda, até maxSpeed. Padrão 10.
Vibração
Quando os arrastes por toque vibram. Só os arrastes iniciados por toque vibram; onde o navegador não consegue vibrar (Safari do iOS) ou bloqueia a vibração (nenhum toque na página ainda), nada acontece.
HapticPatternO arraste começa, depois do toque longo. Padrão true.
HapticPatternO arraste entra em um alvo de drop (uma lista, uma zona) que o aceita. Padrão false.
HapticPatternO drop é concluído. Padrão false.
HapticPatternO drop é recusado (por um alvo ou pelo onBeforeDrop) e os itens voltam ao lugar. Padrão false.
Uma vibração (navigator.vibrate): a duração em ms ou um padrão de liga/desliga. true é a padrão (10ms; [20, 40, 20] para refuse), false ou 0, nenhuma.
type HapticPattern = boolean | number | number[]Anúncios
Textos para leitores de tela, por evento. Retorne undefined para o texto embutido, '' para nenhum. context traz as posições de que falam os textos embutidos das listas ordenáveis.
Um texto é falado pela live region do provider (os movimentos, quando o arraste fica parado por 500 ms); undefined deixa o evento para a próxima fonte (os textos das integrações, como as posições das listas ordenáveis, e depois os padrões). Um movimento não é anunciado para o alvo encontrado no início do arraste: nada se moveu ainda.
(event: DnDEvent, context: AnnouncementContext) => string | undefinedUm arraste começou.
(event: DnDEvent, context: AnnouncementContext) => string | undefinedO arraste passou sobre outro alvo, ou para outra posição em uma lista (quando fica parado por 500 ms).
(event: DnDEndEvent, context: AnnouncementContext) => string | undefinedO drop se concretizou, ou o arraste terminou fora de todos os alvos.
(event: DnDEvent, context: AnnouncementContext) => string | undefinedO arraste foi cancelado, ou o seu drop foi recusado.
(event: DnDEvent, context: AnnouncementContext) => string | undefinedonBeforeDrop respondeu 'continue': o arraste continua.
Do que trata um anúncio, além do evento: para textos seus (outro idioma, outras palavras) que dizem o mesmo que os textos embutidos.
AnnouncedPositionEm uma lista ordenável ou árvore: onde estão os itens arrastados. No início, onde foram pegos; durante o movimento, onde pousariam (nenhuma posição fora das listas); no fim, onde pousaram, ou para onde voltaram.
{ key: Key; label?: string; position: AnnouncedPosition }Uma troca: o item trocado com o arrastado, e onde ele está agora.
numberQuantos itens o arraste carrega.
booleanO arraste copia (group.pull: 'clone', a tecla modificadora de cópia).
Um lugar em uma lista ordenável ou árvore (nas linhas visíveis dela): index conta a partir de 0, de um total de length.