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.

Editar esta página

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).

App.vue
<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.

Live

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.

Live

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.

CollisionDetection

Como 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.

LayoutAnimation

Animação FLIP padrão para as listas ordenáveis.

DropAnimation

Como 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.

AutoAnimation

animateChanges padrão das listas e árvores ordenáveis: mudanças nos itens delas que nenhum arraste fez. Desligado por padrão.

boolean | AutoScrollOptions

Rola 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.

ActivationOptions

O 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 | false

Arrastes 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 | HapticsOptions

Vibraçã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 | null

Tecla (KeyboardEvent.key) que transforma um movimento em cópia. Padrão 'Alt'; null desativa.

string | HTMLElement

Onde 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 | TransitionProps

Como 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> | false

Textos próprios para alguns eventos (veja Announcements); false mantém a live region em silêncio.

string

Como 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.

boolean

Injeta 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

EventoPayloadQuando
drag-startDnDEventUm arraste começou (depois da ativação).
drag-moveDnDEventO ponteiro se moveu durante um arraste (no máximo uma vez por frame).
drag-overDnDEventO alvo sob o arraste mudou.
drag-endDnDEndEventUm drop foi concluído e gravado.
drag-cancelDnDEventO arraste foi cancelado ou o drop, recusado.
drag-resumeDnDEventonBeforeDrop respondeu 'continue': não houve drop, e o arraste continua.
drag-settleDnDEndEvent ou DnDEventO 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).

Active

O arraste.

DragItem[]

Todos os itens arrastados, começando pelo principal: um único overlay para o multi-drag inteiro.

Over | null

O 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.

boolean

Se over aceita os itens arrastados; false quando não há nada embaixo.

DnDStatus

'dragging', depois 'dropping' enquanto o overlay pousa (ou volta ao lugar).

DragMode

O que um drop faria agora (veja DnDEvent.mode): por exemplo, mostrar um sinal de mais enquanto copia.

DropDestination | null

Onde 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.

number

Pixels 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).

number

Zona da borda como fração do tamanho do contêiner. Padrão 0.2 (limitado a 24–96px).

number

Velocidade máxima em px por frame de 16ms.

number

Velocidade 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.

HapticPattern

O arraste começa, depois do toque longo. Padrão true.

HapticPattern

O arraste entra em um alvo de drop (uma lista, uma zona) que o aceita. Padrão false.

HapticPattern

O drop é concluído. Padrão false.

HapticPattern

O 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 | undefined

Um arraste começou.

(event: DnDEvent, context: AnnouncementContext) => string | undefined

O arraste passou sobre outro alvo, ou para outra posição em uma lista (quando fica parado por 500 ms).

(event: DnDEndEvent, context: AnnouncementContext) => string | undefined

O drop se concretizou, ou o arraste terminou fora de todos os alvos.

(event: DnDEvent, context: AnnouncementContext) => string | undefined

O arraste foi cancelado, ou o seu drop foi recusado.

(event: DnDEvent, context: AnnouncementContext) => string | undefined

onBeforeDrop 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.

AnnouncedPosition

Em 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.

number

Quantos itens o arraste carrega.

boolean

O 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.

Key

Id da lista ou da árvore.

string

O label da lista, como as pessoas a chamam.

number

A posição, a partir de 0: os textos embutidos dizem index + 1.

number

Quantas posições a lista tem.