grab cursor

A tinydata-first library
for modern apps

  • Data-first

    No direct DOM manipulations.

  • Lightweight

    ~4kb min-gzip. No dependencies.

  • Modern

    Leverages modern web APIs.

  • Plugins

    Multi-drag, animations, and more.

  • TypeScript

    First-class TypeScript support.

  • Production-ready

    Used on FormKit Pro inputs.

New

FormKit for React

FormKit is now available for React — inputs, validation, and themes for your React projects.

Introduction

FormKit’s Drag and Drop is a small library for adding drag and drop functionality to your app. It’s simple, flexible, framework agnostic, and clocks in at only ~5kb gzipped. Drag and Drop works with React, Solid, Vue, Svelte, or any JavaScript framework. This library differs from others in the way the drag and drop operations are performed. Rather than moving elements around the DOM manually, Drag and Drop updates the reactive data model used by the provided render function.

Getting Started

Install

Drag and Drop is published as @formkit/drag-and-drop on npm. Click to copy the install command for your package manager of choice:

Usage

Drag and drop ships two main functions: dragAndDrop and useDragAndDrop. These can be imported for your framework of choice by using the subpath import @formkit/drag-and-drop/{react/vue/solid}. A native JavaScript version of the dragAndDrop function is also available at @formkit/drag-and-drop.

Whichever method you choose, the core concept remains the same: FormKit's Drag and Drop accepts two main arguments — the parent element containing the draggable items and the data that those items represent.

useDragAndDrop

The useDragAndDrop hook is the most convenient way to add Drag and Drop to your app and is available for React, Vue, and Solid. Call this function with an initial array of values and the configuration options. It returns an array of values containing a template ref, a reactive set of values (and a setter in the case of React), as well as a function to update the parent's config. The template ref should be assigned to the parent DOM element of the items you wish to make draggable. The reactive array of values should be used in your template to render the draggable elements.

// Example parent configuration object:
const config = { sortable: false }

// React:
const [parentRef, values, setValues, updateConfig] = useDragAndDrop(
['Item 1', 'Item2', 'Item3'],
config
)

// Vue:
const [parentRef, values, updateConfig] = useDragAndDrop(
['Item 1', 'Item2', 'Item3'],
config
)

dragAndDrop

The dragAndDrop hook allows you to define your own ref and list state. This is useful if you need to integrate with a pre-existing app without changing your component structure.

// Example parent configuration object:
const config = { sortable: false }

// React:
dragAndDrop({
parent: parentRef,
state: [values, setValues],
...config
})

// Vue:
dragAndDrop({
parent: parentRef,
values: valueRef,
...config
})

// Vanilla JS: (import from core, not subpath)
dragAndDrop({
parent: HTMLElement,
getValues: () => {

// Return array of values
},
setValues: (newValues) =>
// Do something with updated values

},
config
})

Core Features

Sortability

Using useDragAndDrop or dragAndDrop automatically makes a lists sortable. Dragging items within your list will automatically change your list’s state to reflect the new order (which in turn allows the framework to re-render to the correct order):

  • React
  • Vue
  • Solid
  • Native
  • Marko
import React from "react";
import { function useDragAndDrop<E extends HTMLElement, T = unknown>(list: T[], options?: Partial<ParentConfig<T>>): [React.RefObject<E | null>, T[], React.Dispatch<React.SetStateAction<T[]>>, (config: Partial<ParentConfig<T>>) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paramlist - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
} from "@formkit/drag-and-drop/react";
export function function myComponent(): React.JSX.ElementmyComponent() { const [const parent: React.RefObject<HTMLUListElement | null>parent, const tapes: string[]tapes] = useDragAndDrop<HTMLUListElement, string>(list: string[], options?: Partial<ParentConfig<string>>): [React.RefObject<HTMLUListElement | null>, string[], React.Dispatch<React.SetStateAction<string[]>>, (config: Partial<ParentConfig<string>>) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paramlist - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
<HTMLUListElement, string>([
"Depeche Mode", "Duran Duran", "Pet Shop Boys", "Kraftwerk", "Tears for Fears", "Spandau Ballet", ]); return ( <React.JSX.IntrinsicElements.ul: React.DetailedHTMLProps<React.HTMLAttributes<HTMLUListElement>, HTMLUListElement>ul React.RefAttributes<HTMLUListElement>.ref?: React.Ref<HTMLUListElement> | undefined
Allows getting a ref to the component instance. Once the component unmounts, React will set `ref.current` to `null` (or call the ref with `null` if you passed a callback ref).
@see{@link https://react.dev/learn/referencing-values-with-refs#refs-and-the-dom React Docs}
ref
={const parent: React.RefObject<HTMLUListElement | null>parent}>
{const tapes: string[]tapes.Array<string>.map<React.JSX.Element>(callbackfn: (value: string, index: number, array: string[]) => React.JSX.Element, thisArg?: any): React.JSX.Element[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
((tape: stringtape) => (
<React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li React.HTMLAttributes<HTMLLIElement>.className?: string | undefinedclassName="cassette" data-label: stringdata-label={tape: stringtape} React.Attributes.key?: React.Key | null | undefinedkey={tape: stringtape}> {tape: stringtape} </React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li> ))} </React.JSX.IntrinsicElements.ul: React.DetailedHTMLProps<React.HTMLAttributes<HTMLUListElement>, HTMLUListElement>ul> ); }
<script setup lang="ts">
import { function useDragAndDrop<T>(initialValues: T[], options?: Partial<VueParentConfig<T>>): [Ref<HTMLElement | undefined>, Ref<T[]>, (config: Partial<VueParentConfig<T>>) => void]
Creates a new instance of drag and drop and returns the parent element and a ref of the values to use in your template.
@paraminitialValues - The initial values of the parent element.@returnsThe parent element and values for drag and drop.
useDragAndDrop
} from "@formkit/drag-and-drop/vue";
const [const parent: Ref<HTMLElement | undefined, HTMLElement | undefined>parent, const tapes: Ref<string[], string[]>tapes] = useDragAndDrop<string>(initialValues: string[], options?: Partial<Partial<ParentConfig<string>>>): [Ref<HTMLElement | undefined, HTMLElement | undefined>, Ref<string[], string[]>, (config: Partial<Partial<ParentConfig<string>>>) => void]
Creates a new instance of drag and drop and returns the parent element and a ref of the values to use in your template.
@paraminitialValues - The initial values of the parent element.@returnsThe parent element and values for drag and drop.
useDragAndDrop
([
"Depeche Mode", "Duran Duran", "Pet Shop Boys", "Kraftwerk", "Tears for Fears", "Spandau Ballet", ]); </script> <template> <ul: HTMLAttributes & ReservedPropsul ReservedProps.ref?: VNodeRef | undefinedref="parent: HTMLUListElementparent"> <li: LiHTMLAttributes & ReservedPropsli v-for="const tape: stringtape in const tapes: Ref<string[], string[]>tapes" ReservedProps.key?: PropertyKey | undefined:key="const tape: stringtape" HTMLAttributes.class?: ClassValueclass="cassette"> {{ const tape: stringtape }} </li: LiHTMLAttributes & ReservedPropsli> </ul: HTMLAttributes & ReservedPropsul> </template>
/** @jsxImportSource solid-js */
import { 
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
, type JSX } from "solid-js";
import { function useDragAndDrop<E extends HTMLElement, T = unknown>(initValues: T[], options?: Partial<ParentConfig<T>>): [Setter<E | null>, Accessor<Store<T[]>>, ReturnType<typeof createStore>[1], (config?: Partial<ParentConfig<T>>) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paraminitValues - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
} from "@formkit/drag-and-drop/solid";
export const const MyComponent: () => JSX.ElementMyComponent = (): JSX.type JSX.Element = number | boolean | Node | JSX.ArrayElement | (string & {}) | null | undefinedElement => { const [const parent: Setter<HTMLUListElement | null>parent, const tapes: Accessor<string[]>tapes] = useDragAndDrop<HTMLUListElement, string>(initValues: string[], options?: Partial<ParentConfig<string>>): [Setter<HTMLUListElement | null>, Accessor<string[]>, SetStoreFunction<string[]>, (config?: Partial<ParentConfig<string>> | undefined) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paraminitValues - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
<HTMLUListElement, string>([
"Depeche Mode", "Duran Duran", "Pet Shop Boys", "Kraftwerk", "Tears for Fears", "Spandau Ballet", ]); return ( <JSX.HTMLElementTags.ul: JSX.HTMLAttributes<HTMLUListElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLUListElement
ul
ref?: HTMLUListElement | ((el: HTMLUListElement) => void) | undefinedref={const parent: Setter<HTMLUListElement | null>parent}>
<
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
each: false | string[] | null | undefinedeach={const tapes: () => string[]tapes()}>
{(tape: stringtape) => ( <JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
JSX.DOMAttributes<HTMLLIElement>.class?: string | undefinedclass="cassette" data-label: stringdata-label={tape: stringtape}>
{tape: stringtape} </JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
>
)} </
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
>
</JSX.HTMLElementTags.ul: JSX.HTMLAttributes<HTMLUListElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLUListElement
ul
>
); };
import { function reactive<T>(effect: () => T): Computed<T> (+1 overload)
A reactive object is a proxy of the original object that allows for reactive dependency watching. It is created by calling `reactive()` and should be used to store reactive data in your app and components.
@paramdata - The data to make reactive, typically a plain object.@returnsA reactive proxy of the original data.
reactive
, function html(strings: TemplateStringsArray | string[], ...expSlots: ArrowExpression[]): ArrowTemplatehtml } from "@arrow-js/core";
import { function dragAndDrop<T>({ parent, getValues, setValues, config, }: DragAndDrop<T>): void
Initializes the drag and drop functionality for a given parent.
@paramdragAndDrop - The drag and drop configuration.@returnsvoid
dragAndDrop
} from "@formkit/drag-and-drop";
const
const state: Reactive<{
    tapes: string[];
}>
state
=
reactive<{
    tapes: string[];
}>(data: {
    tapes: string[];
}): Reactive<{
    tapes: string[];
}> (+1 overload)
A reactive object is a proxy of the original object that allows for reactive dependency watching. It is created by calling `reactive()` and should be used to store reactive data in your app and components.
@paramdata - The data to make reactive, typically a plain object.@returnsA reactive proxy of the original data.
reactive
({
tapes: string[]tapes: [ "Depeche Mode", "Duran Duran", "Pet Shop Boys", "Kraftwerk", "Tears for Fears", "Spandau Ballet", ], }); function html(strings: TemplateStringsArray | string[], ...expSlots: ArrowExpression[]): ArrowTemplatehtml` <ul id="cassettes"> ${() =>
const state: Reactive<{
    tapes: string[];
}>
state
.tapes: string[] | Reactive<string[]>tapes.Array<T>.map<ArrowTemplate>(callbackfn: (value: string, index: number, array: string[]) => ArrowTemplate, thisArg?: any): ArrowTemplate[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
((tape: stringtape) =>
function html(strings: TemplateStringsArray | string[], ...expSlots: ArrowExpression[]): ArrowTemplatehtml`<li class="cassette" data-label="${tape: stringtape}">${tape: stringtape}</li>`.ArrowTemplate.key: (key: ArrowTemplateKey) => ArrowTemplatekey(tape: stringtape) )} </ul> `(var document: Document
**`window.document`** returns a reference to the document contained in the window. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)
document
.Document.getElementById(elementId: string): HTMLElement | null
The **`getElementById()`** method of the Document interface returns an Element object representing the element whose id property matches the specified string. Since element IDs are required to be unique if specified, they're a useful way to get access to a specific element quickly.
getElementById
("app")!);
dragAndDrop<string>({ parent, getValues, setValues, config, }: DragAndDrop<string>): void
Initializes the drag and drop functionality for a given parent.
@paramdragAndDrop - The drag and drop configuration.@returnsvoid
dragAndDrop
<string>({
DragAndDrop<string>.parent: HTMLElement
The parent element that will contain the draggable nodes.
parent
: var document: Document
**`window.document`** returns a reference to the document contained in the window. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)
document
.Document.getElementById(elementId: string): HTMLElement | null
The **`getElementById()`** method of the Document interface returns an Element object representing the element whose id property matches the specified string. Since element IDs are required to be unique if specified, they're a useful way to get access to a specific element quickly.
getElementById
("cassettes")!,
DragAndDrop<string>.getValues: (parent: HTMLElement) => string[]
A function that returns the values assigned to the parent.
getValues
: () =>
const state: Reactive<{
    tapes: string[];
}>
state
.tapes: string[] | Reactive<string[]>tapes,
DragAndDrop<string>.setValues: (values: string[], parent: HTMLElement) => void
A function that sets the values assigned to the parent.
setValues
: (newValues: string[]newValues) => {
const state: Reactive<{
    tapes: string[];
}>
state
.tapes: string[] | Reactive<string[]>tapes = reactive<string[]>(data: string[]): Reactive<string[]> (+1 overload)
A reactive object is a proxy of the original object that allows for reactive dependency watching. It is created by calling `reactive()` and should be used to store reactive data in your app and components.
@paramdata - The data to make reactive, typically a plain object.@returnsA reactive proxy of the original data.
reactive
(newValues: string[]newValues);
}, });
<let/tapes=[
  "Depeche Mode",
  "Duran Duran",
  "Pet Shop Boys",
  "Kraftwerk",
  "Tears for Fears",
  "Spandau Ballet",
]>

<ul/parent>
  <for|tape| of=tapes by=(t => t)>
    <li class="cassette">${tape}</li>
  </for>
</ul>

<dnd:=tapes parent=parent/>

Draggable

For drag-and-drop to function correctly, the length of array of values provided must be equivalent to the number of immediate children to the parent element. If they are not, a console warning will appear: The number of draggable items in the parent does not match the number of values, which may lead to unexpected behavior." The most common cause of this is when the parent element has an immediate child that is not meant to be draggable. In this case, the configuration property draggable can be set to a callback function that lets you determine whether or not a given element should be draggable:

  • React
  • Vue
  • Solid
  • Native
  • Marko
import React from "react";
import { function useDragAndDrop<E extends HTMLElement, T = unknown>(list: T[], options?: Partial<ParentConfig<T>>): [React.RefObject<E | null>, T[], React.Dispatch<React.SetStateAction<T[]>>, (config: Partial<ParentConfig<T>>) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paramlist - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
} from "@formkit/drag-and-drop/react";
export function function myComponent(): React.JSX.ElementmyComponent() { const [const parent: React.RefObject<HTMLUListElement | null>parent, const tapes: string[]tapes] = useDragAndDrop<HTMLUListElement, string>(list: string[], options?: Partial<ParentConfig<string>>): [React.RefObject<HTMLUListElement | null>, string[], React.Dispatch<React.SetStateAction<string[]>>, (config: Partial<ParentConfig<string>>) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paramlist - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
<HTMLUListElement, string>(
[ "Depeche Mode", "Duran Duran", "Pet Shop Boys", "Kraftwerk", "Tears for Fears", "Spandau Ballet", ], { draggable?: ((child: HTMLElement) => boolean) | undefined
A function that returns whether a given node is draggable.
draggable
: (el: HTMLElementel) => {
return el: HTMLElementel.Element.id: string
The **`id`** property of the Element interface represents the element's identifier, reflecting the id global attribute. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Element/id)
id
!== "no-drag";
}, } ); return ( <React.JSX.IntrinsicElements.ul: React.DetailedHTMLProps<React.HTMLAttributes<HTMLUListElement>, HTMLUListElement>ul React.RefAttributes<HTMLUListElement>.ref?: React.Ref<HTMLUListElement> | undefined
Allows getting a ref to the component instance. Once the component unmounts, React will set `ref.current` to `null` (or call the ref with `null` if you passed a callback ref).
@see{@link https://react.dev/learn/referencing-values-with-refs#refs-and-the-dom React Docs}
ref
={const parent: React.RefObject<HTMLUListElement | null>parent}>
{const tapes: string[]tapes.Array<string>.map<React.JSX.Element>(callbackfn: (value: string, index: number, array: string[]) => React.JSX.Element, thisArg?: any): React.JSX.Element[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
((tape: stringtape) => (
<React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li React.HTMLAttributes<HTMLLIElement>.className?: string | undefinedclassName="cassette" data-label: stringdata-label={tape: stringtape} React.Attributes.key?: React.Key | null | undefinedkey={tape: stringtape}> {tape: stringtape} </React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li> ))} <React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div React.HTMLAttributes<HTMLDivElement>.id?: string | undefinedid="no-drag">I am NOT draggable</React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div> </React.JSX.IntrinsicElements.ul: React.DetailedHTMLProps<React.HTMLAttributes<HTMLUListElement>, HTMLUListElement>ul> ); }
<script setup lang="ts">
import { function useDragAndDrop<T>(initialValues: T[], options?: Partial<VueParentConfig<T>>): [Ref<HTMLElement | undefined>, Ref<T[]>, (config: Partial<VueParentConfig<T>>) => void]
Creates a new instance of drag and drop and returns the parent element and a ref of the values to use in your template.
@paraminitialValues - The initial values of the parent element.@returnsThe parent element and values for drag and drop.
useDragAndDrop
} from "@formkit/drag-and-drop/vue";
const [const parent: Ref<HTMLElement | undefined, HTMLElement | undefined>parent, const tapes: Ref<string[], string[]>tapes] = useDragAndDrop<string>(initialValues: string[], options?: Partial<Partial<ParentConfig<string>>>): [Ref<HTMLElement | undefined, HTMLElement | undefined>, Ref<string[], string[]>, (config: Partial<Partial<ParentConfig<string>>>) => void]
Creates a new instance of drag and drop and returns the parent element and a ref of the values to use in your template.
@paraminitialValues - The initial values of the parent element.@returnsThe parent element and values for drag and drop.
useDragAndDrop
(
[ "Depeche Mode", "Duran Duran", "Pet Shop Boys", "Kraftwerk", "Tears for Fears", "Spandau Ballet", ], { draggable?: ((child: HTMLElement) => boolean) | undefined
A function that returns whether a given node is draggable.
draggable
: (el: HTMLElementel) => {
return el: HTMLElementel.Element.id: string
The **`id`** property of the Element interface represents the element's identifier, reflecting the id global attribute. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Element/id)
id
!== "no-drag";
}, } ); </script> <template> <ul: HTMLAttributes & ReservedPropsul ReservedProps.ref?: VNodeRef | undefinedref="parent: HTMLUListElementparent"> <li: LiHTMLAttributes & ReservedPropsli v-for="const tape: stringtape in const tapes: Ref<string[], string[]>tapes" ReservedProps.key?: PropertyKey | undefined:key="const tape: stringtape" HTMLAttributes.class?: ClassValueclass="cassette"> {{ const tape: stringtape }} </li: LiHTMLAttributes & ReservedPropsli> <li: LiHTMLAttributes & ReservedPropsli HTMLAttributes.id?: string | undefinedid="no-drag">I am NOT draggable</li: LiHTMLAttributes & ReservedPropsli> </ul: HTMLAttributes & ReservedPropsul> </template>
/** @jsxImportSource solid-js */
import { 
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
} from "solid-js";
import { function useDragAndDrop<E extends HTMLElement, T = unknown>(initValues: T[], options?: Partial<ParentConfig<T>>): [Setter<E | null>, Accessor<Store<T[]>>, ReturnType<typeof createStore>[1], (config?: Partial<ParentConfig<T>>) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paraminitValues - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
} from "@formkit/drag-and-drop/solid";
export function function MyComponent(): JSX.ElementMyComponent() { const [const parent: Setter<HTMLUListElement | null>parent, const tapes: Accessor<string[]>tapes] = useDragAndDrop<HTMLUListElement, string>(initValues: string[], options?: Partial<ParentConfig<string>>): [Setter<HTMLUListElement | null>, Accessor<string[]>, SetStoreFunction<string[]>, (config?: Partial<ParentConfig<string>> | undefined) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paraminitValues - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
<HTMLUListElement, string>(
[ "Depeche Mode", "Duran Duran", "Pet Shop Boys", "Kraftwerk", "Tears for Fears", "Spandau Ballet", ], { draggable?: ((child: HTMLElement) => boolean) | undefined
A function that returns whether a given node is draggable.
draggable
: (el: HTMLElementel) => {
return el: HTMLElementel.Element.id: string
The **`id`** property of the Element interface represents the element's identifier, reflecting the id global attribute. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Element/id)
id
!== "no-drag";
}, } ); return ( <JSX.HTMLElementTags.ul: JSX.HTMLAttributes<HTMLUListElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLUListElement
ul
ref?: HTMLUListElement | ((el: HTMLUListElement) => void) | undefinedref={const parent: Setter<HTMLUListElement | null>parent}>
<
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
each: false | string[] | null | undefinedeach={const tapes: () => string[]tapes()}>
{(tape: stringtape) => ( <JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
JSX.DOMAttributes<HTMLLIElement>.class?: string | undefinedclass="cassette" data-label: stringdata-label={tape: stringtape}>
{tape: stringtape} </JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
>
)} </
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
>
<JSX.HTMLElementTags.div: JSX.HTMLAttributes<HTMLDivElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/div@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLDivElement
div
JSX.DOMAttributes<HTMLDivElement>.id?: string | undefinedid="no-drag">I am NOT draggable</JSX.HTMLElementTags.div: JSX.HTMLAttributes<HTMLDivElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/div@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLDivElement
div
>
</JSX.HTMLElementTags.ul: JSX.HTMLAttributes<HTMLUListElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLUListElement
ul
>
); }
import { function reactive<T>(effect: () => T): Computed<T> (+1 overload)
A reactive object is a proxy of the original object that allows for reactive dependency watching. It is created by calling `reactive()` and should be used to store reactive data in your app and components.
@paramdata - The data to make reactive, typically a plain object.@returnsA reactive proxy of the original data.
reactive
, function html(strings: TemplateStringsArray | string[], ...expSlots: ArrowExpression[]): ArrowTemplatehtml } from "@arrow-js/core";
import { function dragAndDrop<T>({ parent, getValues, setValues, config, }: DragAndDrop<T>): void
Initializes the drag and drop functionality for a given parent.
@paramdragAndDrop - The drag and drop configuration.@returnsvoid
dragAndDrop
} from "@formkit/drag-and-drop";
const
const state: Reactive<{
    tapes: string[];
}>
state
=
reactive<{
    tapes: string[];
}>(data: {
    tapes: string[];
}): Reactive<{
    tapes: string[];
}> (+1 overload)
A reactive object is a proxy of the original object that allows for reactive dependency watching. It is created by calling `reactive()` and should be used to store reactive data in your app and components.
@paramdata - The data to make reactive, typically a plain object.@returnsA reactive proxy of the original data.
reactive
({
tapes: string[]tapes: [ "Depeche Mode", "Duran Duran", "Pet Shop Boys", "Kraftwerk", "Tears for Fears", "Spandau Ballet", ], }); function html(strings: TemplateStringsArray | string[], ...expSlots: ArrowExpression[]): ArrowTemplatehtml` <ul id="cassettes"> ${() =>
const state: Reactive<{
    tapes: string[];
}>
state
.tapes: string[] | Reactive<string[]>tapes.Array<T>.map<ArrowTemplate>(callbackfn: (value: string, index: number, array: string[]) => ArrowTemplate, thisArg?: any): ArrowTemplate[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
((tape: stringtape) =>
function html(strings: TemplateStringsArray | string[], ...expSlots: ArrowExpression[]): ArrowTemplatehtml`<li class="cassette" data-label="${tape: stringtape}">${tape: stringtape}</li>`.ArrowTemplate.key: (key: ArrowTemplateKey) => ArrowTemplatekey(tape: stringtape) )} <div id="no-drag">I am NOT draggable</div> </ul> `(var document: Document
**`window.document`** returns a reference to the document contained in the window. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)
document
.Document.getElementById(elementId: string): HTMLElement | null
The **`getElementById()`** method of the Document interface returns an Element object representing the element whose id property matches the specified string. Since element IDs are required to be unique if specified, they're a useful way to get access to a specific element quickly.
getElementById
("app")!);
dragAndDrop<string>({ parent, getValues, setValues, config, }: DragAndDrop<string>): void
Initializes the drag and drop functionality for a given parent.
@paramdragAndDrop - The drag and drop configuration.@returnsvoid
dragAndDrop
<string>({
DragAndDrop<string>.parent: HTMLElement
The parent element that will contain the draggable nodes.
parent
: var document: Document
**`window.document`** returns a reference to the document contained in the window. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)
document
.Document.getElementById(elementId: string): HTMLElement | null
The **`getElementById()`** method of the Document interface returns an Element object representing the element whose id property matches the specified string. Since element IDs are required to be unique if specified, they're a useful way to get access to a specific element quickly.
getElementById
("cassettes")!,
DragAndDrop<string>.getValues: (parent: HTMLElement) => string[]
A function that returns the values assigned to the parent.
getValues
: () =>
const state: Reactive<{
    tapes: string[];
}>
state
.tapes: string[] | Reactive<string[]>tapes,
DragAndDrop<string>.setValues: (values: string[], parent: HTMLElement) => void
A function that sets the values assigned to the parent.
setValues
: (newValues: string[]newValues) => {
const state: Reactive<{
    tapes: string[];
}>
state
.tapes: string[] | Reactive<string[]>tapes = reactive<string[]>(data: string[]): Reactive<string[]> (+1 overload)
A reactive object is a proxy of the original object that allows for reactive dependency watching. It is created by calling `reactive()` and should be used to store reactive data in your app and components.
@paramdata - The data to make reactive, typically a plain object.@returnsA reactive proxy of the original data.
reactive
(newValues: string[]newValues);
}, DragAndDrop<string>.config?: Partial<ParentConfig<string>> | undefined
An optional configuration object.
config
: {
draggable?: ((child: HTMLElement) => boolean) | undefined
A function that returns whether a given node is draggable.
draggable
: (el: HTMLElementel) => {
return el: HTMLElementel.Element.id: string
The **`id`** property of the Element interface represents the element's identifier, reflecting the id global attribute. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Element/id)
id
!== "no-drag";
}, }, });
static const config = {
  draggable: (el: HTMLElement) => el.id !== "no-drag",
};

<let/tapes=[
  "Depeche Mode",
  "Duran Duran",
  "Pet Shop Boys",
  "Kraftwerk",
  "Tears for Fears",
  "Spandau Ballet",
]>

<ul/parent>
  <for|tape| of=tapes by=(t => t)>
    <li class="cassette">${tape}</li>
  </for>
  <li id="no-drag">I am NOT draggable</li>
</ul>

<dnd:=tapes parent=parent config=config/>

Transferability

In addition to sorting, drag-and-drop allows transferring values between parents (lists). To enable this, set the configuration property group to the same value for each list that should allow value transfers. Notice in the example below that items can be appended to the end of the list by hovering over the list itself, or inserted into the list by hovering over the target parent's draggable items.

  • React
  • Vue
  • Solid
  • Native
  • Marko
import React from "react";
import { function useDragAndDrop<E extends HTMLElement, T = unknown>(list: T[], options?: Partial<ParentConfig<T>>): [React.RefObject<E | null>, T[], React.Dispatch<React.SetStateAction<T[]>>, (config: Partial<ParentConfig<T>>) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paramlist - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
} from "@formkit/drag-and-drop/react";
export function function myComponent(): React.JSX.ElementmyComponent() { const const todoItems: string[]todoItems = [ "Schedule perm", "Rewind VHS tapes", "Make change for the arcade", "Get disposable camera developed", "Learn C++", "Return Nintendo Power Glove", ]; const const doneItems: string[]doneItems = ["Pickup new mix-tape from Beth"]; const [const todoList: React.RefObject<HTMLUListElement | null>todoList, const todos: string[]todos] = useDragAndDrop<HTMLUListElement, string>(list: string[], options?: Partial<ParentConfig<string>>): [React.RefObject<HTMLUListElement | null>, string[], React.Dispatch<React.SetStateAction<string[]>>, (config: Partial<ParentConfig<string>>) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paramlist - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
<HTMLUListElement, string>(
const todoItems: string[]todoItems, { group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "todoList" }
); const [const doneList: React.RefObject<HTMLUListElement | null>doneList, const dones: string[]dones] = useDragAndDrop<HTMLUListElement, string>(list: string[], options?: Partial<ParentConfig<string>>): [React.RefObject<HTMLUListElement | null>, string[], React.Dispatch<React.SetStateAction<string[]>>, (config: Partial<ParentConfig<string>>) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paramlist - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
<HTMLUListElement, string>(
const doneItems: string[]doneItems, { group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "todoList" }
); return ( <React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div React.HTMLAttributes<HTMLDivElement>.className?: string | undefinedclassName="kanban-board"> <React.JSX.IntrinsicElements.ul: React.DetailedHTMLProps<React.HTMLAttributes<HTMLUListElement>, HTMLUListElement>ul React.RefAttributes<HTMLUListElement>.ref?: React.Ref<HTMLUListElement> | undefined
Allows getting a ref to the component instance. Once the component unmounts, React will set `ref.current` to `null` (or call the ref with `null` if you passed a callback ref).
@see{@link https://react.dev/learn/referencing-values-with-refs#refs-and-the-dom React Docs}
ref
={const todoList: React.RefObject<HTMLUListElement | null>todoList}>
{const todos: string[]todos.Array<string>.map<React.JSX.Element>(callbackfn: (value: string, index: number, array: string[]) => React.JSX.Element, thisArg?: any): React.JSX.Element[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
((todo: stringtodo) => (
<React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li React.HTMLAttributes<T>.className?: string | undefinedclassName="kanban-item" React.Attributes.key?: React.Key | null | undefinedkey={todo: stringtodo}> {todo: stringtodo} </React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li> ))} </React.JSX.IntrinsicElements.ul: React.DetailedHTMLProps<React.HTMLAttributes<HTMLUListElement>, HTMLUListElement>ul> <React.JSX.IntrinsicElements.ul: React.DetailedHTMLProps<React.HTMLAttributes<HTMLUListElement>, HTMLUListElement>ul React.RefAttributes<HTMLUListElement>.ref?: React.Ref<HTMLUListElement> | undefined
Allows getting a ref to the component instance. Once the component unmounts, React will set `ref.current` to `null` (or call the ref with `null` if you passed a callback ref).
@see{@link https://react.dev/learn/referencing-values-with-refs#refs-and-the-dom React Docs}
ref
={const doneList: React.RefObject<HTMLUListElement | null>doneList}>
{const dones: string[]dones.Array<string>.map<React.JSX.Element>(callbackfn: (value: string, index: number, array: string[]) => React.JSX.Element, thisArg?: any): React.JSX.Element[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
((done: stringdone) => (
<React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li React.HTMLAttributes<T>.className?: string | undefinedclassName="kanban-item" React.Attributes.key?: React.Key | null | undefinedkey={done: stringdone}> {done: stringdone} </React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li> ))} </React.JSX.IntrinsicElements.ul: React.DetailedHTMLProps<React.HTMLAttributes<HTMLUListElement>, HTMLUListElement>ul> </React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div> ); }
<script setup lang="ts">
import { function useDragAndDrop<T>(initialValues: T[], options?: Partial<VueParentConfig<T>>): [Ref<HTMLElement | undefined>, Ref<T[]>, (config: Partial<VueParentConfig<T>>) => void]
Creates a new instance of drag and drop and returns the parent element and a ref of the values to use in your template.
@paraminitialValues - The initial values of the parent element.@returnsThe parent element and values for drag and drop.
useDragAndDrop
} from "@formkit/drag-and-drop/vue";
const const todoItems: string[]todoItems = ["Schedule perm", "Rewind VHS tapes", "Make change for the arcade", "Get disposable camera developed", "Learn C++", "Return Nintendo Power Glove"]; const const doneItems: string[]doneItems = ["Pickup new mix-tape from Beth"]; const [const todoList: Ref<HTMLElement | undefined, HTMLElement | undefined>todoList, const todos: Ref<string[], string[]>todos] = useDragAndDrop<string>(initialValues: string[], options?: Partial<Partial<ParentConfig<string>>>): [Ref<HTMLElement | undefined, HTMLElement | undefined>, Ref<string[], string[]>, (config: Partial<Partial<ParentConfig<string>>>) => void]
Creates a new instance of drag and drop and returns the parent element and a ref of the values to use in your template.
@paraminitialValues - The initial values of the parent element.@returnsThe parent element and values for drag and drop.
useDragAndDrop
(const todoItems: string[]todoItems, { group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "todoList" });
const [const doneList: Ref<HTMLElement | undefined, HTMLElement | undefined>doneList, const dones: Ref<string[], string[]>dones] = useDragAndDrop<string>(initialValues: string[], options?: Partial<Partial<ParentConfig<string>>>): [Ref<HTMLElement | undefined, HTMLElement | undefined>, Ref<string[], string[]>, (config: Partial<Partial<ParentConfig<string>>>) => void]
Creates a new instance of drag and drop and returns the parent element and a ref of the values to use in your template.
@paraminitialValues - The initial values of the parent element.@returnsThe parent element and values for drag and drop.
useDragAndDrop
(const doneItems: string[]doneItems, { group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "todoList" });
</script> <template> <div: HTMLAttributes & ReservedPropsdiv HTMLAttributes.class?: ClassValueclass="kanban-board"> <ul: HTMLAttributes & ReservedPropsul ReservedProps.ref?: VNodeRef | undefinedref="todoList: HTMLUListElementtodoList" HTMLAttributes.class?: ClassValueclass="kanban-column"> <li: LiHTMLAttributes & ReservedPropsli v-for="const todo: stringtodo in const todos: Ref<string[], string[]>todos" ReservedProps.key?: PropertyKey | undefined:key="const todo: stringtodo" HTMLAttributes.class?: ClassValueclass="kanban-item"> {{ const todo: stringtodo }} </li: LiHTMLAttributes & ReservedPropsli> </ul: HTMLAttributes & ReservedPropsul> <ul: HTMLAttributes & ReservedPropsul ReservedProps.ref?: VNodeRef | undefinedref="doneList: HTMLUListElementdoneList" HTMLAttributes.class?: ClassValueclass="kanban-column"> <li: LiHTMLAttributes & ReservedPropsli v-for="const done: stringdone in const dones: Ref<string[], string[]>dones" ReservedProps.key?: PropertyKey | undefined:key="const done: stringdone" HTMLAttributes.class?: ClassValueclass="kanban-item"> {{ const done: stringdone }} </li: LiHTMLAttributes & ReservedPropsli> </ul: HTMLAttributes & ReservedPropsul> </div: HTMLAttributes & ReservedPropsdiv> </template>
/** @jsxImportSource solid-js */
import { 
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
} from "solid-js";
import { function useDragAndDrop<E extends HTMLElement, T = unknown>(initValues: T[], options?: Partial<ParentConfig<T>>): [Setter<E | null>, Accessor<Store<T[]>>, ReturnType<typeof createStore>[1], (config?: Partial<ParentConfig<T>>) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paraminitValues - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
} from "@formkit/drag-and-drop/solid";
export function function MyComponent(): JSX.ElementMyComponent() { const const todoItems: string[]todoItems = [ "Schedule perm", "Rewind VHS tapes", "Make change for the arcade", "Get disposable camera developed", "Learn C++", "Return Nintendo Power Glove", ]; const const doneItems: string[]doneItems = ["Pickup new mix-tape from Beth"]; const [const todoList: Setter<HTMLUListElement | null>todoList, const todos: Accessor<string[]>todos] = useDragAndDrop<HTMLUListElement, string>(initValues: string[], options?: Partial<ParentConfig<string>>): [Setter<HTMLUListElement | null>, Accessor<string[]>, SetStoreFunction<string[]>, (config?: Partial<ParentConfig<string>> | undefined) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paraminitValues - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
<HTMLUListElement, string>(
const todoItems: string[]todoItems, { group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "todoList" }
); const [const doneList: Setter<HTMLUListElement | null>doneList, const dones: Accessor<string[]>dones] = useDragAndDrop<HTMLUListElement, string>(initValues: string[], options?: Partial<ParentConfig<string>>): [Setter<HTMLUListElement | null>, Accessor<string[]>, SetStoreFunction<string[]>, (config?: Partial<ParentConfig<string>> | undefined) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paraminitValues - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
<HTMLUListElement, string>(
const doneItems: string[]doneItems, { group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "todoList" }
); return ( <JSX.HTMLElementTags.div: JSX.HTMLAttributes<HTMLDivElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/div@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLDivElement
div
JSX.DOMAttributes<HTMLDivElement>.class?: string | undefinedclass="kanban-board">
<JSX.HTMLElementTags.ul: JSX.HTMLAttributes<HTMLUListElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLUListElement
ul
ref?: HTMLUListElement | ((el: HTMLUListElement) => void) | undefinedref={const todoList: Setter<HTMLUListElement | null>todoList}>
<
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
each: false | string[] | null | undefinedeach={const todos: () => string[]todos()}>
{(todo: stringtodo) => <JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
JSX.DOMAttributes<T>.class?: string | undefinedclass="kanban-item">{todo: stringtodo}</JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
>}
</
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
>
</JSX.HTMLElementTags.ul: JSX.HTMLAttributes<HTMLUListElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLUListElement
ul
>
<JSX.HTMLElementTags.ul: JSX.HTMLAttributes<HTMLUListElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLUListElement
ul
ref?: HTMLUListElement | ((el: HTMLUListElement) => void) | undefinedref={const doneList: Setter<HTMLUListElement | null>doneList}>
<
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
each: false | string[] | null | undefinedeach={const dones: () => string[]dones()}>
{(done: stringdone) => <JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
JSX.DOMAttributes<T>.class?: string | undefinedclass="kanban-item">{done: stringdone}</JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
>}
</
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
>
</JSX.HTMLElementTags.ul: JSX.HTMLAttributes<HTMLUListElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLUListElement
ul
>
</JSX.HTMLElementTags.div: JSX.HTMLAttributes<HTMLDivElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/div@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLDivElement
div
>
); }
import { function reactive<T>(effect: () => T): Computed<T> (+1 overload)
A reactive object is a proxy of the original object that allows for reactive dependency watching. It is created by calling `reactive()` and should be used to store reactive data in your app and components.
@paramdata - The data to make reactive, typically a plain object.@returnsA reactive proxy of the original data.
reactive
, function html(strings: TemplateStringsArray | string[], ...expSlots: ArrowExpression[]): ArrowTemplatehtml } from "@arrow-js/core";
import { function dragAndDrop<T>({ parent, getValues, setValues, config, }: DragAndDrop<T>): void
Initializes the drag and drop functionality for a given parent.
@paramdragAndDrop - The drag and drop configuration.@returnsvoid
dragAndDrop
} from "@formkit/drag-and-drop";
const
const state: Reactive<{
    todos: string[];
    dones: string[];
}>
state
=
reactive<{
    todos: string[];
    dones: string[];
}>(data: {
    todos: string[];
    dones: string[];
}): Reactive<{
    todos: string[];
    dones: string[];
}> (+1 overload)
A reactive object is a proxy of the original object that allows for reactive dependency watching. It is created by calling `reactive()` and should be used to store reactive data in your app and components.
@paramdata - The data to make reactive, typically a plain object.@returnsA reactive proxy of the original data.
reactive
({
todos: string[]todos: [ "Schedule perm", "Rewind VHS tapes", "Make change for the arcade", "Get disposable camera developed", "Learn C++", "Return Nintendo Power Glove", ], dones: string[]dones: ["Pickup new mix-tape from Beth"], }); dragAndDrop<string>({ parent, getValues, setValues, config, }: DragAndDrop<string>): void
Initializes the drag and drop functionality for a given parent.
@paramdragAndDrop - The drag and drop configuration.@returnsvoid
dragAndDrop
<string>({
DragAndDrop<string>.parent: HTMLElement
The parent element that will contain the draggable nodes.
parent
: var document: Document
**`window.document`** returns a reference to the document contained in the window. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)
document
.Document.getElementById(elementId: string): HTMLElement | null
The **`getElementById()`** method of the Document interface returns an Element object representing the element whose id property matches the specified string. Since element IDs are required to be unique if specified, they're a useful way to get access to a specific element quickly.
getElementById
("todo-list")!,
DragAndDrop<string>.getValues: (parent: HTMLElement) => string[]
A function that returns the values assigned to the parent.
getValues
: () =>
const state: Reactive<{
    todos: string[];
    dones: string[];
}>
state
.todos: string[] | Reactive<string[]>todos,
DragAndDrop<string>.setValues: (values: string[], parent: HTMLElement) => void
A function that sets the values assigned to the parent.
setValues
: (newValues: string[]newValues) => {
const state: Reactive<{
    todos: string[];
    dones: string[];
}>
state
.todos: string[] | Reactive<string[]>todos = reactive<string[]>(data: string[]): Reactive<string[]> (+1 overload)
A reactive object is a proxy of the original object that allows for reactive dependency watching. It is created by calling `reactive()` and should be used to store reactive data in your app and components.
@paramdata - The data to make reactive, typically a plain object.@returnsA reactive proxy of the original data.
reactive
(newValues: string[]newValues);
}, DragAndDrop<string>.config?: Partial<ParentConfig<string>> | undefined
An optional configuration object.
config
: {
group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "todoList",
}, }); dragAndDrop<string>({ parent, getValues, setValues, config, }: DragAndDrop<string>): void
Initializes the drag and drop functionality for a given parent.
@paramdragAndDrop - The drag and drop configuration.@returnsvoid
dragAndDrop
<string>({
DragAndDrop<string>.parent: HTMLElement
The parent element that will contain the draggable nodes.
parent
: var document: Document
**`window.document`** returns a reference to the document contained in the window. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)
document
.Document.getElementById(elementId: string): HTMLElement | null
The **`getElementById()`** method of the Document interface returns an Element object representing the element whose id property matches the specified string. Since element IDs are required to be unique if specified, they're a useful way to get access to a specific element quickly.
getElementById
("done-list")!,
DragAndDrop<string>.getValues: (parent: HTMLElement) => string[]
A function that returns the values assigned to the parent.
getValues
: () =>
const state: Reactive<{
    todos: string[];
    dones: string[];
}>
state
.dones: string[] | Reactive<string[]>dones,
DragAndDrop<string>.setValues: (values: string[], parent: HTMLElement) => void
A function that sets the values assigned to the parent.
setValues
: (newValues: string[]newValues) => {
const state: Reactive<{
    todos: string[];
    dones: string[];
}>
state
.dones: string[] | Reactive<string[]>dones = reactive<string[]>(data: string[]): Reactive<string[]> (+1 overload)
A reactive object is a proxy of the original object that allows for reactive dependency watching. It is created by calling `reactive()` and should be used to store reactive data in your app and components.
@paramdata - The data to make reactive, typically a plain object.@returnsA reactive proxy of the original data.
reactive
(newValues: string[]newValues);
}, DragAndDrop<string>.config?: Partial<ParentConfig<string>> | undefined
An optional configuration object.
config
: {
group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "todoList",
}, }); function html(strings: TemplateStringsArray | string[], ...expSlots: ArrowExpression[]): ArrowTemplatehtml` <div class="kanban-board"> <ul class="kanban-list" id="todo-list"> ${() =>
const state: Reactive<{
    todos: string[];
    dones: string[];
}>
state
.todos: string[] | Reactive<string[]>todos.Array<T>.map<ArrowTemplate>(callbackfn: (value: string, index: number, array: string[]) => ArrowTemplate, thisArg?: any): ArrowTemplate[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
((todo: stringtodo) =>
function html(strings: TemplateStringsArray | string[], ...expSlots: ArrowExpression[]): ArrowTemplatehtml`<li class="kanban-item">${todo: stringtodo}</li>`.ArrowTemplate.key: (key: ArrowTemplateKey) => ArrowTemplatekey(todo: stringtodo) )} </ul> <ul class="kanban-list" id="done-list"> ${
const state: Reactive<{
    todos: string[];
    dones: string[];
}>
state
.dones: string[] | Reactive<string[]>dones.Array<T>.map<ArrowTemplate>(callbackfn: (value: string, index: number, array: string[]) => ArrowTemplate, thisArg?: any): ArrowTemplate[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
((done: stringdone) =>
function html(strings: TemplateStringsArray | string[], ...expSlots: ArrowExpression[]): ArrowTemplatehtml`<li class="kanban-item">${done: stringdone}</li>`.ArrowTemplate.key: (key: ArrowTemplateKey) => ArrowTemplatekey(done: stringdone) )} </ul> </div> `(var document: Document
**`window.document`** returns a reference to the document contained in the window. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)
document
.Document.getElementById(elementId: string): HTMLElement | null
The **`getElementById()`** method of the Document interface returns an Element object representing the element whose id property matches the specified string. Since element IDs are required to be unique if specified, they're a useful way to get access to a specific element quickly.
getElementById
("app")!);
static const todoItems = ["Schedule perm", "Rewind VHS tapes", "Make change for the arcade", "Get disposable camera developed", "Learn C++", "Return Nintendo Power Glove"];
static const doneItems = ["Pickup new mix-tape from Beth"];
static const todoConfig = { group: "todoList" };

<let/todos=todoItems>
<let/dones=doneItems>

<div class="kanban-board">
  <ul/todoList class="kanban-column">
    <for|todo| of=todos by=(t => t)>
      <li class="kanban-item">${todo}</li>
    </for>
  </ul>
  <ul/doneList class="kanban-column">
    <for|done| of=dones by=(t => t)>
      <li class="kanban-item">${done}</li>
    </for>
  </ul>
</div>

<dnd:=todos parent=todoList config=todoConfig/>
<dnd:=dones parent=doneList config=todoConfig/>

Disable sort

Sortability within a given parent can be toggled on and off by setting the sortable property to in the configuration.

  • React
  • Vue
  • Solid
  • Native
  • Marko
import React from "react";
import { function useDragAndDrop<E extends HTMLElement, T = unknown>(list: T[], options?: Partial<ParentConfig<T>>): [React.RefObject<E | null>, T[], React.Dispatch<React.SetStateAction<T[]>>, (config: Partial<ParentConfig<T>>) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paramlist - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
} from "@formkit/drag-and-drop/react";
export function function myComponent(): React.JSX.ElementmyComponent() { const const todoItems: string[]todoItems = ["Schedule perm", "Rewind VHS tapes", "Make change for the arcade", "Get disposable camera developed", "Learn C++", "Return Nintendo Power Glove"]; const const doneItems: string[]doneItems = ["Pickup new mix-tape from Beth"]; const [const todoList: React.RefObject<HTMLUListElement | null>todoList, const todos: string[]todos] = useDragAndDrop<HTMLUListElement, string>(list: string[], options?: Partial<ParentConfig<string>>): [React.RefObject<HTMLUListElement | null>, string[], React.Dispatch<React.SetStateAction<string[]>>, (config: Partial<ParentConfig<string>>) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paramlist - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
<HTMLUListElement, string>(
const todoItems: string[]todoItems, { group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "todoList",
sortable?: boolean | undefined
Flag for whether or not to allow sorting within a given parent.
sortable
: false
} ); const [const doneList: React.RefObject<HTMLUListElement | null>doneList, const dones: string[]dones] = useDragAndDrop<HTMLUListElement, string>(list: string[], options?: Partial<ParentConfig<string>>): [React.RefObject<HTMLUListElement | null>, string[], React.Dispatch<React.SetStateAction<string[]>>, (config: Partial<ParentConfig<string>>) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paramlist - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
<HTMLUListElement, string>(
const doneItems: string[]doneItems, { group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "todoList",
sortable?: boolean | undefined
Flag for whether or not to allow sorting within a given parent.
sortable
: false
} ); return ( <React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div React.HTMLAttributes<HTMLDivElement>.className?: string | undefinedclassName="kanban-board"> <React.JSX.IntrinsicElements.ul: React.DetailedHTMLProps<React.HTMLAttributes<HTMLUListElement>, HTMLUListElement>ul React.RefAttributes<HTMLUListElement>.ref?: React.Ref<HTMLUListElement> | undefined
Allows getting a ref to the component instance. Once the component unmounts, React will set `ref.current` to `null` (or call the ref with `null` if you passed a callback ref).
@see{@link https://react.dev/learn/referencing-values-with-refs#refs-and-the-dom React Docs}
ref
={const todoList: React.RefObject<HTMLUListElement | null>todoList}>
{const todos: string[]todos.Array<string>.map<React.JSX.Element>(callbackfn: (value: string, index: number, array: string[]) => React.JSX.Element, thisArg?: any): React.JSX.Element[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
((todo: stringtodo) => (
<React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li React.HTMLAttributes<T>.className?: string | undefinedclassName="kanban-item" React.Attributes.key?: React.Key | null | undefinedkey={todo: stringtodo}> {todo: stringtodo} </React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li> ))} </React.JSX.IntrinsicElements.ul: React.DetailedHTMLProps<React.HTMLAttributes<HTMLUListElement>, HTMLUListElement>ul> <React.JSX.IntrinsicElements.ul: React.DetailedHTMLProps<React.HTMLAttributes<HTMLUListElement>, HTMLUListElement>ul React.RefAttributes<HTMLUListElement>.ref?: React.Ref<HTMLUListElement> | undefined
Allows getting a ref to the component instance. Once the component unmounts, React will set `ref.current` to `null` (or call the ref with `null` if you passed a callback ref).
@see{@link https://react.dev/learn/referencing-values-with-refs#refs-and-the-dom React Docs}
ref
={const doneList: React.RefObject<HTMLUListElement | null>doneList}>
{const dones: string[]dones.Array<string>.map<React.JSX.Element>(callbackfn: (value: string, index: number, array: string[]) => React.JSX.Element, thisArg?: any): React.JSX.Element[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
((done: stringdone) => (
<React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li React.HTMLAttributes<T>.className?: string | undefinedclassName="kanban-item" React.Attributes.key?: React.Key | null | undefinedkey={done: stringdone}> {done: stringdone} </React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li> ))} </React.JSX.IntrinsicElements.ul: React.DetailedHTMLProps<React.HTMLAttributes<HTMLUListElement>, HTMLUListElement>ul> </React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div> ); }
<script setup lang="ts">
import { function useDragAndDrop<T>(initialValues: T[], options?: Partial<VueParentConfig<T>>): [Ref<HTMLElement | undefined>, Ref<T[]>, (config: Partial<VueParentConfig<T>>) => void]
Creates a new instance of drag and drop and returns the parent element and a ref of the values to use in your template.
@paraminitialValues - The initial values of the parent element.@returnsThe parent element and values for drag and drop.
useDragAndDrop
} from "@formkit/drag-and-drop/vue";
const const todoItems: string[]todoItems = [ "Schedule perm", "Rewind VHS tapes", "Make change for the arcade", "Get disposable camera developed", "Learn C++", "Return Nintendo Power Glove", ]; const const doneItems: string[]doneItems = ["Pickup new mix-tape from Beth"]; const [const todoList: Ref<HTMLElement | undefined, HTMLElement | undefined>todoList, const todos: Ref<string[], string[]>todos] = useDragAndDrop<string>(initialValues: string[], options?: Partial<Partial<ParentConfig<string>>>): [Ref<HTMLElement | undefined, HTMLElement | undefined>, Ref<string[], string[]>, (config: Partial<Partial<ParentConfig<string>>>) => void]
Creates a new instance of drag and drop and returns the parent element and a ref of the values to use in your template.
@paraminitialValues - The initial values of the parent element.@returnsThe parent element and values for drag and drop.
useDragAndDrop
(const todoItems: string[]todoItems, {
group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "todoList",
sortable?: boolean | undefined
Flag for whether or not to allow sorting within a given parent.
sortable
: false,
}); const [const doneList: Ref<HTMLElement | undefined, HTMLElement | undefined>doneList, const dones: Ref<string[], string[]>dones] = useDragAndDrop<string>(initialValues: string[], options?: Partial<Partial<ParentConfig<string>>>): [Ref<HTMLElement | undefined, HTMLElement | undefined>, Ref<string[], string[]>, (config: Partial<Partial<ParentConfig<string>>>) => void]
Creates a new instance of drag and drop and returns the parent element and a ref of the values to use in your template.
@paraminitialValues - The initial values of the parent element.@returnsThe parent element and values for drag and drop.
useDragAndDrop
(const doneItems: string[]doneItems, {
group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "todoList",
sortable?: boolean | undefined
Flag for whether or not to allow sorting within a given parent.
sortable
: false,
}); </script> <template> <div: HTMLAttributes & ReservedPropsdiv HTMLAttributes.class?: ClassValueclass="kanban-board"> <ul: HTMLAttributes & ReservedPropsul ReservedProps.ref?: VNodeRef | undefinedref="todoList: HTMLUListElementtodoList" HTMLAttributes.class?: ClassValueclass="kanban-column"> <li: LiHTMLAttributes & ReservedPropsli v-for="const todo: stringtodo in const todos: Ref<string[], string[]>todos" ReservedProps.key?: PropertyKey | undefined:key="const todo: stringtodo" HTMLAttributes.class?: ClassValueclass="kanban-item"> {{ const todo: stringtodo }} </li: LiHTMLAttributes & ReservedPropsli> </ul: HTMLAttributes & ReservedPropsul> <ul: HTMLAttributes & ReservedPropsul ReservedProps.ref?: VNodeRef | undefinedref="doneList: HTMLUListElementdoneList" HTMLAttributes.class?: ClassValueclass="kanban-column"> <li: LiHTMLAttributes & ReservedPropsli v-for="const done: stringdone in const dones: Ref<string[], string[]>dones" ReservedProps.key?: PropertyKey | undefined:key="const done: stringdone" HTMLAttributes.class?: ClassValueclass="kanban-item"> {{ const done: stringdone }} </li: LiHTMLAttributes & ReservedPropsli> </ul: HTMLAttributes & ReservedPropsul> </div: HTMLAttributes & ReservedPropsdiv> </template>
/** @jsxImportSource solid-js */
import { 
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
} from "solid-js";
import { function useDragAndDrop<E extends HTMLElement, T = unknown>(initValues: T[], options?: Partial<ParentConfig<T>>): [Setter<E | null>, Accessor<Store<T[]>>, ReturnType<typeof createStore>[1], (config?: Partial<ParentConfig<T>>) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paraminitValues - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
} from "@formkit/drag-and-drop/solid";
export function function MyComponent(): JSX.ElementMyComponent() { const const todoItems: string[]todoItems = [ "Schedule perm", "Rewind VHS tapes", "Make change for the arcade", "Get disposable camera developed", "Learn C++", "Return Nintendo Power Glove", ]; const const doneItems: string[]doneItems = ["Pickup new mix-tape from Beth"]; const [const todoList: Setter<HTMLUListElement | null>todoList, const todos: Accessor<string[]>todos] = useDragAndDrop<HTMLUListElement, string>(initValues: string[], options?: Partial<ParentConfig<string>>): [Setter<HTMLUListElement | null>, Accessor<string[]>, SetStoreFunction<string[]>, (config?: Partial<ParentConfig<string>> | undefined) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paraminitValues - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
<HTMLUListElement, string>(
const todoItems: string[]todoItems, { group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "todoList",
sortable?: boolean | undefined
Flag for whether or not to allow sorting within a given parent.
sortable
: false,
} ); const [const doneList: Setter<HTMLUListElement | null>doneList, const dones: Accessor<string[]>dones] = useDragAndDrop<HTMLUListElement, string>(initValues: string[], options?: Partial<ParentConfig<string>>): [Setter<HTMLUListElement | null>, Accessor<string[]>, SetStoreFunction<string[]>, (config?: Partial<ParentConfig<string>> | undefined) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paraminitValues - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
<HTMLUListElement, string>(
const doneItems: string[]doneItems, { group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "todoList",
sortable?: boolean | undefined
Flag for whether or not to allow sorting within a given parent.
sortable
: false,
} ); return ( <JSX.HTMLElementTags.div: JSX.HTMLAttributes<HTMLDivElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/div@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLDivElement
div
JSX.DOMAttributes<HTMLDivElement>.class?: string | undefinedclass="kanban-board">
<JSX.HTMLElementTags.ul: JSX.HTMLAttributes<HTMLUListElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLUListElement
ul
ref?: HTMLUListElement | ((el: HTMLUListElement) => void) | undefinedref={const todoList: Setter<HTMLUListElement | null>todoList}>
<
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
each: false | string[] | null | undefinedeach={const todos: () => string[]todos()}>
{(todo: stringtodo) => <JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
JSX.DOMAttributes<T>.class?: string | undefinedclass="kanban-item">{todo: stringtodo}</JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
>}
</
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
>
</JSX.HTMLElementTags.ul: JSX.HTMLAttributes<HTMLUListElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLUListElement
ul
>
<JSX.HTMLElementTags.ul: JSX.HTMLAttributes<HTMLUListElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLUListElement
ul
ref?: HTMLUListElement | ((el: HTMLUListElement) => void) | undefinedref={const doneList: Setter<HTMLUListElement | null>doneList}>
<
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
each: false | string[] | null | undefinedeach={const dones: () => string[]dones()}>
{(done: stringdone) => <JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
JSX.DOMAttributes<T>.class?: string | undefinedclass="kanban-item">{done: stringdone}</JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
>}
</
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
>
</JSX.HTMLElementTags.ul: JSX.HTMLAttributes<HTMLUListElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLUListElement
ul
>
</JSX.HTMLElementTags.div: JSX.HTMLAttributes<HTMLDivElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/div@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLDivElement
div
>
); }
import { function reactive<T>(effect: () => T): Computed<T> (+1 overload)
A reactive object is a proxy of the original object that allows for reactive dependency watching. It is created by calling `reactive()` and should be used to store reactive data in your app and components.
@paramdata - The data to make reactive, typically a plain object.@returnsA reactive proxy of the original data.
reactive
, function html(strings: TemplateStringsArray | string[], ...expSlots: ArrowExpression[]): ArrowTemplatehtml } from "@arrow-js/core";
import { function dragAndDrop<T>({ parent, getValues, setValues, config, }: DragAndDrop<T>): void
Initializes the drag and drop functionality for a given parent.
@paramdragAndDrop - The drag and drop configuration.@returnsvoid
dragAndDrop
} from "@formkit/drag-and-drop";
const
const state: Reactive<{
    todos: string[];
    dones: string[];
}>
state
=
reactive<{
    todos: string[];
    dones: string[];
}>(data: {
    todos: string[];
    dones: string[];
}): Reactive<{
    todos: string[];
    dones: string[];
}> (+1 overload)
A reactive object is a proxy of the original object that allows for reactive dependency watching. It is created by calling `reactive()` and should be used to store reactive data in your app and components.
@paramdata - The data to make reactive, typically a plain object.@returnsA reactive proxy of the original data.
reactive
({
todos: string[]todos: [ "Schedule perm", "Rewind VHS tapes", "Make change for the arcade", "Get disposable camera developed", "Learn C++", "Return Nintendo Power Glove", ], dones: string[]dones: ["Pickup new mix-tape from Beth"], }); dragAndDrop<string>({ parent, getValues, setValues, config, }: DragAndDrop<string>): void
Initializes the drag and drop functionality for a given parent.
@paramdragAndDrop - The drag and drop configuration.@returnsvoid
dragAndDrop
<string>({
DragAndDrop<string>.parent: HTMLElement
The parent element that will contain the draggable nodes.
parent
: var document: Document
**`window.document`** returns a reference to the document contained in the window. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)
document
.Document.getElementById(elementId: string): HTMLElement | null
The **`getElementById()`** method of the Document interface returns an Element object representing the element whose id property matches the specified string. Since element IDs are required to be unique if specified, they're a useful way to get access to a specific element quickly.
getElementById
("todo-list")!,
DragAndDrop<string>.getValues: (parent: HTMLElement) => string[]
A function that returns the values assigned to the parent.
getValues
: () =>
const state: Reactive<{
    todos: string[];
    dones: string[];
}>
state
.todos: string[] | Reactive<string[]>todos,
DragAndDrop<string>.setValues: (values: string[], parent: HTMLElement) => void
A function that sets the values assigned to the parent.
setValues
: (newValues: string[]newValues) => {
const state: Reactive<{
    todos: string[];
    dones: string[];
}>
state
.todos: string[] | Reactive<string[]>todos = reactive<string[]>(data: string[]): Reactive<string[]> (+1 overload)
A reactive object is a proxy of the original object that allows for reactive dependency watching. It is created by calling `reactive()` and should be used to store reactive data in your app and components.
@paramdata - The data to make reactive, typically a plain object.@returnsA reactive proxy of the original data.
reactive
(newValues: string[]newValues);
}, DragAndDrop<string>.config?: Partial<ParentConfig<string>> | undefined
An optional configuration object.
config
: {
group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "todoList",
sortable?: boolean | undefined
Flag for whether or not to allow sorting within a given parent.
sortable
: false,
}, }); dragAndDrop<string>({ parent, getValues, setValues, config, }: DragAndDrop<string>): void
Initializes the drag and drop functionality for a given parent.
@paramdragAndDrop - The drag and drop configuration.@returnsvoid
dragAndDrop
<string>({
DragAndDrop<string>.parent: HTMLElement
The parent element that will contain the draggable nodes.
parent
: var document: Document
**`window.document`** returns a reference to the document contained in the window. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)
document
.Document.getElementById(elementId: string): HTMLElement | null
The **`getElementById()`** method of the Document interface returns an Element object representing the element whose id property matches the specified string. Since element IDs are required to be unique if specified, they're a useful way to get access to a specific element quickly.
getElementById
("done-list")!,
DragAndDrop<string>.getValues: (parent: HTMLElement) => string[]
A function that returns the values assigned to the parent.
getValues
: () =>
const state: Reactive<{
    todos: string[];
    dones: string[];
}>
state
.dones: string[] | Reactive<string[]>dones,
DragAndDrop<string>.setValues: (values: string[], parent: HTMLElement) => void
A function that sets the values assigned to the parent.
setValues
: (newValues: string[]newValues) => {
const state: Reactive<{
    todos: string[];
    dones: string[];
}>
state
.dones: string[] | Reactive<string[]>dones = reactive<string[]>(data: string[]): Reactive<string[]> (+1 overload)
A reactive object is a proxy of the original object that allows for reactive dependency watching. It is created by calling `reactive()` and should be used to store reactive data in your app and components.
@paramdata - The data to make reactive, typically a plain object.@returnsA reactive proxy of the original data.
reactive
(newValues: string[]newValues);
}, DragAndDrop<string>.config?: Partial<ParentConfig<string>> | undefined
An optional configuration object.
config
: {
group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "todoList",
sortable?: boolean | undefined
Flag for whether or not to allow sorting within a given parent.
sortable
: false,
}, }); function html(strings: TemplateStringsArray | string[], ...expSlots: ArrowExpression[]): ArrowTemplatehtml` <div class="kanban-board"> <ul class="kanban-list" id="todo-list"> ${() =>
const state: Reactive<{
    todos: string[];
    dones: string[];
}>
state
.todos: string[] | Reactive<string[]>todos.Array<T>.map<ArrowTemplate>(callbackfn: (value: string, index: number, array: string[]) => ArrowTemplate, thisArg?: any): ArrowTemplate[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
((todo: stringtodo) =>
function html(strings: TemplateStringsArray | string[], ...expSlots: ArrowExpression[]): ArrowTemplatehtml`<li class="kanban-item">${todo: stringtodo}</li>`.ArrowTemplate.key: (key: ArrowTemplateKey) => ArrowTemplatekey(todo: stringtodo) )} </ul> <ul class="kanban-list" id="done-list"> ${
const state: Reactive<{
    todos: string[];
    dones: string[];
}>
state
.dones: string[] | Reactive<string[]>dones.Array<T>.map<ArrowTemplate>(callbackfn: (value: string, index: number, array: string[]) => ArrowTemplate, thisArg?: any): ArrowTemplate[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
((done: stringdone) =>
function html(strings: TemplateStringsArray | string[], ...expSlots: ArrowExpression[]): ArrowTemplatehtml`<li class="kanban-item">${done: stringdone}</li>`.ArrowTemplate.key: (key: ArrowTemplateKey) => ArrowTemplatekey(done: stringdone) )} </ul> </div> `(var document: Document
**`window.document`** returns a reference to the document contained in the window. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)
document
.Document.getElementById(elementId: string): HTMLElement | null
The **`getElementById()`** method of the Document interface returns an Element object representing the element whose id property matches the specified string. Since element IDs are required to be unique if specified, they're a useful way to get access to a specific element quickly.
getElementById
("app")!);
static const todoItems = ["Schedule perm", "Rewind VHS tapes", "Make change for the arcade", "Get disposable camera developed", "Learn C++", "Return Nintendo Power Glove"];
static const doneItems = ["Pickup new mix-tape from Beth"];
static const config = { group: "todoList", sortable: false };

<let/todos=todoItems>
<let/dones=doneItems>

<div class="kanban-board">
  <ul/todoList class="kanban-column">
    <for|todo| of=todos by=(t => t)>
      <li class="kanban-item">${todo}</li>
    </for>
  </ul>
  <ul/doneList class="kanban-column">
    <for|done| of=dones by=(t => t)>
      <li class="kanban-item">${done}</li>
    </for>
  </ul>
</div>

<dnd:=todos parent=todoList config=config/>
<dnd:=dones parent=doneList config=config/>

Accepts

For a more nuanced transfer experience, define the accepts property in the configuration. This property is a callback function that lets you determine whether or not a given element can be transferred into the given list.

  • React
  • Vue
  • Solid
  • Native
  • Marko
import React from "react";
import type { interface ParentConfig<T>
The configuration object for a given parent.
ParentConfig
} from "@formkit/drag-and-drop";
import { function useDragAndDrop<E extends HTMLElement, T = unknown>(list: T[], options?: Partial<ParentConfig<T>>): [React.RefObject<E | null>, T[], React.Dispatch<React.SetStateAction<T[]>>, (config: Partial<ParentConfig<T>>) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paramlist - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
} from "@formkit/drag-and-drop/react";
export default function function myComponent(): React.JSX.ElementmyComponent() { const [const source: React.RefObject<HTMLUListElement | null>source, const items1: string[]items1] = useDragAndDrop<HTMLUListElement, string>(list: string[], options?: Partial<ParentConfig<string>>): [React.RefObject<HTMLUListElement | null>, string[], React.Dispatch<React.SetStateAction<string[]>>, (config: Partial<ParentConfig<string>>) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paramlist - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
<HTMLUListElement, string>(
["dungeon_master.exe", "map_1.dat", "map_2.dat", "character1.txt", "character2.txt", "shell32.dll", "README.txt",], { draggable?: ((child: HTMLElement) => boolean) | undefined
A function that returns whether a given node is draggable.
draggable
: (el: HTMLElementel) => {
return el: HTMLElementel.Element.id: string
The **`id`** property of the Element interface represents the element's identifier, reflecting the id global attribute. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Element/id)
id
!== "no-drag";
}, } ); const const config1: Partial<ParentConfig<string>>config1: type Partial<T> = { [P in keyof T]?: T[P] | undefined; }
Make all properties in T optional
Partial
<interface ParentConfig<T>
The configuration object for a given parent.
ParentConfig
<string>> = {};
const config1: Partial<ParentConfig<string>>config1.accepts?: ((targetParentData: ParentRecord<string>, initialParentData: ParentRecord<string>, currentParentData: ParentRecord<string>, state: BaseDragState<string>) => boolean) | undefined
A function that returns whether a given parent accepts a given node.
accepts
= (_parent: ParentRecord<string>_parent, lastParent: ParentRecord<string>lastParent) => {
if (lastParent: ParentRecord<string>lastParent.ParentRecord<string>.el: HTMLElementel === const target2: React.RefObject<HTMLUListElement | null>target2.React.RefObject<HTMLUListElement | null>.current: HTMLUListElement | null
The current value of the ref.
current
) {
return false; } return const items2: string[]items2.Array<string>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
< 3;
}; const const config2: Partial<ParentConfig<string>>config2: type Partial<T> = { [P in keyof T]?: T[P] | undefined; }
Make all properties in T optional
Partial
<interface ParentConfig<T>
The configuration object for a given parent.
ParentConfig
<string>> = {};
const config2: Partial<ParentConfig<string>>config2.accepts?: ((targetParentData: ParentRecord<string>, initialParentData: ParentRecord<string>, currentParentData: ParentRecord<string>, state: BaseDragState<string>) => boolean) | undefined
A function that returns whether a given parent accepts a given node.
accepts
= (_parent: ParentRecord<string>_parent, lastParent: ParentRecord<string>lastParent) => {
if (lastParent: ParentRecord<string>lastParent.ParentRecord<string>.el: HTMLElementel === const target1: React.RefObject<HTMLUListElement | null>target1.React.RefObject<HTMLUListElement | null>.current: HTMLUListElement | null
The current value of the ref.
current
) {
return false; } return const items3: string[]items3.Array<string>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
< 5;
}; const [const target1: React.RefObject<HTMLUListElement | null>target1, const items2: string[]items2] = useDragAndDrop<HTMLUListElement, string>(list: string[], options?: Partial<ParentConfig<string>>): [React.RefObject<HTMLUListElement | null>, string[], React.Dispatch<React.SetStateAction<string[]>>, (config: Partial<ParentConfig<string>>) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paramlist - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
<HTMLUListElement, string>(
["knight.bmp", "dragon.bmp"], const config1: Partial<ParentConfig<string>>config1 ); const [const target2: React.RefObject<HTMLUListElement | null>target2, const items3: string[]items3] = useDragAndDrop<HTMLUListElement, string>(list: string[], options?: Partial<ParentConfig<string>>): [React.RefObject<HTMLUListElement | null>, string[], React.Dispatch<React.SetStateAction<string[]>>, (config: Partial<ParentConfig<string>>) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paramlist - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
<HTMLUListElement, string>(
["brick.bmp", "moss.bmp"], const config2: Partial<ParentConfig<string>>config2 ); return ( <React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div> <React.JSX.IntrinsicElements.ul: React.DetailedHTMLProps<React.HTMLAttributes<HTMLUListElement>, HTMLUListElement>ul React.RefAttributes<HTMLUListElement>.ref?: React.Ref<HTMLUListElement> | undefined
Allows getting a ref to the component instance. Once the component unmounts, React will set `ref.current` to `null` (or call the ref with `null` if you passed a callback ref).
@see{@link https://react.dev/learn/referencing-values-with-refs#refs-and-the-dom React Docs}
ref
={const source: React.RefObject<HTMLUListElement | null>source}>
{const items1: string[]items1.Array<string>.map<React.JSX.Element>(callbackfn: (value: string, index: number, array: string[]) => React.JSX.Element, thisArg?: any): React.JSX.Element[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
((item: stringitem) => (
<React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li React.Attributes.key?: React.Key | null | undefinedkey={item: stringitem}>{item: stringitem}</React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li> ))} </React.JSX.IntrinsicElements.ul: React.DetailedHTMLProps<React.HTMLAttributes<HTMLUListElement>, HTMLUListElement>ul> <React.JSX.IntrinsicElements.ul: React.DetailedHTMLProps<React.HTMLAttributes<HTMLUListElement>, HTMLUListElement>ul React.RefAttributes<HTMLUListElement>.ref?: React.Ref<HTMLUListElement> | undefined
Allows getting a ref to the component instance. Once the component unmounts, React will set `ref.current` to `null` (or call the ref with `null` if you passed a callback ref).
@see{@link https://react.dev/learn/referencing-values-with-refs#refs-and-the-dom React Docs}
ref
={const target1: React.RefObject<HTMLUListElement | null>target1}>
{const items2: string[]items2.Array<string>.map<React.JSX.Element>(callbackfn: (value: string, index: number, array: string[]) => React.JSX.Element, thisArg?: any): React.JSX.Element[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
((item: stringitem) => (
<React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li React.Attributes.key?: React.Key | null | undefinedkey={item: stringitem}>{item: stringitem}</React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li> ))} </React.JSX.IntrinsicElements.ul: React.DetailedHTMLProps<React.HTMLAttributes<HTMLUListElement>, HTMLUListElement>ul> <React.JSX.IntrinsicElements.ul: React.DetailedHTMLProps<React.HTMLAttributes<HTMLUListElement>, HTMLUListElement>ul React.RefAttributes<HTMLUListElement>.ref?: React.Ref<HTMLUListElement> | undefined
Allows getting a ref to the component instance. Once the component unmounts, React will set `ref.current` to `null` (or call the ref with `null` if you passed a callback ref).
@see{@link https://react.dev/learn/referencing-values-with-refs#refs-and-the-dom React Docs}
ref
={const target2: React.RefObject<HTMLUListElement | null>target2}>
{const items3: string[]items3.Array<string>.map<React.JSX.Element>(callbackfn: (value: string, index: number, array: string[]) => React.JSX.Element, thisArg?: any): React.JSX.Element[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
((item: stringitem) => (
<React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li React.Attributes.key?: React.Key | null | undefinedkey={item: stringitem}>{item: stringitem}</React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li> ))} </React.JSX.IntrinsicElements.ul: React.DetailedHTMLProps<React.HTMLAttributes<HTMLUListElement>, HTMLUListElement>ul> </React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div> ); }
<script setup lang="ts">
import type { interface ParentConfig<T>
The configuration object for a given parent.
ParentConfig
} from "@formkit/drag-and-drop";
import { function useDragAndDrop<T>(initialValues: T[], options?: Partial<VueParentConfig<T>>): [Ref<HTMLElement | undefined>, Ref<T[]>, (config: Partial<VueParentConfig<T>>) => void]
Creates a new instance of drag and drop and returns the parent element and a ref of the values to use in your template.
@paraminitialValues - The initial values of the parent element.@returnsThe parent element and values for drag and drop.
useDragAndDrop
} from "@formkit/drag-and-drop/vue";
const [const source: Ref<HTMLElement | undefined, HTMLElement | undefined>source, const items1: Ref<string[], string[]>items1] = useDragAndDrop<string>(initialValues: string[], options?: Partial<Partial<ParentConfig<string>>>): [Ref<HTMLElement | undefined, HTMLElement | undefined>, Ref<string[], string[]>, (config: Partial<Partial<ParentConfig<string>>>) => void]
Creates a new instance of drag and drop and returns the parent element and a ref of the values to use in your template.
@paraminitialValues - The initial values of the parent element.@returnsThe parent element and values for drag and drop.
useDragAndDrop
(
["dungeon_master.exe", "map_1.dat", "map_2.dat", "character1.txt", "character2.txt", "shell32.dll", "README.txt"], { accepts?: ((targetParentData: ParentRecord<string>, initialParentData: ParentRecord<string>, currentParentData: ParentRecord<string>, state: BaseDragState<string>) => boolean) | undefined
A function that returns whether a given parent accepts a given node.
accepts
: () => {
return true; }, } ); const const config1: Partial<ParentConfig<string>>config1: type Partial<T> = { [P in keyof T]?: T[P] | undefined; }
Make all properties in T optional
Partial
<interface ParentConfig<T>
The configuration object for a given parent.
ParentConfig
<string>> = {};
const config1: Partial<ParentConfig<string>>config1.accepts?: ((targetParentData: ParentRecord<string>, initialParentData: ParentRecord<string>, currentParentData: ParentRecord<string>, state: BaseDragState<string>) => boolean) | undefined
A function that returns whether a given parent accepts a given node.
accepts
= (_parent: ParentRecord<string>_parent, lastParent: ParentRecord<string>lastParent) => {
if (lastParent: ParentRecord<string>lastParent.ParentRecord<string>.el: HTMLElementel === const target2: Ref<HTMLElement | undefined, HTMLElement | undefined>target2.Ref<HTMLElement | undefined, HTMLElement | undefined>.value: HTMLElement | undefinedvalue) { return false; } return const items2: Ref<string[], string[]>items2.Ref<string[], string[]>.value: string[]value.Array<T>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
< 3;
}; const const config2: Partial<ParentConfig<string>>config2: type Partial<T> = { [P in keyof T]?: T[P] | undefined; }
Make all properties in T optional
Partial
<interface ParentConfig<T>
The configuration object for a given parent.
ParentConfig
<string>> = {};
const config2: Partial<ParentConfig<string>>config2.accepts?: ((targetParentData: ParentRecord<string>, initialParentData: ParentRecord<string>, currentParentData: ParentRecord<string>, state: BaseDragState<string>) => boolean) | undefined
A function that returns whether a given parent accepts a given node.
accepts
= (_parent: ParentRecord<string>_parent, lastParent: ParentRecord<string>lastParent) => {
if (lastParent: ParentRecord<string>lastParent.ParentRecord<string>.el: HTMLElementel === const target1: Ref<HTMLElement | undefined, HTMLElement | undefined>target1.Ref<HTMLElement | undefined, HTMLElement | undefined>.value: HTMLElement | undefinedvalue) { return false; } return const items3: Ref<string[], string[]>items3.Ref<string[], string[]>.value: string[]value.Array<T>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
< 5;
}; const [const target1: Ref<HTMLElement | undefined, HTMLElement | undefined>target1, const items2: Ref<string[], string[]>items2] = useDragAndDrop<string>(initialValues: string[], options?: Partial<Partial<ParentConfig<string>>>): [Ref<HTMLElement | undefined, HTMLElement | undefined>, Ref<string[], string[]>, (config: Partial<Partial<ParentConfig<string>>>) => void]
Creates a new instance of drag and drop and returns the parent element and a ref of the values to use in your template.
@paraminitialValues - The initial values of the parent element.@returnsThe parent element and values for drag and drop.
useDragAndDrop
(["knight.bmp", "dragon.bmp"], const config1: Partial<ParentConfig<string>>config1);
const [const target2: Ref<HTMLElement | undefined, HTMLElement | undefined>target2, const items3: Ref<string[], string[]>items3] = useDragAndDrop<string>(initialValues: string[], options?: Partial<Partial<ParentConfig<string>>>): [Ref<HTMLElement | undefined, HTMLElement | undefined>, Ref<string[], string[]>, (config: Partial<Partial<ParentConfig<string>>>) => void]
Creates a new instance of drag and drop and returns the parent element and a ref of the values to use in your template.
@paraminitialValues - The initial values of the parent element.@returnsThe parent element and values for drag and drop.
useDragAndDrop
(["brick.bmp", "moss.bmp"], const config2: Partial<ParentConfig<string>>config2);
</script> <template> <div: HTMLAttributes & ReservedPropsdiv name: stringname="accepts"> <div: HTMLAttributes & ReservedPropsdiv HTMLAttributes.class?: ClassValueclass="flex justify-between"> <div: HTMLAttributes & ReservedPropsdiv> <ul: HTMLAttributes & ReservedPropsul ReservedProps.ref?: VNodeRef | undefinedref="source: HTMLUListElementsource"> <li: LiHTMLAttributes & ReservedPropsli v-for="const item: stringitem in const items1: Ref<string[], string[]>items1" ReservedProps.key?: PropertyKey | undefined:key="const item: stringitem">{{ const item: stringitem }}</li: LiHTMLAttributes & ReservedPropsli> </ul: HTMLAttributes & ReservedPropsul> </div: HTMLAttributes & ReservedPropsdiv> <div: HTMLAttributes & ReservedPropsdiv HTMLAttributes.class?: ClassValueclass="flex flex-col"> <div: HTMLAttributes & ReservedPropsdiv> <h5: HTMLAttributes & ReservedPropsh5>I can accept up to three items</h5: HTMLAttributes & ReservedPropsh5> <ul: HTMLAttributes & ReservedPropsul ReservedProps.ref?: VNodeRef | undefinedref="target1: HTMLUListElementtarget1" HTMLAttributes.class?: ClassValueclass="border-solid border-2 border-indigo-600"> <li: LiHTMLAttributes & ReservedPropsli v-for="const item: stringitem in const items2: Ref<string[], string[]>items2" ReservedProps.key?: PropertyKey | undefined:key="const item: stringitem">{{ const item: stringitem }}</li: LiHTMLAttributes & ReservedPropsli> </ul: HTMLAttributes & ReservedPropsul> </div: HTMLAttributes & ReservedPropsdiv> <div: HTMLAttributes & ReservedPropsdiv> I can accept up to five items. <ul: HTMLAttributes & ReservedPropsul ReservedProps.ref?: VNodeRef | undefinedref="target2: HTMLUListElementtarget2" HTMLAttributes.class?: ClassValueclass="border-solid border-2 border-indigo-600"> <li: LiHTMLAttributes & ReservedPropsli v-for="const item: stringitem in const items3: Ref<string[], string[]>items3" ReservedProps.key?: PropertyKey | undefined:key="const item: stringitem">{{ const item: stringitem }}</li: LiHTMLAttributes & ReservedPropsli> </ul: HTMLAttributes & ReservedPropsul> </div: HTMLAttributes & ReservedPropsdiv> </div: HTMLAttributes & ReservedPropsdiv> </div: HTMLAttributes & ReservedPropsdiv> </div: HTMLAttributes & ReservedPropsdiv> </template>
/** @jsxImportSource solid-js */
import type { interface ParentConfig<T>
The configuration object for a given parent.
ParentConfig
} from "@formkit/drag-and-drop";
import {
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
} from "solid-js";
import { function useDragAndDrop<E extends HTMLElement, T = unknown>(initValues: T[], options?: Partial<ParentConfig<T>>): [Setter<E | null>, Accessor<Store<T[]>>, ReturnType<typeof createStore>[1], (config?: Partial<ParentConfig<T>>) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paraminitValues - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
} from "@formkit/drag-and-drop/solid";
export default function function MyComponent(): JSX.ElementMyComponent() { const [const source: Setter<HTMLUListElement | null>source, const items1: Accessor<string[]>items1] = useDragAndDrop<HTMLUListElement, string>(initValues: string[], options?: Partial<ParentConfig<string>>): [Setter<HTMLUListElement | null>, Accessor<string[]>, SetStoreFunction<string[]>, (config?: Partial<ParentConfig<string>> | undefined) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paraminitValues - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
<HTMLUListElement, string>(
[ "dungeon_master.exe", "map_1.dat", "map_2.dat", "character1.txt", "character2.txt", "shell32.dll", "README.txt", ], { draggable?: ((child: HTMLElement) => boolean) | undefined
A function that returns whether a given node is draggable.
draggable
: (el: HTMLElementel) => {
return el: HTMLElementel.Element.id: string
The **`id`** property of the Element interface represents the element's identifier, reflecting the id global attribute. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Element/id)
id
!== "no-drag";
}, } ); const const config1: Partial<ParentConfig<string>>config1: type Partial<T> = { [P in keyof T]?: T[P] | undefined; }
Make all properties in T optional
Partial
<interface ParentConfig<T>
The configuration object for a given parent.
ParentConfig
<string>> = {};
const config1: Partial<ParentConfig<string>>config1.accepts?: ((targetParentData: ParentRecord<string>, initialParentData: ParentRecord<string>, currentParentData: ParentRecord<string>, state: BaseDragState<string>) => boolean) | undefined
A function that returns whether a given parent accepts a given node.
accepts
= (_parent: ParentRecord<string>_parent, lastParent: ParentRecord<string>lastParent) => {
if ( const target2: Setter<HTMLElement | null>target2 && const target2: Setter<HTMLElement | null>target2 instanceof
var HTMLElement: {
    new (): HTMLElement;
    prototype: HTMLElement;
}
The **`HTMLElement`** interface represents any HTML element. Some elements directly implement this interface, while others implement it via an interface that inherits it. [MDN Reference](https://developer.mozilla.org/docs/Web/API/HTMLElement)
HTMLElement
&&
lastParent: ParentRecord<string>lastParent.ParentRecord<T>.el: HTMLElementel === const target2: Setter<HTMLElement | null> & HTMLElementtarget2 ) { return false; } return const items2: () => string[]items2().Array<string>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
< 3;
}; const const config2: Partial<ParentConfig<string>>config2: type Partial<T> = { [P in keyof T]?: T[P] | undefined; }
Make all properties in T optional
Partial
<interface ParentConfig<T>
The configuration object for a given parent.
ParentConfig
<string>> = {};
const config2: Partial<ParentConfig<string>>config2.accepts?: ((targetParentData: ParentRecord<string>, initialParentData: ParentRecord<string>, currentParentData: ParentRecord<string>, state: BaseDragState<string>) => boolean) | undefined
A function that returns whether a given parent accepts a given node.
accepts
= (_parent: ParentRecord<string>_parent, lastParent: ParentRecord<string>lastParent) => {
if ( const target1: Setter<HTMLElement | null>target1 && const target1: Setter<HTMLElement | null>target1 instanceof
var HTMLElement: {
    new (): HTMLElement;
    prototype: HTMLElement;
}
The **`HTMLElement`** interface represents any HTML element. Some elements directly implement this interface, while others implement it via an interface that inherits it. [MDN Reference](https://developer.mozilla.org/docs/Web/API/HTMLElement)
HTMLElement
&&
lastParent: ParentRecord<string>lastParent.ParentRecord<T>.el: HTMLElementel === const target1: Setter<HTMLElement | null> & HTMLElementtarget1 ) { return false; } return const items3: () => string[]items3().Array<string>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
< 5;
}; const [const target1: Setter<HTMLElement | null>target1, const items2: Accessor<string[]>items2] = useDragAndDrop<HTMLElement, string>(initValues: string[], options?: Partial<ParentConfig<string>>): [Setter<HTMLElement | null>, Accessor<string[]>, SetStoreFunction<string[]>, (config?: Partial<ParentConfig<string>> | undefined) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paraminitValues - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
(
["knight.bmp", "dragon.bmp"], const config1: Partial<ParentConfig<string>>config1 ); const [const target2: Setter<HTMLElement | null>target2, const items3: Accessor<string[]>items3] = useDragAndDrop<HTMLElement, string>(initValues: string[], options?: Partial<ParentConfig<string>>): [Setter<HTMLElement | null>, Accessor<string[]>, SetStoreFunction<string[]>, (config?: Partial<ParentConfig<string>> | undefined) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paraminitValues - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
(["brick.bmp", "moss.bmp"], const config2: Partial<ParentConfig<string>>config2);
return ( <JSX.HTMLElementTags.div: JSX.HTMLAttributes<HTMLDivElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/div@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLDivElement
div
>
<JSX.HTMLElementTags.ul: JSX.HTMLAttributes<HTMLUListElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLUListElement
ul
ref?: HTMLUListElement | ((el: HTMLUListElement) => void) | undefinedref={const source: Setter<HTMLUListElement | null>source}>
<
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
each: false | string[] | null | undefinedeach={const items1: () => string[]items1()}>{(item: stringitem) => <JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
>{item: stringitem}</JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
>}</
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
>
</JSX.HTMLElementTags.ul: JSX.HTMLAttributes<HTMLUListElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLUListElement
ul
>
<JSX.HTMLElementTags.ul: JSX.HTMLAttributes<HTMLUListElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLUListElement
ul
ref?: HTMLUListElement | ((el: HTMLUListElement) => void) | undefinedref={const target1: Setter<HTMLElement | null>target1}>
<
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
each: false | string[] | null | undefinedeach={const items2: () => string[]items2()}>{(item: stringitem) => <JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
>{item: stringitem}</JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
>}</
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
>
</JSX.HTMLElementTags.ul: JSX.HTMLAttributes<HTMLUListElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLUListElement
ul
>
<JSX.HTMLElementTags.ul: JSX.HTMLAttributes<HTMLUListElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLUListElement
ul
ref?: HTMLUListElement | ((el: HTMLUListElement) => void) | undefinedref={const target2: Setter<HTMLElement | null>target2}>
<
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
each: false | string[] | null | undefinedeach={const items3: () => string[]items3()}>{(item: stringitem) => <JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
>{item: stringitem}</JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
>}</
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
>
</JSX.HTMLElementTags.ul: JSX.HTMLAttributes<HTMLUListElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLUListElement
ul
>
</JSX.HTMLElementTags.div: JSX.HTMLAttributes<HTMLDivElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/div@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLDivElement
div
>
); }
import { function reactive<T>(effect: () => T): Computed<T> (+1 overload)
A reactive object is a proxy of the original object that allows for reactive dependency watching. It is created by calling `reactive()` and should be used to store reactive data in your app and components.
@paramdata - The data to make reactive, typically a plain object.@returnsA reactive proxy of the original data.
reactive
, function html(strings: TemplateStringsArray | string[], ...expSlots: ArrowExpression[]): ArrowTemplatehtml } from "@arrow-js/core";
import { function dragAndDrop<T>({ parent, getValues, setValues, config, }: DragAndDrop<T>): void
Initializes the drag and drop functionality for a given parent.
@paramdragAndDrop - The drag and drop configuration.@returnsvoid
dragAndDrop
} from "@formkit/drag-and-drop";
const
const state: Reactive<{
    items1: string[];
    items2: string[];
    items3: string[];
}>
state
=
reactive<{
    items1: string[];
    items2: string[];
    items3: string[];
}>(data: {
    items1: string[];
    items2: string[];
    items3: string[];
}): Reactive<{
    items1: string[];
    items2: string[];
    items3: string[];
}> (+1 overload)
A reactive object is a proxy of the original object that allows for reactive dependency watching. It is created by calling `reactive()` and should be used to store reactive data in your app and components.
@paramdata - The data to make reactive, typically a plain object.@returnsA reactive proxy of the original data.
reactive
({
items1: string[]items1: ["dungeon_master.exe", "map_1.dat", "map_2.dat", "character1.txt", "character2.txt", "shell32.dll", "README.txt"], items2: string[]items2: ["knight.bmp", "dragon.bmp"], items3: string[]items3: ["brick.bmp", "moss.bmp"], }); dragAndDrop<string>({ parent, getValues, setValues, config, }: DragAndDrop<string>): void
Initializes the drag and drop functionality for a given parent.
@paramdragAndDrop - The drag and drop configuration.@returnsvoid
dragAndDrop
<string>({
DragAndDrop<string>.parent: HTMLElement
The parent element that will contain the draggable nodes.
parent
: var document: Document
**`window.document`** returns a reference to the document contained in the window. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)
document
.Document.getElementById(elementId: string): HTMLElement | null
The **`getElementById()`** method of the Document interface returns an Element object representing the element whose id property matches the specified string. Since element IDs are required to be unique if specified, they're a useful way to get access to a specific element quickly.
getElementById
("source")!,
DragAndDrop<string>.getValues: (parent: HTMLElement) => string[]
A function that returns the values assigned to the parent.
getValues
: () =>
const state: Reactive<{
    items1: string[];
    items2: string[];
    items3: string[];
}>
state
.items1: string[] | Reactive<string[]>items1,
DragAndDrop<string>.setValues: (values: string[], parent: HTMLElement) => void
A function that sets the values assigned to the parent.
setValues
: (newValues: string[]newValues) => {
const state: Reactive<{
    items1: string[];
    items2: string[];
    items3: string[];
}>
state
.items1: string[] | Reactive<string[]>items1 = reactive<string[]>(data: string[]): Reactive<string[]> (+1 overload)
A reactive object is a proxy of the original object that allows for reactive dependency watching. It is created by calling `reactive()` and should be used to store reactive data in your app and components.
@paramdata - The data to make reactive, typically a plain object.@returnsA reactive proxy of the original data.
reactive
(newValues: string[]newValues);
}, DragAndDrop<string>.config?: Partial<ParentConfig<string>> | undefined
An optional configuration object.
config
: {
accepts?: ((targetParentData: ParentRecord<string>, initialParentData: ParentRecord<string>, currentParentData: ParentRecord<string>, state: BaseDragState<string>) => boolean) | undefined
A function that returns whether a given parent accepts a given node.
accepts
: () => {
return true; }, }, }); dragAndDrop<string>({ parent, getValues, setValues, config, }: DragAndDrop<string>): void
Initializes the drag and drop functionality for a given parent.
@paramdragAndDrop - The drag and drop configuration.@returnsvoid
dragAndDrop
<string>({
DragAndDrop<string>.parent: HTMLElement
The parent element that will contain the draggable nodes.
parent
: var document: Document
**`window.document`** returns a reference to the document contained in the window. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)
document
.Document.getElementById(elementId: string): HTMLElement | null
The **`getElementById()`** method of the Document interface returns an Element object representing the element whose id property matches the specified string. Since element IDs are required to be unique if specified, they're a useful way to get access to a specific element quickly.
getElementById
("target1")!,
DragAndDrop<string>.getValues: (parent: HTMLElement) => string[]
A function that returns the values assigned to the parent.
getValues
: () =>
const state: Reactive<{
    items1: string[];
    items2: string[];
    items3: string[];
}>
state
.items2: string[] | Reactive<string[]>items2,
DragAndDrop<string>.setValues: (values: string[], parent: HTMLElement) => void
A function that sets the values assigned to the parent.
setValues
: (newValues: string[]newValues) => {
const state: Reactive<{
    items1: string[];
    items2: string[];
    items3: string[];
}>
state
.items2: string[] | Reactive<string[]>items2 = reactive<string[]>(data: string[]): Reactive<string[]> (+1 overload)
A reactive object is a proxy of the original object that allows for reactive dependency watching. It is created by calling `reactive()` and should be used to store reactive data in your app and components.
@paramdata - The data to make reactive, typically a plain object.@returnsA reactive proxy of the original data.
reactive
(newValues: string[]newValues);
}, DragAndDrop<string>.config?: Partial<ParentConfig<string>> | undefined
An optional configuration object.
config
: {
accepts?: ((targetParentData: ParentRecord<string>, initialParentData: ParentRecord<string>, currentParentData: ParentRecord<string>, state: BaseDragState<string>) => boolean) | undefined
A function that returns whether a given parent accepts a given node.
accepts
: () => {
return
const state: Reactive<{
    items1: string[];
    items2: string[];
    items3: string[];
}>
state
.items1: string[] | Reactive<string[]>items1.Array<T>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
< 3;
}, }, }); dragAndDrop<string>({ parent, getValues, setValues, config, }: DragAndDrop<string>): void
Initializes the drag and drop functionality for a given parent.
@paramdragAndDrop - The drag and drop configuration.@returnsvoid
dragAndDrop
<string>({
DragAndDrop<string>.parent: HTMLElement
The parent element that will contain the draggable nodes.
parent
: var document: Document
**`window.document`** returns a reference to the document contained in the window. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)
document
.Document.getElementById(elementId: string): HTMLElement | null
The **`getElementById()`** method of the Document interface returns an Element object representing the element whose id property matches the specified string. Since element IDs are required to be unique if specified, they're a useful way to get access to a specific element quickly.
getElementById
("target2")!,
DragAndDrop<string>.getValues: (parent: HTMLElement) => string[]
A function that returns the values assigned to the parent.
getValues
: () =>
const state: Reactive<{
    items1: string[];
    items2: string[];
    items3: string[];
}>
state
.items3: string[] | Reactive<string[]>items3,
DragAndDrop<string>.setValues: (values: string[], parent: HTMLElement) => void
A function that sets the values assigned to the parent.
setValues
: (newValues: string[]newValues) => {
const state: Reactive<{
    items1: string[];
    items2: string[];
    items3: string[];
}>
state
.items3: string[] | Reactive<string[]>items3 = reactive<string[]>(data: string[]): Reactive<string[]> (+1 overload)
A reactive object is a proxy of the original object that allows for reactive dependency watching. It is created by calling `reactive()` and should be used to store reactive data in your app and components.
@paramdata - The data to make reactive, typically a plain object.@returnsA reactive proxy of the original data.
reactive
(newValues: string[]newValues);
}, DragAndDrop<string>.config?: Partial<ParentConfig<string>> | undefined
An optional configuration object.
config
: {
accepts?: ((targetParentData: ParentRecord<string>, initialParentData: ParentRecord<string>, currentParentData: ParentRecord<string>, state: BaseDragState<string>) => boolean) | undefined
A function that returns whether a given parent accepts a given node.
accepts
: () => {
return
const state: Reactive<{
    items1: string[];
    items2: string[];
    items3: string[];
}>
state
.items1: string[] | Reactive<string[]>items1.Array<T>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
< 3;
}, }, }); function html(strings: TemplateStringsArray | string[], ...expSlots: ArrowExpression[]): ArrowTemplatehtml` <div> <ul id="source"> ${
const state: Reactive<{
    items1: string[];
    items2: string[];
    items3: string[];
}>
state
.items1: string[] | Reactive<string[]>items1.Array<T>.map<ArrowTemplate>(callbackfn: (value: string, index: number, array: string[]) => ArrowTemplate, thisArg?: any): ArrowTemplate[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
((item: stringitem) => function html(strings: TemplateStringsArray | string[], ...expSlots: ArrowExpression[]): ArrowTemplatehtml`<li>${item: stringitem}</li>`)}
</ul> <div> <h5>I can accept up to three items</h5> <ul id="target1"> ${
const state: Reactive<{
    items1: string[];
    items2: string[];
    items3: string[];
}>
state
.items2: string[] | Reactive<string[]>items2.Array<T>.map<ArrowTemplate>(callbackfn: (value: string, index: number, array: string[]) => ArrowTemplate, thisArg?: any): ArrowTemplate[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
((item: stringitem) => function html(strings: TemplateStringsArray | string[], ...expSlots: ArrowExpression[]): ArrowTemplatehtml`<li>${item: stringitem}</li>`)}
</ul> <h5>I can accept up to five items</h5> <ul id="target2"> ${
const state: Reactive<{
    items1: string[];
    items2: string[];
    items3: string[];
}>
state
.items2: string[] | Reactive<string[]>items2.Array<T>.map<ArrowTemplate>(callbackfn: (value: string, index: number, array: string[]) => ArrowTemplate, thisArg?: any): ArrowTemplate[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
((item: stringitem) => function html(strings: TemplateStringsArray | string[], ...expSlots: ArrowExpression[]): ArrowTemplatehtml`<li>${item: stringitem}</li>`)}
</ul> </div> </div> `(var document: Document
**`window.document`** returns a reference to the document contained in the window. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)
document
.Document.getElementById(elementId: string): HTMLElement | null
The **`getElementById()`** method of the Document interface returns an Element object representing the element whose id property matches the specified string. Since element IDs are required to be unique if specified, they're a useful way to get access to a specific element quickly.
getElementById
("app")!);
static const sourceItems = ["dungeon_master.exe", "map_1.dat", "map_2.dat", "character1.txt", "character2.txt", "shell32.dll", "README.txt"];
static const target1Items = ["knight.bmp", "dragon.bmp"];
static const target2Items = ["brick.bmp", "moss.bmp"];

<let/items1=sourceItems>
<let/items2=target1Items>
<let/items3=target2Items>

<!-- Config objects are stable; accepts callbacks close over reactive vars. -->
<let/sourceConfig={ accepts: () => true }>
<let/target1Config={
  accepts: (_parent, lastParent) => {
    if (lastParent.el === target2()) return false;
    return items2.length < 3;
  },
}>
<let/target2Config={
  accepts: (_parent, lastParent) => {
    if (lastParent.el === target1()) return false;
    return items3.length < 5;
  },
}>

<div>
  <div class="flex justify-between">
    <div>
      <ul/source>
        <for|item| of=items1 by=(i => i)>
          <li>${item}</li>
        </for>
      </ul>
    </div>
    <div class="flex flex-col">
      <div>
        <h5>I can accept up to three items</h5>
        <ul/target1 class="border-solid border-2 border-indigo-600">
          <for|item| of=items2 by=(i => i)>
            <li>${item}</li>
          </for>
        </ul>
      </div>
      <div>
        I can accept up to five items.
        <ul/target2 class="border-solid border-2 border-indigo-600">
          <for|item| of=items3 by=(i => i)>
            <li>${item}</li>
          </for>
        </ul>
      </div>
    </div>
  </div>
</div>

<dnd:=items1 parent=source config=sourceConfig/>
<dnd:=items2 parent=target1 config=target1Config/>
<dnd:=items3 parent=target2 config=target2Config/>

Drag Handles

Drag handles are a common way to allow users to drag items without accidentally dragging them when they don't intend to. To implement drag handles, set the dragHandle property to a selector that will be used to find the handle.

  • React
  • Vue
  • Solid
  • Native
  • Marko
import React from "react";
import { function useDragAndDrop<E extends HTMLElement, T = unknown>(list: T[], options?: Partial<ParentConfig<T>>): [React.RefObject<E | null>, T[], React.Dispatch<React.SetStateAction<T[]>>, (config: Partial<ParentConfig<T>>) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paramlist - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
} from "@formkit/drag-and-drop/react";
export function function myComponent(): React.JSX.ElementmyComponent() { const const todoItems: string[]todoItems = ["Schedule perm", "Rewind VHS tapes", "Make change for the arcade", "Get disposable camera developed", "Learn C++", "Return Nintendo Power Glove"]; const const doneItems: string[]doneItems = ["Pickup new mix-tape from Beth", "Implement drag handles"]; const [const todoList: React.RefObject<HTMLUListElement | null>todoList, const todos: string[]todos] = useDragAndDrop<HTMLUListElement, string>(list: string[], options?: Partial<ParentConfig<string>>): [React.RefObject<HTMLUListElement | null>, string[], React.Dispatch<React.SetStateAction<string[]>>, (config: Partial<ParentConfig<string>>) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paramlist - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
<HTMLUListElement, string>(
const todoItems: string[]todoItems, { group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "todoList",
dragHandle?: string | undefined
A selector for the drag handle. Will search at any depth within the draggable element.
dragHandle
: ".kanban-handle"
} ); const [const doneList: React.RefObject<HTMLUListElement | null>doneList, const dones: string[]dones] = useDragAndDrop<HTMLUListElement, string>(list: string[], options?: Partial<ParentConfig<string>>): [React.RefObject<HTMLUListElement | null>, string[], React.Dispatch<React.SetStateAction<string[]>>, (config: Partial<ParentConfig<string>>) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paramlist - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
<HTMLUListElement, string>(
const doneItems: string[]doneItems, { group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "todoList",
dragHandle?: string | undefined
A selector for the drag handle. Will search at any depth within the draggable element.
dragHandle
: ".kanban-handle"
} ); return ( <React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div React.HTMLAttributes<HTMLDivElement>.className?: string | undefinedclassName="kanban-board"> <React.JSX.IntrinsicElements.ul: React.DetailedHTMLProps<React.HTMLAttributes<HTMLUListElement>, HTMLUListElement>ul React.RefAttributes<HTMLUListElement>.ref?: React.Ref<HTMLUListElement> | undefined
Allows getting a ref to the component instance. Once the component unmounts, React will set `ref.current` to `null` (or call the ref with `null` if you passed a callback ref).
@see{@link https://react.dev/learn/referencing-values-with-refs#refs-and-the-dom React Docs}
ref
={const todoList: React.RefObject<HTMLUListElement | null>todoList} React.HTMLAttributes<T>.className?: string | undefinedclassName="kanban-column">
{const todos: string[]todos.Array<string>.map<React.JSX.Element>(callbackfn: (value: string, index: number, array: string[]) => React.JSX.Element, thisArg?: any): React.JSX.Element[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
((todo: stringtodo) => (
<React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li React.HTMLAttributes<T>.className?: string | undefinedclassName="kanban-item" React.Attributes.key?: React.Key | null | undefinedkey={todo: stringtodo}> <React.JSX.IntrinsicElements.span: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>span React.HTMLAttributes<T>.className?: string | undefinedclassName="kanban-handle"></React.JSX.IntrinsicElements.span: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>span> {todo: stringtodo} </React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li> ))} </React.JSX.IntrinsicElements.ul: React.DetailedHTMLProps<React.HTMLAttributes<HTMLUListElement>, HTMLUListElement>ul> <React.JSX.IntrinsicElements.ul: React.DetailedHTMLProps<React.HTMLAttributes<HTMLUListElement>, HTMLUListElement>ul React.RefAttributes<HTMLUListElement>.ref?: React.Ref<HTMLUListElement> | undefined
Allows getting a ref to the component instance. Once the component unmounts, React will set `ref.current` to `null` (or call the ref with `null` if you passed a callback ref).
@see{@link https://react.dev/learn/referencing-values-with-refs#refs-and-the-dom React Docs}
ref
={const doneList: React.RefObject<HTMLUListElement | null>doneList} React.HTMLAttributes<T>.className?: string | undefinedclassName="kanban-column">
{const dones: string[]dones.Array<string>.map<React.JSX.Element>(callbackfn: (value: string, index: number, array: string[]) => React.JSX.Element, thisArg?: any): React.JSX.Element[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
((done: stringdone) => (
<React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li React.HTMLAttributes<T>.className?: string | undefinedclassName="kanban-item" React.Attributes.key?: React.Key | null | undefinedkey={done: stringdone}> <React.JSX.IntrinsicElements.span: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>span React.HTMLAttributes<T>.className?: string | undefinedclassName="kanban-handle"></React.JSX.IntrinsicElements.span: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>span> {done: stringdone} </React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li> ))} </React.JSX.IntrinsicElements.ul: React.DetailedHTMLProps<React.HTMLAttributes<HTMLUListElement>, HTMLUListElement>ul> </React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div> ); }
<script setup lang="ts">
import { function useDragAndDrop<T>(initialValues: T[], options?: Partial<VueParentConfig<T>>): [Ref<HTMLElement | undefined>, Ref<T[]>, (config: Partial<VueParentConfig<T>>) => void]
Creates a new instance of drag and drop and returns the parent element and a ref of the values to use in your template.
@paraminitialValues - The initial values of the parent element.@returnsThe parent element and values for drag and drop.
useDragAndDrop
} from "@formkit/drag-and-drop/vue";
const const todoItems: string[]todoItems = ["Schedule perm", "Rewind VHS tapes", "Make change for the arcade", "Get disposable camera developed", "Learn C++", "Return Nintendo Power Glove"]; const const doneItems: string[]doneItems = ["Pickup new mix-tape from Beth", "Implement drag handles"]; const [const todoList: Ref<HTMLElement | undefined, HTMLElement | undefined>todoList, const todos: Ref<string[], string[]>todos] = useDragAndDrop<string>(initialValues: string[], options?: Partial<Partial<ParentConfig<string>>>): [Ref<HTMLElement | undefined, HTMLElement | undefined>, Ref<string[], string[]>, (config: Partial<Partial<ParentConfig<string>>>) => void]
Creates a new instance of drag and drop and returns the parent element and a ref of the values to use in your template.
@paraminitialValues - The initial values of the parent element.@returnsThe parent element and values for drag and drop.
useDragAndDrop
(const todoItems: string[]todoItems, {
group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "todoList",
dragHandle?: string | undefined
A selector for the drag handle. Will search at any depth within the draggable element.
dragHandle
: ".kanban-handle",
}); const [const doneList: Ref<HTMLElement | undefined, HTMLElement | undefined>doneList, const dones: Ref<string[], string[]>dones] = useDragAndDrop<string>(initialValues: string[], options?: Partial<Partial<ParentConfig<string>>>): [Ref<HTMLElement | undefined, HTMLElement | undefined>, Ref<string[], string[]>, (config: Partial<Partial<ParentConfig<string>>>) => void]
Creates a new instance of drag and drop and returns the parent element and a ref of the values to use in your template.
@paraminitialValues - The initial values of the parent element.@returnsThe parent element and values for drag and drop.
useDragAndDrop
(const doneItems: string[]doneItems, {
group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "todoList",
dragHandle?: string | undefined
A selector for the drag handle. Will search at any depth within the draggable element.
dragHandle
: ".kanban-handle",
}); </script> <template> <div: HTMLAttributes & ReservedPropsdiv HTMLAttributes.class?: ClassValueclass="kanban-board"> <ul: HTMLAttributes & ReservedPropsul ReservedProps.ref?: VNodeRef | undefinedref="todoList: HTMLUListElementtodoList" HTMLAttributes.class?: ClassValueclass="kanban-column"> <li: LiHTMLAttributes & ReservedPropsli v-for="const todo: stringtodo in const todos: Ref<string[], string[]>todos" ReservedProps.key?: PropertyKey | undefined:key="const todo: stringtodo" HTMLAttributes.class?: ClassValueclass="kanban-item"> <span: HTMLAttributes & ReservedPropsspan HTMLAttributes.class?: ClassValueclass="kanban-handle"></span: HTMLAttributes & ReservedPropsspan> {{ const todo: stringtodo }} </li: LiHTMLAttributes & ReservedPropsli> </ul: HTMLAttributes & ReservedPropsul> <ul: HTMLAttributes & ReservedPropsul ReservedProps.ref?: VNodeRef | undefinedref="doneList: HTMLUListElementdoneList" HTMLAttributes.class?: ClassValueclass="kanban-column"> <li: LiHTMLAttributes & ReservedPropsli v-for="const done: stringdone in const dones: Ref<string[], string[]>dones" ReservedProps.key?: PropertyKey | undefined:key="const done: stringdone" HTMLAttributes.class?: ClassValueclass="kanban-item"> <span: HTMLAttributes & ReservedPropsspan HTMLAttributes.class?: ClassValueclass="kanban-handle"></span: HTMLAttributes & ReservedPropsspan> {{ const done: stringdone }} </li: LiHTMLAttributes & ReservedPropsli> </ul: HTMLAttributes & ReservedPropsul> </div: HTMLAttributes & ReservedPropsdiv> </template>
/** @jsxImportSource solid-js */
import { 
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
} from "solid-js";
import { function useDragAndDrop<E extends HTMLElement, T = unknown>(initValues: T[], options?: Partial<ParentConfig<T>>): [Setter<E | null>, Accessor<Store<T[]>>, ReturnType<typeof createStore>[1], (config?: Partial<ParentConfig<T>>) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paraminitValues - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
} from "@formkit/drag-and-drop/solid";
export function function MyComponent(): JSX.ElementMyComponent() { const const todoItems: string[]todoItems = [ "Schedule perm", "Rewind VHS tapes", "Make change for the arcade", "Get disposable camera developed", "Learn C++", "Return Nintendo Power Glove", ]; const const doneItems: string[]doneItems = ["Pickup new mix-tape from Beth", "Implement drag handles"]; const [const todoList: Setter<HTMLUListElement | null>todoList, const todos: Accessor<string[]>todos] = useDragAndDrop<HTMLUListElement, string>(initValues: string[], options?: Partial<ParentConfig<string>>): [Setter<HTMLUListElement | null>, Accessor<string[]>, SetStoreFunction<string[]>, (config?: Partial<ParentConfig<string>> | undefined) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paraminitValues - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
<HTMLUListElement, string>(
const todoItems: string[]todoItems, { group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "todoList",
dragHandle?: string | undefined
A selector for the drag handle. Will search at any depth within the draggable element.
dragHandle
: ".kanban-handle",
} ); const [const doneList: Setter<HTMLUListElement | null>doneList, const dones: Accessor<string[]>dones] = useDragAndDrop<HTMLUListElement, string>(initValues: string[], options?: Partial<ParentConfig<string>>): [Setter<HTMLUListElement | null>, Accessor<string[]>, SetStoreFunction<string[]>, (config?: Partial<ParentConfig<string>> | undefined) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paraminitValues - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
<HTMLUListElement, string>(
const doneItems: string[]doneItems, { group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "todoList",
dragHandle?: string | undefined
A selector for the drag handle. Will search at any depth within the draggable element.
dragHandle
: ".kanban-handle",
} ); return ( <JSX.HTMLElementTags.div: JSX.HTMLAttributes<HTMLDivElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/div@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLDivElement
div
JSX.DOMAttributes<HTMLDivElement>.class?: string | undefinedclass="kanban-board">
<JSX.HTMLElementTags.ul: JSX.HTMLAttributes<HTMLUListElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLUListElement
ul
ref?: HTMLUListElement | ((el: HTMLUListElement) => void) | undefinedref={const todoList: Setter<HTMLUListElement | null>todoList} JSX.DOMAttributes<T>.class?: string | undefinedclass="kanban-column">
<
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
each: false | string[] | null | undefinedeach={const todos: () => string[]todos()}>
{(todo: stringtodo) => ( <JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
JSX.DOMAttributes<T>.class?: string | undefinedclass="kanban-item">
<JSX.HTMLElementTags.span: JSX.HTMLAttributes<HTMLSpanElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/span@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLSpanElement
span
JSX.DOMAttributes<T>.class?: string | undefinedclass="kanban-handle"></JSX.HTMLElementTags.span: JSX.HTMLAttributes<HTMLSpanElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/span@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLSpanElement
span
>
{todo: stringtodo} </JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
>
)} </
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
>
</JSX.HTMLElementTags.ul: JSX.HTMLAttributes<HTMLUListElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLUListElement
ul
>
<JSX.HTMLElementTags.ul: JSX.HTMLAttributes<HTMLUListElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLUListElement
ul
ref?: HTMLUListElement | ((el: HTMLUListElement) => void) | undefinedref={const doneList: Setter<HTMLUListElement | null>doneList} JSX.DOMAttributes<T>.class?: string | undefinedclass="kanban-column">
<
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
each: false | string[] | null | undefinedeach={const dones: () => string[]dones()}>
{(done: stringdone) => ( <JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
JSX.DOMAttributes<T>.class?: string | undefinedclass="kanban-item">
<JSX.HTMLElementTags.span: JSX.HTMLAttributes<HTMLSpanElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/span@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLSpanElement
span
JSX.DOMAttributes<T>.class?: string | undefinedclass="kanban-handle"></JSX.HTMLElementTags.span: JSX.HTMLAttributes<HTMLSpanElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/span@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLSpanElement
span
>
{done: stringdone} </JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
>
)} </
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
>
</JSX.HTMLElementTags.ul: JSX.HTMLAttributes<HTMLUListElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLUListElement
ul
>
</JSX.HTMLElementTags.div: JSX.HTMLAttributes<HTMLDivElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/div@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLDivElement
div
>
); }
import { function reactive<T>(effect: () => T): Computed<T> (+1 overload)
A reactive object is a proxy of the original object that allows for reactive dependency watching. It is created by calling `reactive()` and should be used to store reactive data in your app and components.
@paramdata - The data to make reactive, typically a plain object.@returnsA reactive proxy of the original data.
reactive
, function html(strings: TemplateStringsArray | string[], ...expSlots: ArrowExpression[]): ArrowTemplatehtml } from "@arrow-js/core";
import { function dragAndDrop<T>({ parent, getValues, setValues, config, }: DragAndDrop<T>): void
Initializes the drag and drop functionality for a given parent.
@paramdragAndDrop - The drag and drop configuration.@returnsvoid
dragAndDrop
} from "@formkit/drag-and-drop";
const
const state: Reactive<{
    todos: string[];
    dones: string[];
}>
state
=
reactive<{
    todos: string[];
    dones: string[];
}>(data: {
    todos: string[];
    dones: string[];
}): Reactive<{
    todos: string[];
    dones: string[];
}> (+1 overload)
A reactive object is a proxy of the original object that allows for reactive dependency watching. It is created by calling `reactive()` and should be used to store reactive data in your app and components.
@paramdata - The data to make reactive, typically a plain object.@returnsA reactive proxy of the original data.
reactive
({
todos: string[]todos: [ "Schedule perm", "Rewind VHS tapes", "Make change for the arcade", "Get disposable camera developed", "Learn C++", "Return Nintendo Power Glove", ], dones: string[]dones: ["Pickup new mix-tape from Beth", "Implement drag handles"], }); dragAndDrop<string>({ parent, getValues, setValues, config, }: DragAndDrop<string>): void
Initializes the drag and drop functionality for a given parent.
@paramdragAndDrop - The drag and drop configuration.@returnsvoid
dragAndDrop
<string>({
DragAndDrop<string>.parent: HTMLElement
The parent element that will contain the draggable nodes.
parent
: var document: Document
**`window.document`** returns a reference to the document contained in the window. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)
document
.Document.getElementById(elementId: string): HTMLElement | null
The **`getElementById()`** method of the Document interface returns an Element object representing the element whose id property matches the specified string. Since element IDs are required to be unique if specified, they're a useful way to get access to a specific element quickly.
getElementById
("todo-list")!,
DragAndDrop<string>.getValues: (parent: HTMLElement) => string[]
A function that returns the values assigned to the parent.
getValues
: () =>
const state: Reactive<{
    todos: string[];
    dones: string[];
}>
state
.todos: string[] | Reactive<string[]>todos,
DragAndDrop<string>.setValues: (values: string[], parent: HTMLElement) => void
A function that sets the values assigned to the parent.
setValues
: (newValues: string[]newValues) => {
const state: Reactive<{
    todos: string[];
    dones: string[];
}>
state
.todos: string[] | Reactive<string[]>todos = reactive<string[]>(data: string[]): Reactive<string[]> (+1 overload)
A reactive object is a proxy of the original object that allows for reactive dependency watching. It is created by calling `reactive()` and should be used to store reactive data in your app and components.
@paramdata - The data to make reactive, typically a plain object.@returnsA reactive proxy of the original data.
reactive
(newValues: string[]newValues);
}, DragAndDrop<string>.config?: Partial<ParentConfig<string>> | undefined
An optional configuration object.
config
: {
group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "todoList",
dragHandle?: string | undefined
A selector for the drag handle. Will search at any depth within the draggable element.
dragHandle
: ".kanban-handle",
}, }); dragAndDrop<string>({ parent, getValues, setValues, config, }: DragAndDrop<string>): void
Initializes the drag and drop functionality for a given parent.
@paramdragAndDrop - The drag and drop configuration.@returnsvoid
dragAndDrop
<string>({
DragAndDrop<string>.parent: HTMLElement
The parent element that will contain the draggable nodes.
parent
: var document: Document
**`window.document`** returns a reference to the document contained in the window. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)
document
.Document.getElementById(elementId: string): HTMLElement | null
The **`getElementById()`** method of the Document interface returns an Element object representing the element whose id property matches the specified string. Since element IDs are required to be unique if specified, they're a useful way to get access to a specific element quickly.
getElementById
("done-list")!,
DragAndDrop<string>.getValues: (parent: HTMLElement) => string[]
A function that returns the values assigned to the parent.
getValues
: () =>
const state: Reactive<{
    todos: string[];
    dones: string[];
}>
state
.dones: string[] | Reactive<string[]>dones,
DragAndDrop<string>.setValues: (values: string[], parent: HTMLElement) => void
A function that sets the values assigned to the parent.
setValues
: (newValues: string[]newValues) => {
const state: Reactive<{
    todos: string[];
    dones: string[];
}>
state
.dones: string[] | Reactive<string[]>dones = reactive<string[]>(data: string[]): Reactive<string[]> (+1 overload)
A reactive object is a proxy of the original object that allows for reactive dependency watching. It is created by calling `reactive()` and should be used to store reactive data in your app and components.
@paramdata - The data to make reactive, typically a plain object.@returnsA reactive proxy of the original data.
reactive
(newValues: string[]newValues);
}, DragAndDrop<string>.config?: Partial<ParentConfig<string>> | undefined
An optional configuration object.
config
: {
group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "todoList",
dragHandle?: string | undefined
A selector for the drag handle. Will search at any depth within the draggable element.
dragHandle
: ".kanban-handle",
}, }); function html(strings: TemplateStringsArray | string[], ...expSlots: ArrowExpression[]): ArrowTemplatehtml` <div class="kanban-board"> <ul class="kanban-column" id="todo-list"> ${() =>
const state: Reactive<{
    todos: string[];
    dones: string[];
}>
state
.todos: string[] | Reactive<string[]>todos.Array<T>.map<ArrowTemplate>(callbackfn: (value: string, index: number, array: string[]) => ArrowTemplate, thisArg?: any): ArrowTemplate[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
((todo: stringtodo) =>
function html(strings: TemplateStringsArray | string[], ...expSlots: ArrowExpression[]): ArrowTemplatehtml` <li class="kanban-item"> <span class="kanban-handle"></span> ${todo: stringtodo} </li> `.ArrowTemplate.key: (key: ArrowTemplateKey) => ArrowTemplatekey(todo: stringtodo) )} </ul> <ul class="kanban-column" id="done-list"> ${
const state: Reactive<{
    todos: string[];
    dones: string[];
}>
state
.dones: string[] | Reactive<string[]>dones.Array<T>.map<ArrowTemplate>(callbackfn: (value: string, index: number, array: string[]) => ArrowTemplate, thisArg?: any): ArrowTemplate[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
((done: stringdone) =>
function html(strings: TemplateStringsArray | string[], ...expSlots: ArrowExpression[]): ArrowTemplatehtml` <li class="kanban-item"> <span class="kanban-handle"></span> ${done: stringdone} </li> `.ArrowTemplate.key: (key: ArrowTemplateKey) => ArrowTemplatekey(done: stringdone) )} </ul> </div> `(var document: Document
**`window.document`** returns a reference to the document contained in the window. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)
document
.Document.getElementById(elementId: string): HTMLElement | null
The **`getElementById()`** method of the Document interface returns an Element object representing the element whose id property matches the specified string. Since element IDs are required to be unique if specified, they're a useful way to get access to a specific element quickly.
getElementById
("app")!);
static const todoItems = ["Schedule perm", "Rewind VHS tapes", "Make change for the arcade", "Get disposable camera developed", "Learn C++", "Return Nintendo Power Glove"];
static const doneItems = ["Pickup new mix-tape from Beth", "Implement drag handles"];
static const config = { group: "todoList", dragHandle: ".kanban-handle" };

<let/todos=todoItems>
<let/dones=doneItems>

<div class="kanban-board">
  <ul/todoList class="kanban-column">
    <for|todo| of=todos by=(t => t)>
      <li class="kanban-item">
        <span class="kanban-handle"/>
        ${todo}
      </li>
    </for>
  </ul>
  <ul/doneList class="kanban-column">
    <for|done| of=dones by=(t => t)>
      <li class="kanban-item">
        <span class="kanban-handle"/>
        ${done}
      </li>
    </for>
  </ul>
</div>

<dnd:=todos parent=todoList config=config/>
<dnd:=dones parent=doneList config=config/>

Updating Config

The parent's configuration can be updated idempotently during runtime by using the updateConfig method. In the example below, clicking the button will toggle whether drag and drop is enabled for the parent.

  • React
  • Vue
  • Solid
  • Native
  • Marko
import React from "react";
import { function useState<S>(initialState: S | (() => S)): [S, React.Dispatch<React.SetStateAction<S>>] (+1 overload)
Returns a stateful value, and a function to update it.
@version16.8.0@see{@link https://react.dev/reference/react/useState}
useState
} from "react";
import { function useDragAndDrop<E extends HTMLElement, T = unknown>(list: T[], options?: Partial<ParentConfig<T>>): [React.RefObject<E | null>, T[], React.Dispatch<React.SetStateAction<T[]>>, (config: Partial<ParentConfig<T>>) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paramlist - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
} from "@formkit/drag-and-drop/react";
export function function myComponent(): React.JSX.ElementmyComponent() { const [const parent: React.RefObject<HTMLUListElement | null>parent, const values: string[]values, const _setValues: React.Dispatch<React.SetStateAction<string[]>>_setValues, const updateConfig: (config: Partial<ParentConfig<string>>) => voidupdateConfig] = useDragAndDrop<HTMLUListElement, string>(list: string[], options?: Partial<ParentConfig<string>>): [React.RefObject<HTMLUListElement | null>, string[], React.Dispatch<React.SetStateAction<string[]>>, (config: Partial<ParentConfig<string>>) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paramlist - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
<
HTMLUListElement, string >([ "Depeche Mode", "Duran Duran", "Pet Shop Boys", "Kraftwerk", "Tears for Fears", "Spandau Ballet", ]); const [const disabled: booleandisabled, const setDisabled: React.Dispatch<React.SetStateAction<boolean>>setDisabled] = useState<boolean>(initialState: boolean | (() => boolean)): [boolean, React.Dispatch<React.SetStateAction<boolean>>] (+1 overload)
Returns a stateful value, and a function to update it.
@version16.8.0@see{@link https://react.dev/reference/react/useState}
useState
(false);
const const toggleDisabled: () => voidtoggleDisabled = () => { const setDisabled: (value: React.SetStateAction<boolean>) => voidsetDisabled(!const disabled: booleandisabled); const updateConfig: (config: Partial<ParentConfig<string>>) => voidupdateConfig({ disabled?: boolean | undefined
A flag to disable dragability of all nodes in the parent.
disabled
: !const disabled: booleandisabled });
}; return ( <React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div> <React.JSX.IntrinsicElements.ul: React.DetailedHTMLProps<React.HTMLAttributes<HTMLUListElement>, HTMLUListElement>ul React.RefAttributes<HTMLUListElement>.ref?: React.Ref<HTMLUListElement> | undefined
Allows getting a ref to the component instance. Once the component unmounts, React will set `ref.current` to `null` (or call the ref with `null` if you passed a callback ref).
@see{@link https://react.dev/learn/referencing-values-with-refs#refs-and-the-dom React Docs}
ref
={const parent: React.RefObject<HTMLUListElement | null>parent}>
{const values: string[]values.Array<string>.map<React.JSX.Element>(callbackfn: (value: string, index: number, array: string[]) => React.JSX.Element, thisArg?: any): React.JSX.Element[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
((tape: stringtape) => (
<React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li React.HTMLAttributes<HTMLLIElement>.className?: string | undefinedclassName="cassette" data-label: stringdata-label={tape: stringtape} React.Attributes.key?: React.Key | null | undefinedkey={tape: stringtape}> {tape: stringtape} </React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li> ))} </React.JSX.IntrinsicElements.ul: React.DetailedHTMLProps<React.HTMLAttributes<HTMLUListElement>, HTMLUListElement>ul> <React.JSX.IntrinsicElements.button: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>button React.DOMAttributes<HTMLButtonElement>.onClick?: React.MouseEventHandler<HTMLButtonElement> | undefinedonClick={const toggleDisabled: () => voidtoggleDisabled}> {const disabled: booleandisabled ? "Enable" : "Disable"} drag and drop </React.JSX.IntrinsicElements.button: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>button> </React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div> ); }
<script setup lang="ts">
import { function useDragAndDrop<T>(initialValues: T[], options?: Partial<VueParentConfig<T>>): [Ref<HTMLElement | undefined>, Ref<T[]>, (config: Partial<VueParentConfig<T>>) => void]
Creates a new instance of drag and drop and returns the parent element and a ref of the values to use in your template.
@paraminitialValues - The initial values of the parent element.@returnsThe parent element and values for drag and drop.
useDragAndDrop
} from "@formkit/drag-and-drop/vue";
import { function ref<T>(value: T): [T] extends [Ref] ? IfAny<T, Ref<T>, T> : Ref<UnwrapRef<T>, UnwrapRef<T> | T> (+1 overload)
Takes an inner value and returns a reactive and mutable ref object, which has a single property `.value` that points to the inner value.
@paramvalue - The object to wrap in the ref.@see{@link https://vuejs.org/api/reactivity-core.html#ref}
ref
} from "vue";
const const disabled: Ref<boolean, boolean>disabled = ref<boolean>(value: boolean): Ref<boolean, boolean> (+1 overload)
Takes an inner value and returns a reactive and mutable ref object, which has a single property `.value` that points to the inner value.
@paramvalue - The object to wrap in the ref.@see{@link https://vuejs.org/api/reactivity-core.html#ref}
ref
(false);
const [const parentRef: Ref<HTMLElement | undefined, HTMLElement | undefined>parentRef, const values: Ref<string[], string[]>values, const updateConfig: (config: Partial<Partial<ParentConfig<string>>>) => voidupdateConfig] = useDragAndDrop<string>(initialValues: string[], options?: Partial<Partial<ParentConfig<string>>>): [Ref<HTMLElement | undefined, HTMLElement | undefined>, Ref<string[], string[]>, (config: Partial<Partial<ParentConfig<string>>>) => void]
Creates a new instance of drag and drop and returns the parent element and a ref of the values to use in your template.
@paraminitialValues - The initial values of the parent element.@returnsThe parent element and values for drag and drop.
useDragAndDrop
([
"Depeche Mode", "Duran Duran", "Pet", "Kraftwerk", "Tears for Fears", "Spandau Ballet", ]); function function toggleDisabled(): voidtoggleDisabled() { const disabled: Ref<boolean, boolean>disabled.Ref<boolean, boolean>.value: booleanvalue = !const disabled: Ref<boolean, boolean>disabled.Ref<boolean, boolean>.value: booleanvalue; const updateConfig: (config: Partial<Partial<ParentConfig<string>>>) => voidupdateConfig({ disabled?: boolean | undefined
A flag to disable dragability of all nodes in the parent.
disabled
: const disabled: Ref<boolean, boolean>disabled.Ref<boolean, boolean>.value: booleanvalue });
} </script> <template> <ul: HTMLAttributes & ReservedPropsul ReservedProps.ref?: VNodeRef | undefinedref="parentRef: HTMLUListElementparentRef"> <li: LiHTMLAttributes & ReservedPropsli v-for="const tape: stringtape in const values: Ref<string[], string[]>values" ReservedProps.key?: PropertyKey | undefined:key="const tape: stringtape" HTMLAttributes.class?: ClassValueclass="cassette"> {{ const tape: stringtape }} </li: LiHTMLAttributes & ReservedPropsli> </ul: HTMLAttributes & ReservedPropsul> <button: ButtonHTMLAttributes & ReservedPropsbutton HTMLAttributes.id?: string | undefinedid="no-drag" @onClick?: ((payload: PointerEvent) => void) | undefinedclick="function toggleDisabled(): voidtoggleDisabled"> {{ const disabled: Ref<boolean, boolean>disabled ? "Enable" : "Disable" }} drag and drop </button: ButtonHTMLAttributes & ReservedPropsbutton> </template>
/** @jsxImportSource solid-js */
import { function createSignal<T>(): Signal<T | undefined> (+1 overload)
Creates a simple reactive state with a getter and setter ```typescript const [state: Accessor<T>, setState: Setter<T>] = createSignal<T>( value: T, options?: { name?: string, equals?: false | ((prev: T, next: T) => boolean) } ) ```
@paramvalue initial value of the state; if empty, the state's type will automatically extended with undefined; otherwise you need to extend the type manually if you want setting to undefined not be an error@paramoptions optional object with a name for debugging purposes and equals, a comparator function for the previous and next value to allow fine-grained control over the reactivity@returns```typescript [state: Accessor<T>, setState: Setter<T>] ``` * the Accessor is merely a function that returns the current value and registers each call to the reactive root * the Setter is a function that allows directly setting or mutating the value: ```typescript const [count, setCount] = createSignal(0); setCount(count => count + 1); ```@descriptionhttps://docs.solidjs.com/reference/basic-reactivity/create-signal
createSignal
} from "solid-js";
import {
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
} from "solid-js";
import { function useDragAndDrop<E extends HTMLElement, T = unknown>(initValues: T[], options?: Partial<ParentConfig<T>>): [Setter<E | null>, Accessor<Store<T[]>>, ReturnType<typeof createStore>[1], (config?: Partial<ParentConfig<T>>) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paraminitValues - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
} from "@formkit/drag-and-drop/solid";
export function function MyComponent(): JSX.ElementMyComponent() { const [const parent: Setter<HTMLUListElement | null>parent, const values: Accessor<string[]>values, , const updateConfig: (config?: Partial<ParentConfig<string>> | undefined) => voidupdateConfig] = useDragAndDrop<HTMLUListElement, string>(initValues: string[], options?: Partial<ParentConfig<string>>): [Setter<HTMLUListElement | null>, Accessor<string[]>, SetStoreFunction<string[]>, (config?: Partial<ParentConfig<string>> | undefined) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paraminitValues - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
<
HTMLUListElement, string >([ "Depeche Mode", "Duran Duran", "Pet Shop Boys", "Kraftwerk", "Tears for Fears", "Spandau Ballet", ]); const [const disabled: Accessor<boolean>disabled, const setDisabled: Setter<boolean>setDisabled] = createSignal<boolean>(value: boolean, options?: SignalOptions<boolean> | undefined): Signal<boolean> (+1 overload)
Creates a simple reactive state with a getter and setter ```typescript const [state: Accessor<T>, setState: Setter<T>] = createSignal<T>( value: T, options?: { name?: string, equals?: false | ((prev: T, next: T) => boolean) } ) ```
@paramvalue initial value of the state; if empty, the state's type will automatically extended with undefined; otherwise you need to extend the type manually if you want setting to undefined not be an error@paramoptions optional object with a name for debugging purposes and equals, a comparator function for the previous and next value to allow fine-grained control over the reactivity@returns```typescript [state: Accessor<T>, setState: Setter<T>] ``` * the Accessor is merely a function that returns the current value and registers each call to the reactive root * the Setter is a function that allows directly setting or mutating the value: ```typescript const [count, setCount] = createSignal(0); setCount(count => count + 1); ```@descriptionhttps://docs.solidjs.com/reference/basic-reactivity/create-signal
createSignal
(false);
const const toggleDisabled: () => voidtoggleDisabled = () => { const setDisabled: <boolean>(value: boolean | ((prev: boolean) => boolean)) => boolean (+3 overloads)setDisabled(!const disabled: () => booleandisabled()); const updateConfig: (config?: Partial<ParentConfig<string>> | undefined) => voidupdateConfig({ disabled?: boolean | undefined
A flag to disable dragability of all nodes in the parent.
disabled
: !const disabled: () => booleandisabled() });
}; return ( <JSX.HTMLElementTags.div: JSX.HTMLAttributes<HTMLDivElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/div@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLDivElement
div
>
<JSX.HTMLElementTags.ul: JSX.HTMLAttributes<HTMLUListElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLUListElement
ul
ref?: HTMLUListElement | ((el: HTMLUListElement) => void) | undefinedref={const parent: Setter<HTMLUListElement | null>parent}>
<
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
each: false | string[] | null | undefinedeach={const values: () => string[]values()}>
{(tape: stringtape) => ( <JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
JSX.DOMAttributes<HTMLLIElement>.class?: string | undefinedclass="cassette" data-label: stringdata-label={tape: stringtape}>
{tape: stringtape} </JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
>
)} </
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
>
</JSX.HTMLElementTags.ul: JSX.HTMLAttributes<HTMLUListElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLUListElement
ul
>
<JSX.HTMLElementTags.button: JSX.ButtonHTMLAttributes<HTMLButtonElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/button@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLButtonElement
button
JSX.CustomEventHandlersCamelCase<HTMLButtonElement>.onClick?: JSX.EventHandlerUnion<HTMLButtonElement, MouseEvent, JSX.EventHandler<HTMLButtonElement, MouseEvent>> | undefinedonClick={const toggleDisabled: () => voidtoggleDisabled}>
{const disabled: () => booleandisabled() ? "Enable" : "Disable"} drag and drop </JSX.HTMLElementTags.button: JSX.ButtonHTMLAttributes<HTMLButtonElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/button@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLButtonElement
button
>
</JSX.HTMLElementTags.div: JSX.HTMLAttributes<HTMLDivElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/div@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLDivElement
div
>
); }
import { function reactive<T>(effect: () => T): Computed<T> (+1 overload)
A reactive object is a proxy of the original object that allows for reactive dependency watching. It is created by calling `reactive()` and should be used to store reactive data in your app and components.
@paramdata - The data to make reactive, typically a plain object.@returnsA reactive proxy of the original data.
reactive
, function html(strings: TemplateStringsArray | string[], ...expSlots: ArrowExpression[]): ArrowTemplatehtml } from "@arrow-js/core";
import { function dragAndDrop<T>({ parent, getValues, setValues, config, }: DragAndDrop<T>): void
Initializes the drag and drop functionality for a given parent.
@paramdragAndDrop - The drag and drop configuration.@returnsvoid
dragAndDrop
, function updateConfig<T>(parent: HTMLElement, config: Partial<ParentConfig<T>>): void
Utility function to update parent config.
@paramparent - The parent element.@paramconfig - The config to update.@returnsvoid
updateConfig
} from "@formkit/drag-and-drop";
const
const state: Reactive<{
    tapes: string[];
    disabled: boolean;
}>
state
=
reactive<{
    tapes: string[];
    disabled: boolean;
}>(data: {
    tapes: string[];
    disabled: boolean;
}): Reactive<{
    tapes: string[];
    disabled: boolean;
}> (+1 overload)
A reactive object is a proxy of the original object that allows for reactive dependency watching. It is created by calling `reactive()` and should be used to store reactive data in your app and components.
@paramdata - The data to make reactive, typically a plain object.@returnsA reactive proxy of the original data.
reactive
({
tapes: string[]tapes: [ "Depeche Mode", "Duran Duran", "Pet Shop Boys", "Kraftwerk", "Tears for Fears", "Spandau Ballet", ], disabled: booleandisabled: false, }); function function toggleDisabled(): voidtoggleDisabled() {
const state: Reactive<{
    tapes: string[];
    disabled: boolean;
}>
state
.disabled: booleandisabled = !
const state: Reactive<{
    tapes: string[];
    disabled: boolean;
}>
state
.disabled: booleandisabled;
updateConfig<unknown>(parent: HTMLElement, config: Partial<ParentConfig<unknown>>): void
Utility function to update parent config.
@paramparent - The parent element.@paramconfig - The config to update.@returnsvoid
updateConfig
(var document: Document
**`window.document`** returns a reference to the document contained in the window. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)
document
.Document.getElementById(elementId: string): HTMLElement | null
The **`getElementById()`** method of the Document interface returns an Element object representing the element whose id property matches the specified string. Since element IDs are required to be unique if specified, they're a useful way to get access to a specific element quickly.
getElementById
("cassettes")!, {
disabled?: boolean | undefined
A flag to disable dragability of all nodes in the parent.
disabled
: !
const state: Reactive<{
    tapes: string[];
    disabled: boolean;
}>
state
.disabled: booleandisabled,
}); } function html(strings: TemplateStringsArray | string[], ...expSlots: ArrowExpression[]): ArrowTemplatehtml` <ul id="cassettes"> ${
const state: Reactive<{
    tapes: string[];
    disabled: boolean;
}>
state
.tapes: string[] | Reactive<string[]>tapes.Array<T>.map<ArrowTemplate>(callbackfn: (value: string, index: number, array: string[]) => ArrowTemplate, thisArg?: any): ArrowTemplate[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
((tape: stringtape) =>
function html(strings: TemplateStringsArray | string[], ...expSlots: ArrowExpression[]): ArrowTemplatehtml`<li class="cassette" data-label="${tape: stringtape}">${tape: stringtape}</li>`.ArrowTemplate.key: (key: ArrowTemplateKey) => ArrowTemplatekey(tape: stringtape) )} </ul> <button onclick=${function toggleDisabled(): voidtoggleDisabled}>Toggle Disabled</button> `(var document: Document
**`window.document`** returns a reference to the document contained in the window. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)
document
.Document.getElementById(elementId: string): HTMLElement | null
The **`getElementById()`** method of the Document interface returns an Element object representing the element whose id property matches the specified string. Since element IDs are required to be unique if specified, they're a useful way to get access to a specific element quickly.
getElementById
("app")!);
dragAndDrop<string>({ parent, getValues, setValues, config, }: DragAndDrop<string>): void
Initializes the drag and drop functionality for a given parent.
@paramdragAndDrop - The drag and drop configuration.@returnsvoid
dragAndDrop
<string>({
DragAndDrop<string>.parent: HTMLElement
The parent element that will contain the draggable nodes.
parent
: var document: Document
**`window.document`** returns a reference to the document contained in the window. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)
document
.Document.getElementById(elementId: string): HTMLElement | null
The **`getElementById()`** method of the Document interface returns an Element object representing the element whose id property matches the specified string. Since element IDs are required to be unique if specified, they're a useful way to get access to a specific element quickly.
getElementById
("cassettes")!,
DragAndDrop<string>.getValues: (parent: HTMLElement) => string[]
A function that returns the values assigned to the parent.
getValues
: () =>
const state: Reactive<{
    tapes: string[];
    disabled: boolean;
}>
state
.tapes: string[] | Reactive<string[]>tapes,
DragAndDrop<string>.setValues: (values: string[], parent: HTMLElement) => void
A function that sets the values assigned to the parent.
setValues
: (newValues: string[]newValues) => {
const state: Reactive<{
    tapes: string[];
    disabled: boolean;
}>
state
.tapes: string[] | Reactive<string[]>tapes = reactive<string[]>(data: string[]): Reactive<string[]> (+1 overload)
A reactive object is a proxy of the original object that allows for reactive dependency watching. It is created by calling `reactive()` and should be used to store reactive data in your app and components.
@paramdata - The data to make reactive, typically a plain object.@returnsA reactive proxy of the original data.
reactive
(newValues: string[]newValues);
}, });
<let/tapes=[
  "Depeche Mode",
  "Duran Duran",
  "Pet",
  "Kraftwerk",
  "Tears for Fears",
  "Spandau Ballet",
]>
<let/disabled=false>
<let/config={}>

<ul/parent>
  <for|tape| of=tapes by=(t => t)>
    <li class="cassette">${tape}</li>
  </for>
</ul>

<dnd:=tapes parent=parent config=config/>

<button
  id="no-drag"
  onClick() {
    disabled = !disabled;
    config = { disabled };
  }
>
  ${disabled ? "Enable" : "Disable"} drag and drop
</button>

Multi Drag

Multi drag allows users to select multiple items and drag them all at once. To enable multi drag, set the multiDrag property to true in the configuration.

  • React
  • Vue
  • Solid
  • Native
  • Marko
import React from "react";
import { function useDragAndDrop<E extends HTMLElement, T = unknown>(list: T[], options?: Partial<ParentConfig<T>>): [React.RefObject<E | null>, T[], React.Dispatch<React.SetStateAction<T[]>>, (config: Partial<ParentConfig<T>>) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paramlist - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
} from "@formkit/drag-and-drop/react";
export function function myComponent(): React.JSX.ElementmyComponent() { const const mockFileNames: string[]mockFileNames = [ "dungeon_master.exe", "map_1.dat", "map_2.dat", "character1.txt", "character2.txt", "shell32.dll", "README.txt", ]; const [const parent1: React.RefObject<HTMLUListElement | null>parent1, const files1: string[]files1] = useDragAndDrop<HTMLUListElement, string>(list: string[], options?: Partial<ParentConfig<string>>): [React.RefObject<HTMLUListElement | null>, string[], React.Dispatch<React.SetStateAction<string[]>>, (config: Partial<ParentConfig<string>>) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paramlist - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
<HTMLUListElement, string>(
const mockFileNames: string[]mockFileNames, { group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "A",
multiDrag?: boolean | undefinedmultiDrag: true, selectedClass?: string | undefined
The class to add to a node when it is selected (clicked or pressed).
selectedClass
: "bg-blue-500 text-white",
} ); const [const parent2: React.RefObject<HTMLUListElement | null>parent2, const files2: string[]files2] = useDragAndDrop<HTMLUListElement, string>(list: string[], options?: Partial<ParentConfig<string>>): [React.RefObject<HTMLUListElement | null>, string[], React.Dispatch<React.SetStateAction<string[]>>, (config: Partial<ParentConfig<string>>) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paramlist - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
<HTMLUListElement, string>([], {
group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "A",
multiDrag?: boolean | undefinedmultiDrag: true, selectedClass?: string | undefined
The class to add to a node when it is selected (clicked or pressed).
selectedClass
: "bg-blue-500 text-white",
}); return ( <React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div React.HTMLAttributes<HTMLDivElement>.className?: string | undefinedclassName="file-manager"> <React.JSX.IntrinsicElements.ul: React.DetailedHTMLProps<React.HTMLAttributes<HTMLUListElement>, HTMLUListElement>ul React.RefAttributes<HTMLUListElement>.ref?: React.Ref<HTMLUListElement> | undefined
Allows getting a ref to the component instance. Once the component unmounts, React will set `ref.current` to `null` (or call the ref with `null` if you passed a callback ref).
@see{@link https://react.dev/learn/referencing-values-with-refs#refs-and-the-dom React Docs}
ref
={const parent1: React.RefObject<HTMLUListElement | null>parent1} React.HTMLAttributes<T>.className?: string | undefinedclassName="file-list">
{const files1: string[]files1.Array<string>.map<React.JSX.Element>(callbackfn: (value: string, index: number, array: string[]) => React.JSX.Element, thisArg?: any): React.JSX.Element[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
((file: stringfile) => (
<React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li React.Attributes.key?: React.Key | null | undefinedkey={file: stringfile} React.HTMLAttributes<T>.className?: string | undefinedclassName="file"> {file: stringfile} </React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li> ))} </React.JSX.IntrinsicElements.ul: React.DetailedHTMLProps<React.HTMLAttributes<HTMLUListElement>, HTMLUListElement>ul> <React.JSX.IntrinsicElements.ul: React.DetailedHTMLProps<React.HTMLAttributes<HTMLUListElement>, HTMLUListElement>ul React.RefAttributes<HTMLUListElement>.ref?: React.Ref<HTMLUListElement> | undefined
Allows getting a ref to the component instance. Once the component unmounts, React will set `ref.current` to `null` (or call the ref with `null` if you passed a callback ref).
@see{@link https://react.dev/learn/referencing-values-with-refs#refs-and-the-dom React Docs}
ref
={const parent2: React.RefObject<HTMLUListElement | null>parent2} React.HTMLAttributes<T>.className?: string | undefinedclassName="file-list">
{const files2: string[]files2.Array<string>.map<React.JSX.Element>(callbackfn: (value: string, index: number, array: string[]) => React.JSX.Element, thisArg?: any): React.JSX.Element[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
((file: stringfile) => (
<React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li React.Attributes.key?: React.Key | null | undefinedkey={file: stringfile} React.HTMLAttributes<T>.className?: string | undefinedclassName="file"> {file: stringfile} </React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li> ))} </React.JSX.IntrinsicElements.ul: React.DetailedHTMLProps<React.HTMLAttributes<HTMLUListElement>, HTMLUListElement>ul> </React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div> ); }
<script setup lang="ts">
import { function useDragAndDrop<T>(initialValues: T[], options?: Partial<VueParentConfig<T>>): [Ref<HTMLElement | undefined>, Ref<T[]>, (config: Partial<VueParentConfig<T>>) => void]
Creates a new instance of drag and drop and returns the parent element and a ref of the values to use in your template.
@paraminitialValues - The initial values of the parent element.@returnsThe parent element and values for drag and drop.
useDragAndDrop
} from "@formkit/drag-and-drop/vue";
const const mockFileNames: string[]mockFileNames = [ "dungeon_master.exe", "map_1.dat", "map_2.dat", "character1.txt", "character2.txt", "shell32.dll", "README.txt", ]; const [const parent1: Ref<HTMLElement | undefined, HTMLElement | undefined>parent1, const files1: Ref<string[], string[]>files1] = useDragAndDrop<string>(initialValues: string[], options?: Partial<Partial<ParentConfig<string>>>): [Ref<HTMLElement | undefined, HTMLElement | undefined>, Ref<string[], string[]>, (config: Partial<Partial<ParentConfig<string>>>) => void]
Creates a new instance of drag and drop and returns the parent element and a ref of the values to use in your template.
@paraminitialValues - The initial values of the parent element.@returnsThe parent element and values for drag and drop.
useDragAndDrop
(const mockFileNames: string[]mockFileNames, {
group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "A",
multiDrag?: boolean | undefinedmultiDrag: true, selectedClass?: string | undefined
The class to add to a node when it is selected (clicked or pressed).
selectedClass
: "bg-blue-500 text-white",
}); const [const parent2: Ref<HTMLElement | undefined, HTMLElement | undefined>parent2, const files2: Ref<never[], never[]>files2] = useDragAndDrop<never>(initialValues: never[], options?: Partial<Partial<ParentConfig<never>>>): [Ref<HTMLElement | undefined, HTMLElement | undefined>, Ref<never[], never[]>, (config: Partial<Partial<ParentConfig<never>>>) => void]
Creates a new instance of drag and drop and returns the parent element and a ref of the values to use in your template.
@paraminitialValues - The initial values of the parent element.@returnsThe parent element and values for drag and drop.
useDragAndDrop
([], {
group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "A",
multiDrag?: boolean | undefinedmultiDrag: true, selectedClass?: string | undefined
The class to add to a node when it is selected (clicked or pressed).
selectedClass
: "bg-blue-500 text-white",
}); </script> <template> <div: HTMLAttributes & ReservedPropsdiv HTMLAttributes.class?: ClassValueclass="file-manager"> <ul: HTMLAttributes & ReservedPropsul ReservedProps.ref?: VNodeRef | undefinedref="parent1: HTMLUListElementparent1" HTMLAttributes.class?: ClassValueclass="file-list"> <li: LiHTMLAttributes & ReservedPropsli v-for="const item: stringitem in const files1: Ref<string[], string[]>files1" ReservedProps.key?: PropertyKey | undefined:key="const item: stringitem" HTMLAttributes.class?: ClassValueclass="file"> {{ const item: stringitem }} </li: LiHTMLAttributes & ReservedPropsli> </ul: HTMLAttributes & ReservedPropsul> <ul: HTMLAttributes & ReservedPropsul ReservedProps.ref?: VNodeRef | undefinedref="parent2: HTMLUListElementparent2" HTMLAttributes.class?: ClassValueclass="file-list"> <li: LiHTMLAttributes & ReservedPropsli v-for="const item: neveritem in const files2: Ref<never[], never[]>files2" ReservedProps.key?: PropertyKey | undefined:key="const item: neveritem" HTMLAttributes.class?: ClassValueclass="file"> {{ const item: neveritem }} </li: LiHTMLAttributes & ReservedPropsli> </ul: HTMLAttributes & ReservedPropsul> </div: HTMLAttributes & ReservedPropsdiv> </template>
/** @jsxImportSource solid-js */
import { 
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
} from "solid-js";
import { function useDragAndDrop<E extends HTMLElement, T = unknown>(initValues: T[], options?: Partial<ParentConfig<T>>): [Setter<E | null>, Accessor<Store<T[]>>, ReturnType<typeof createStore>[1], (config?: Partial<ParentConfig<T>>) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paraminitValues - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
} from "@formkit/drag-and-drop/solid";
export function function MyComponent(): JSX.ElementMyComponent() { const const mockFileNames: string[]mockFileNames = [ "dungeon_master.exe", "map_1.dat", "map_2.dat", "character1.txt", "character2.txt", "shell32.dll", "README.txt", ]; const [const parent1: Setter<HTMLUListElement | null>parent1, const files1: Accessor<string[]>files1] = useDragAndDrop<HTMLUListElement, string>(initValues: string[], options?: Partial<ParentConfig<string>>): [Setter<HTMLUListElement | null>, Accessor<string[]>, SetStoreFunction<string[]>, (config?: Partial<ParentConfig<string>> | undefined) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paraminitValues - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
<HTMLUListElement, string>(
const mockFileNames: string[]mockFileNames, { group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "A",
multiDrag?: boolean | undefinedmultiDrag: true, selectedClass?: string | undefined
The class to add to a node when it is selected (clicked or pressed).
selectedClass
: "bg-blue-500 text-white",
} ); const [const parent2: Setter<HTMLUListElement | null>parent2, const files2: Accessor<string[]>files2] = useDragAndDrop<HTMLUListElement, string>(initValues: string[], options?: Partial<ParentConfig<string>>): [Setter<HTMLUListElement | null>, Accessor<string[]>, SetStoreFunction<string[]>, (config?: Partial<ParentConfig<string>> | undefined) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paraminitValues - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
<HTMLUListElement, string>([], {
group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "A",
multiDrag?: boolean | undefinedmultiDrag: true, selectedClass?: string | undefined
The class to add to a node when it is selected (clicked or pressed).
selectedClass
: "bg-blue-500 text-white",
}); return ( <JSX.HTMLElementTags.div: JSX.HTMLAttributes<HTMLDivElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/div@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLDivElement
div
JSX.DOMAttributes<HTMLDivElement>.class?: string | undefinedclass="file-manager">
<JSX.HTMLElementTags.ul: JSX.HTMLAttributes<HTMLUListElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLUListElement
ul
ref?: HTMLUListElement | ((el: HTMLUListElement) => void) | undefinedref={const parent1: Setter<HTMLUListElement | null>parent1} JSX.DOMAttributes<T>.class?: string | undefinedclass="file-list">
<
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
each: false | string[] | null | undefinedeach={const files1: () => string[]files1()}>{(file: stringfile) => <JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
JSX.DOMAttributes<T>.class?: string | undefinedclass="file">{file: stringfile}</JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
>}</
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
>
</JSX.HTMLElementTags.ul: JSX.HTMLAttributes<HTMLUListElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLUListElement
ul
>
<JSX.HTMLElementTags.ul: JSX.HTMLAttributes<HTMLUListElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLUListElement
ul
ref?: HTMLUListElement | ((el: HTMLUListElement) => void) | undefinedref={const parent2: Setter<HTMLUListElement | null>parent2} JSX.DOMAttributes<T>.class?: string | undefinedclass="file-list">
<
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
each: false | string[] | null | undefinedeach={const files2: () => string[]files2()}>{(file: stringfile) => <JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
JSX.DOMAttributes<T>.class?: string | undefinedclass="file">{file: stringfile}</JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
>}</
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
>
</JSX.HTMLElementTags.ul: JSX.HTMLAttributes<HTMLUListElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLUListElement
ul
>
</JSX.HTMLElementTags.div: JSX.HTMLAttributes<HTMLDivElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/div@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLDivElement
div
>
); }
import { function reactive<T>(effect: () => T): Computed<T> (+1 overload)
A reactive object is a proxy of the original object that allows for reactive dependency watching. It is created by calling `reactive()` and should be used to store reactive data in your app and components.
@paramdata - The data to make reactive, typically a plain object.@returnsA reactive proxy of the original data.
reactive
, function html(strings: TemplateStringsArray | string[], ...expSlots: ArrowExpression[]): ArrowTemplatehtml } from "@arrow-js/core";
import { function dragAndDrop<T>({ parent, getValues, setValues, config, }: DragAndDrop<T>): void
Initializes the drag and drop functionality for a given parent.
@paramdragAndDrop - The drag and drop configuration.@returnsvoid
dragAndDrop
} from "@formkit/drag-and-drop";
const
const state: Reactive<{
    files1: string[];
    files2: string[];
}>
state
=
reactive<{
    files1: string[];
    files2: string[];
}>(data: {
    files1: string[];
    files2: string[];
}): Reactive<{
    files1: string[];
    files2: string[];
}> (+1 overload)
A reactive object is a proxy of the original object that allows for reactive dependency watching. It is created by calling `reactive()` and should be used to store reactive data in your app and components.
@paramdata - The data to make reactive, typically a plain object.@returnsA reactive proxy of the original data.
reactive
({
files1: string[]files1: [ "dungeon_master.exe", "map_1.dat", "map_2.dat", "character1.txt", "character2.txt", "shell32.dll", "README.txt", ], files2: string[]files2: [] as string[], }); dragAndDrop<string>({ parent, getValues, setValues, config, }: DragAndDrop<string>): void
Initializes the drag and drop functionality for a given parent.
@paramdragAndDrop - The drag and drop configuration.@returnsvoid
dragAndDrop
<string>({
DragAndDrop<string>.parent: HTMLElement
The parent element that will contain the draggable nodes.
parent
: var document: Document
**`window.document`** returns a reference to the document contained in the window. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)
document
.Document.getElementById(elementId: string): HTMLElement | null
The **`getElementById()`** method of the Document interface returns an Element object representing the element whose id property matches the specified string. Since element IDs are required to be unique if specified, they're a useful way to get access to a specific element quickly.
getElementById
("parent1")!,
DragAndDrop<string>.getValues: (parent: HTMLElement) => string[]
A function that returns the values assigned to the parent.
getValues
: () =>
const state: Reactive<{
    files1: string[];
    files2: string[];
}>
state
.files1: string[] | Reactive<string[]>files1,
DragAndDrop<string>.setValues: (values: string[], parent: HTMLElement) => void
A function that sets the values assigned to the parent.
setValues
: (newValues: string[]newValues) => {
const state: Reactive<{
    files1: string[];
    files2: string[];
}>
state
.files1: string[] | Reactive<string[]>files1 = reactive<string[]>(data: string[]): Reactive<string[]> (+1 overload)
A reactive object is a proxy of the original object that allows for reactive dependency watching. It is created by calling `reactive()` and should be used to store reactive data in your app and components.
@paramdata - The data to make reactive, typically a plain object.@returnsA reactive proxy of the original data.
reactive
(newValues: string[]newValues);
}, DragAndDrop<string>.config?: Partial<ParentConfig<string>> | undefined
An optional configuration object.
config
: {
group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "A",
multiDrag?: boolean | undefinedmultiDrag: true, selectedClass?: string | undefined
The class to add to a node when it is selected (clicked or pressed).
selectedClass
: "bg-blue-500 text-white",
}, }); dragAndDrop<string>({ parent, getValues, setValues, config, }: DragAndDrop<string>): void
Initializes the drag and drop functionality for a given parent.
@paramdragAndDrop - The drag and drop configuration.@returnsvoid
dragAndDrop
<string>({
DragAndDrop<string>.parent: HTMLElement
The parent element that will contain the draggable nodes.
parent
: var document: Document
**`window.document`** returns a reference to the document contained in the window. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)
document
.Document.getElementById(elementId: string): HTMLElement | null
The **`getElementById()`** method of the Document interface returns an Element object representing the element whose id property matches the specified string. Since element IDs are required to be unique if specified, they're a useful way to get access to a specific element quickly.
getElementById
("parent2")!,
DragAndDrop<string>.getValues: (parent: HTMLElement) => string[]
A function that returns the values assigned to the parent.
getValues
: () =>
const state: Reactive<{
    files1: string[];
    files2: string[];
}>
state
.files2: string[] | Reactive<string[]>files2,
DragAndDrop<string>.setValues: (values: string[], parent: HTMLElement) => void
A function that sets the values assigned to the parent.
setValues
: (newValues: string[]newValues) => {
const state: Reactive<{
    files1: string[];
    files2: string[];
}>
state
.files2: string[] | Reactive<string[]>files2 = reactive<string[]>(data: string[]): Reactive<string[]> (+1 overload)
A reactive object is a proxy of the original object that allows for reactive dependency watching. It is created by calling `reactive()` and should be used to store reactive data in your app and components.
@paramdata - The data to make reactive, typically a plain object.@returnsA reactive proxy of the original data.
reactive
(newValues: string[]newValues);
}, DragAndDrop<string>.config?: Partial<ParentConfig<string>> | undefined
An optional configuration object.
config
: {
group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "A",
multiDrag?: boolean | undefinedmultiDrag: true, selectedClass?: string | undefined
The class to add to a node when it is selected (clicked or pressed).
selectedClass
: "bg-blue-500 text-white",
}, }); function html(strings: TemplateStringsArray | string[], ...expSlots: ArrowExpression[]): ArrowTemplatehtml` <div class="file-manager"> <ul class="file-list" id="parent1"> ${() =>
const state: Reactive<{
    files1: string[];
    files2: string[];
}>
state
.files1: string[] | Reactive<string[]>files1.Array<T>.map<ArrowTemplate>(callbackfn: (value: string, index: number, array: string[]) => ArrowTemplate, thisArg?: any): ArrowTemplate[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
((file: stringfile) =>
function html(strings: TemplateStringsArray | string[], ...expSlots: ArrowExpression[]): ArrowTemplatehtml` <li class="file">${file: stringfile}</li> `.ArrowTemplate.key: (key: ArrowTemplateKey) => ArrowTemplatekey(file: stringfile) )} </ul> <ul class="file-list" id="parent2"> ${
const state: Reactive<{
    files1: string[];
    files2: string[];
}>
state
.files2: string[] | Reactive<string[]>files2.Array<T>.map<ArrowTemplate>(callbackfn: (value: string, index: number, array: string[]) => ArrowTemplate, thisArg?: any): ArrowTemplate[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
((file: stringfile) =>
function html(strings: TemplateStringsArray | string[], ...expSlots: ArrowExpression[]): ArrowTemplatehtml` <li class="file">${file: stringfile}</li> `.ArrowTemplate.key: (key: ArrowTemplateKey) => ArrowTemplatekey(file: stringfile) )} </ul> </div> `(var document: Document
**`window.document`** returns a reference to the document contained in the window. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)
document
.Document.getElementById(elementId: string): HTMLElement | null
The **`getElementById()`** method of the Document interface returns an Element object representing the element whose id property matches the specified string. Since element IDs are required to be unique if specified, they're a useful way to get access to a specific element quickly.
getElementById
("app")!);
static const mockFileNames = [
  "dungeon_master.exe",
  "map_1.dat",
  "map_2.dat",
  "character1.txt",
  "character2.txt",
  "shell32.dll",
  "README.txt",
];
static const config = {
  group: "A",
  multiDrag: true,
  selectedClass: "bg-blue-500 text-white",
};

<let/files1=mockFileNames>
<let/files2=[]>

<div class="file-manager">
  <ul/parent1 class="file-list">
    <for|item| of=files1 by=(f => f)>
      <li class="file">${item}</li>
    </for>
  </ul>
  <ul/parent2 class="file-list">
    <for|item| of=files2 by=(f => f)>
      <li class="file">${item}</li>
    </for>
  </ul>
</div>

<dnd:=files1 parent=parent1 config=config/>
<dnd:=files2 parent=parent2 config=config/>

Plugins

Plugins are a powerful way to extend the functionality of the library. They can be used to add new features, modify existing ones, or even create entirely new experiences.

Drop or Swap

The examples seen so far have shown the values of a given list being updated as the end-user drags over the list and its children. To enable behavior where the values of the list are only updated when the user drops the item, use the dropOrSwap plugin.

  • React
  • Vue
  • Solid
  • Native
  • Marko
import React from "react";
import { 
function dropOrSwap<T>(dropSwapConfig?: DropSwapConfig<T>): (parent: HTMLElement) => {
    setup(): void;
} | undefined
dropOrSwap
} from "@formkit/drag-and-drop";
import { function useDragAndDrop<E extends HTMLElement, T = unknown>(list: T[], options?: Partial<ParentConfig<T>>): [React.RefObject<E | null>, T[], React.Dispatch<React.SetStateAction<T[]>>, (config: Partial<ParentConfig<T>>) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paramlist - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
} from "@formkit/drag-and-drop/react";
export function function myComponent(): React.JSX.ElementmyComponent() { const const todoItems: string[]todoItems = [ "Schedule perm", "Rewind VHS tapes", "Make change for the arcade", "Get disposable camera developed", "Learn C++", "Return Nintendo Power Glove", ]; const [const todoSwap: booleantodoSwap, const setTodoSwap: React.Dispatch<React.SetStateAction<boolean>>setTodoSwap] = React.function React.useState<boolean>(initialState: boolean | (() => boolean)): [boolean, React.Dispatch<React.SetStateAction<boolean>>] (+1 overload)
Returns a stateful value, and a function to update it.
@version16.8.0@see{@link https://react.dev/reference/react/useState}
useState
(false);
const [const doneSwap: booleandoneSwap, const setDoneSwap: React.Dispatch<React.SetStateAction<boolean>>setDoneSwap] = React.function React.useState<boolean>(initialState: boolean | (() => boolean)): [boolean, React.Dispatch<React.SetStateAction<boolean>>] (+1 overload)
Returns a stateful value, and a function to update it.
@version16.8.0@see{@link https://react.dev/reference/react/useState}
useState
(false);
const const doneItems: string[]doneItems = ["Pickup new mix-tape from Beth"]; const [const todoList: React.RefObject<HTMLUListElement | null>todoList, const todos: string[]todos] = useDragAndDrop<HTMLUListElement, string>(list: string[], options?: Partial<ParentConfig<string>>): [React.RefObject<HTMLUListElement | null>, string[], React.Dispatch<React.SetStateAction<string[]>>, (config: Partial<ParentConfig<string>>) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paramlist - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
<HTMLUListElement, string>(
const todoItems: string[]todoItems, { group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "todoList",
plugins?: DNDPlugin[] | undefined
An array of functions to use for a given parent.
plugins
: [
dropOrSwap<unknown>(dropSwapConfig?: DropSwapConfig<unknown>): (parent: HTMLElement) => {
    setup(): void;
} | undefined
dropOrSwap
({
DropSwapConfig<unknown>.shouldSwap?: ((data: ShouldSwapData<unknown>) => boolean) | undefinedshouldSwap: () => { return const todoSwap: booleantodoSwap; }, }), ], } ); const [const doneList: React.RefObject<HTMLUListElement | null>doneList, const dones: string[]dones] = useDragAndDrop<HTMLUListElement, string>(list: string[], options?: Partial<ParentConfig<string>>): [React.RefObject<HTMLUListElement | null>, string[], React.Dispatch<React.SetStateAction<string[]>>, (config: Partial<ParentConfig<string>>) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paramlist - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
<HTMLUListElement, string>(
const doneItems: string[]doneItems, { group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "todoList",
plugins?: DNDPlugin[] | undefined
An array of functions to use for a given parent.
plugins
: [
dropOrSwap<unknown>(dropSwapConfig?: DropSwapConfig<unknown>): (parent: HTMLElement) => {
    setup(): void;
} | undefined
dropOrSwap
({
DropSwapConfig<unknown>.shouldSwap?: ((data: ShouldSwapData<unknown>) => boolean) | undefinedshouldSwap: () => { return const doneSwap: booleandoneSwap; }, }), ], } ); function function (local function) toggleTodoSwap(): voidtoggleTodoSwap() { const setTodoSwap: (value: React.SetStateAction<boolean>) => voidsetTodoSwap(!const todoSwap: booleantodoSwap); } function function (local function) toggleDoneSwap(): voidtoggleDoneSwap() { const setDoneSwap: (value: React.SetStateAction<boolean>) => voidsetDoneSwap(!const doneSwap: booleandoneSwap); } return ( <React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div React.HTMLAttributes<HTMLDivElement>.className?: string | undefinedclassName="kanban-board"> <React.JSX.IntrinsicElements.ul: React.DetailedHTMLProps<React.HTMLAttributes<HTMLUListElement>, HTMLUListElement>ul React.RefAttributes<HTMLUListElement>.ref?: React.Ref<HTMLUListElement> | undefined
Allows getting a ref to the component instance. Once the component unmounts, React will set `ref.current` to `null` (or call the ref with `null` if you passed a callback ref).
@see{@link https://react.dev/learn/referencing-values-with-refs#refs-and-the-dom React Docs}
ref
={const todoList: React.RefObject<HTMLUListElement | null>todoList}>
{const todos: string[]todos.Array<string>.map<React.JSX.Element>(callbackfn: (value: string, index: number, array: string[]) => React.JSX.Element, thisArg?: any): React.JSX.Element[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
((todo: stringtodo) => (
<React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li React.HTMLAttributes<T>.className?: string | undefinedclassName="kanban-item" React.Attributes.key?: React.Key | null | undefinedkey={todo: stringtodo}> {todo: stringtodo} </React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li> ))} </React.JSX.IntrinsicElements.ul: React.DetailedHTMLProps<React.HTMLAttributes<HTMLUListElement>, HTMLUListElement>ul> <React.JSX.IntrinsicElements.button: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>button React.DOMAttributes<HTMLButtonElement>.onClick?: React.MouseEventHandler<HTMLButtonElement> | undefinedonClick={function (local function) toggleTodoSwap(): voidtoggleTodoSwap}> {" "} Toggle {const todoSwap: booleantodoSwap ? "Drop" : "Swap"} </React.JSX.IntrinsicElements.button: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>button> <React.JSX.IntrinsicElements.ul: React.DetailedHTMLProps<React.HTMLAttributes<HTMLUListElement>, HTMLUListElement>ul React.RefAttributes<HTMLUListElement>.ref?: React.Ref<HTMLUListElement> | undefined
Allows getting a ref to the component instance. Once the component unmounts, React will set `ref.current` to `null` (or call the ref with `null` if you passed a callback ref).
@see{@link https://react.dev/learn/referencing-values-with-refs#refs-and-the-dom React Docs}
ref
={const doneList: React.RefObject<HTMLUListElement | null>doneList}>
{const dones: string[]dones.Array<string>.map<React.JSX.Element>(callbackfn: (value: string, index: number, array: string[]) => React.JSX.Element, thisArg?: any): React.JSX.Element[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
((done: stringdone) => (
<React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li React.HTMLAttributes<T>.className?: string | undefinedclassName="kanban-item" React.Attributes.key?: React.Key | null | undefinedkey={done: stringdone}> {done: stringdone} </React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li> ))} </React.JSX.IntrinsicElements.ul: React.DetailedHTMLProps<React.HTMLAttributes<HTMLUListElement>, HTMLUListElement>ul> <React.JSX.IntrinsicElements.button: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>button React.DOMAttributes<HTMLButtonElement>.onClick?: React.MouseEventHandler<HTMLButtonElement> | undefinedonClick={function (local function) toggleDoneSwap(): voidtoggleDoneSwap}> Toggle {const doneSwap: booleandoneSwap ? "Drop" : "Swap"} </React.JSX.IntrinsicElements.button: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>button> </React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div> ); }
<script setup lang="ts">
import { function ref<T>(value: T): [T] extends [Ref] ? IfAny<T, Ref<T>, T> : Ref<UnwrapRef<T>, UnwrapRef<T> | T> (+1 overload)
Takes an inner value and returns a reactive and mutable ref object, which has a single property `.value` that points to the inner value.
@paramvalue - The object to wrap in the ref.@see{@link https://vuejs.org/api/reactivity-core.html#ref}
ref
} from "vue";
import {
function dropOrSwap<T>(dropSwapConfig?: DropSwapConfig<T>): (parent: HTMLElement) => {
    setup(): void;
} | undefined
dropOrSwap
} from "@formkit/drag-and-drop";
import { function useDragAndDrop<T>(initialValues: T[], options?: Partial<VueParentConfig<T>>): [Ref<HTMLElement | undefined>, Ref<T[]>, (config: Partial<VueParentConfig<T>>) => void]
Creates a new instance of drag and drop and returns the parent element and a ref of the values to use in your template.
@paraminitialValues - The initial values of the parent element.@returnsThe parent element and values for drag and drop.
useDragAndDrop
} from "@formkit/drag-and-drop/vue";
const const todoItems: string[]todoItems = [ "Schedule perm", "Rewind VHS tapes", "Make change for the arcade", "Get disposable camera developed", "Learn C++", "Return Nintendo Power Glove", ]; const const doneItems: string[]doneItems = ["Pickup new mix-tape from Beth"]; const const todoShouldSwap: Ref<boolean, boolean>todoShouldSwap = ref<boolean>(value: boolean): Ref<boolean, boolean> (+1 overload)
Takes an inner value and returns a reactive and mutable ref object, which has a single property `.value` that points to the inner value.
@paramvalue - The object to wrap in the ref.@see{@link https://vuejs.org/api/reactivity-core.html#ref}
ref
(false);
const const doneShouldSwap: Ref<boolean, boolean>doneShouldSwap = ref<boolean>(value: boolean): Ref<boolean, boolean> (+1 overload)
Takes an inner value and returns a reactive and mutable ref object, which has a single property `.value` that points to the inner value.
@paramvalue - The object to wrap in the ref.@see{@link https://vuejs.org/api/reactivity-core.html#ref}
ref
(false);
const [const todoList: Ref<HTMLElement | undefined, HTMLElement | undefined>todoList, const todos: Ref<string[], string[]>todos] = useDragAndDrop<string>(initialValues: string[], options?: Partial<Partial<ParentConfig<string>>>): [Ref<HTMLElement | undefined, HTMLElement | undefined>, Ref<string[], string[]>, (config: Partial<Partial<ParentConfig<string>>>) => void]
Creates a new instance of drag and drop and returns the parent element and a ref of the values to use in your template.
@paraminitialValues - The initial values of the parent element.@returnsThe parent element and values for drag and drop.
useDragAndDrop
(const todoItems: string[]todoItems, {
group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "todoList",
plugins?: DNDPlugin[] | undefined
An array of functions to use for a given parent.
plugins
: [
dropOrSwap<unknown>(dropSwapConfig?: DropSwapConfig<unknown>): (parent: HTMLElement) => {
    setup(): void;
} | undefined
dropOrSwap
({
DropSwapConfig<unknown>.shouldSwap?: ((data: ShouldSwapData<unknown>) => boolean) | undefinedshouldSwap: () => const todoShouldSwap: Ref<boolean, boolean>todoShouldSwap.Ref<boolean, boolean>.value: booleanvalue, }), ], }); const [const doneList: Ref<HTMLElement | undefined, HTMLElement | undefined>doneList, const dones: Ref<string[], string[]>dones] = useDragAndDrop<string>(initialValues: string[], options?: Partial<Partial<ParentConfig<string>>>): [Ref<HTMLElement | undefined, HTMLElement | undefined>, Ref<string[], string[]>, (config: Partial<Partial<ParentConfig<string>>>) => void]
Creates a new instance of drag and drop and returns the parent element and a ref of the values to use in your template.
@paraminitialValues - The initial values of the parent element.@returnsThe parent element and values for drag and drop.
useDragAndDrop
(const doneItems: string[]doneItems, {
group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "todoList",
plugins?: DNDPlugin[] | undefined
An array of functions to use for a given parent.
plugins
: [
dropOrSwap<unknown>(dropSwapConfig?: DropSwapConfig<unknown>): (parent: HTMLElement) => {
    setup(): void;
} | undefined
dropOrSwap
({
DropSwapConfig<unknown>.shouldSwap?: ((data: ShouldSwapData<unknown>) => boolean) | undefinedshouldSwap: () => const doneShouldSwap: Ref<boolean, boolean>doneShouldSwap.Ref<boolean, boolean>.value: booleanvalue, }), ], }); function function toggleTodoSwap(): voidtoggleTodoSwap() { const todoShouldSwap: Ref<boolean, boolean>todoShouldSwap.Ref<boolean, boolean>.value: booleanvalue = !const todoShouldSwap: Ref<boolean, boolean>todoShouldSwap.Ref<boolean, boolean>.value: booleanvalue; } function function toggleDoneSwap(): voidtoggleDoneSwap() { const doneShouldSwap: Ref<boolean, boolean>doneShouldSwap.Ref<boolean, boolean>.value: booleanvalue = !const doneShouldSwap: Ref<boolean, boolean>doneShouldSwap.Ref<boolean, boolean>.value: booleanvalue; } </script> <template> <div: HTMLAttributes & ReservedPropsdiv HTMLAttributes.class?: ClassValueclass="kanban-board"> <ul: HTMLAttributes & ReservedPropsul ReservedProps.ref?: VNodeRef | undefinedref="todoList: HTMLUListElementtodoList" HTMLAttributes.class?: ClassValueclass="kanban-column"> <li: LiHTMLAttributes & ReservedPropsli v-for="const todo: stringtodo in const todos: Ref<string[], string[]>todos" ReservedProps.key?: PropertyKey | undefined:key="const todo: stringtodo" HTMLAttributes.class?: ClassValueclass="kanban-item"> {{ const todo: stringtodo }} </li: LiHTMLAttributes & ReservedPropsli> </ul: HTMLAttributes & ReservedPropsul> <div: HTMLAttributes & ReservedPropsdiv> <button: ButtonHTMLAttributes & ReservedPropsbutton @onClick?: ((payload: PointerEvent) => void) | undefinedclick="function toggleTodoSwap(): voidtoggleTodoSwap()" HTMLAttributes.class?: ClassValueclass="bg-indigo-500 text-white font-bold py-2 px-4 rounded-lg mt-4" > Toggle {{ const todoShouldSwap: Ref<boolean, boolean>todoShouldSwap ? "Drop" : "Swap" }} </button: ButtonHTMLAttributes & ReservedPropsbutton> </div: HTMLAttributes & ReservedPropsdiv> <ul: HTMLAttributes & ReservedPropsul ReservedProps.ref?: VNodeRef | undefinedref="doneList: HTMLUListElementdoneList" HTMLAttributes.class?: ClassValueclass="kanban-column"> <li: LiHTMLAttributes & ReservedPropsli v-for="const done: stringdone in const dones: Ref<string[], string[]>dones" ReservedProps.key?: PropertyKey | undefined:key="const done: stringdone" HTMLAttributes.class?: ClassValueclass="kanban-item"> {{ const done: stringdone }} </li: LiHTMLAttributes & ReservedPropsli> </ul: HTMLAttributes & ReservedPropsul> <div: HTMLAttributes & ReservedPropsdiv> <button: ButtonHTMLAttributes & ReservedPropsbutton @onClick?: ((payload: PointerEvent) => void) | undefinedclick="function toggleDoneSwap(): voidtoggleDoneSwap()" HTMLAttributes.class?: ClassValueclass="bg-indigo-500 text-white font-bold py-2 px-4 rounded-lg mt-4" > Toggle {{ const doneShouldSwap: Ref<boolean, boolean>doneShouldSwap ? "Drop" : "Swap" }} </button: ButtonHTMLAttributes & ReservedPropsbutton> </div: HTMLAttributes & ReservedPropsdiv> </div: HTMLAttributes & ReservedPropsdiv> </template>
/** @jsxImportSource solid-js */
import { function createSignal<T>(): Signal<T | undefined> (+1 overload)
Creates a simple reactive state with a getter and setter ```typescript const [state: Accessor<T>, setState: Setter<T>] = createSignal<T>( value: T, options?: { name?: string, equals?: false | ((prev: T, next: T) => boolean) } ) ```
@paramvalue initial value of the state; if empty, the state's type will automatically extended with undefined; otherwise you need to extend the type manually if you want setting to undefined not be an error@paramoptions optional object with a name for debugging purposes and equals, a comparator function for the previous and next value to allow fine-grained control over the reactivity@returns```typescript [state: Accessor<T>, setState: Setter<T>] ``` * the Accessor is merely a function that returns the current value and registers each call to the reactive root * the Setter is a function that allows directly setting or mutating the value: ```typescript const [count, setCount] = createSignal(0); setCount(count => count + 1); ```@descriptionhttps://docs.solidjs.com/reference/basic-reactivity/create-signal
createSignal
} from "solid-js";
import {
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
} from "solid-js";
import {
function dropOrSwap<T>(dropSwapConfig?: DropSwapConfig<T>): (parent: HTMLElement) => {
    setup(): void;
} | undefined
dropOrSwap
} from "@formkit/drag-and-drop";
import { function useDragAndDrop<E extends HTMLElement, T = unknown>(initValues: T[], options?: Partial<ParentConfig<T>>): [Setter<E | null>, Accessor<Store<T[]>>, ReturnType<typeof createStore>[1], (config?: Partial<ParentConfig<T>>) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paraminitValues - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
} from "@formkit/drag-and-drop/solid";
export function function MyComponent(): JSX.ElementMyComponent() { const const todoItems: string[]todoItems = [ "Schedule perm", "Rewind VHS tapes", "Make change for the arcade", "Get disposable camera developed", "Learn C++", "Return Nintendo Power Glove", ]; const [const todoSwap: Accessor<boolean>todoSwap, const setTodoSwap: Setter<boolean>setTodoSwap] = createSignal<boolean>(value: boolean, options?: SignalOptions<boolean> | undefined): Signal<boolean> (+1 overload)
Creates a simple reactive state with a getter and setter ```typescript const [state: Accessor<T>, setState: Setter<T>] = createSignal<T>( value: T, options?: { name?: string, equals?: false | ((prev: T, next: T) => boolean) } ) ```
@paramvalue initial value of the state; if empty, the state's type will automatically extended with undefined; otherwise you need to extend the type manually if you want setting to undefined not be an error@paramoptions optional object with a name for debugging purposes and equals, a comparator function for the previous and next value to allow fine-grained control over the reactivity@returns```typescript [state: Accessor<T>, setState: Setter<T>] ``` * the Accessor is merely a function that returns the current value and registers each call to the reactive root * the Setter is a function that allows directly setting or mutating the value: ```typescript const [count, setCount] = createSignal(0); setCount(count => count + 1); ```@descriptionhttps://docs.solidjs.com/reference/basic-reactivity/create-signal
createSignal
(false);
const [const doneSwap: Accessor<boolean>doneSwap, const setDoneSwap: Setter<boolean>setDoneSwap] = createSignal<boolean>(value: boolean, options?: SignalOptions<boolean> | undefined): Signal<boolean> (+1 overload)
Creates a simple reactive state with a getter and setter ```typescript const [state: Accessor<T>, setState: Setter<T>] = createSignal<T>( value: T, options?: { name?: string, equals?: false | ((prev: T, next: T) => boolean) } ) ```
@paramvalue initial value of the state; if empty, the state's type will automatically extended with undefined; otherwise you need to extend the type manually if you want setting to undefined not be an error@paramoptions optional object with a name for debugging purposes and equals, a comparator function for the previous and next value to allow fine-grained control over the reactivity@returns```typescript [state: Accessor<T>, setState: Setter<T>] ``` * the Accessor is merely a function that returns the current value and registers each call to the reactive root * the Setter is a function that allows directly setting or mutating the value: ```typescript const [count, setCount] = createSignal(0); setCount(count => count + 1); ```@descriptionhttps://docs.solidjs.com/reference/basic-reactivity/create-signal
createSignal
(false);
const const doneItems: string[]doneItems = ["Pickup new mix-tape from Beth"]; const [const todoList: Setter<HTMLUListElement | null>todoList, const todos: Accessor<string[]>todos] = useDragAndDrop<HTMLUListElement, string>(initValues: string[], options?: Partial<ParentConfig<string>>): [Setter<HTMLUListElement | null>, Accessor<string[]>, SetStoreFunction<string[]>, (config?: Partial<ParentConfig<string>> | undefined) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paraminitValues - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
<HTMLUListElement, string>(
const todoItems: string[]todoItems, { group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "todoList",
plugins?: DNDPlugin[] | undefined
An array of functions to use for a given parent.
plugins
: [
dropOrSwap<unknown>(dropSwapConfig?: DropSwapConfig<unknown>): (parent: HTMLElement) => {
    setup(): void;
} | undefined
dropOrSwap
({
DropSwapConfig<unknown>.shouldSwap?: ((data: ShouldSwapData<unknown>) => boolean) | undefinedshouldSwap: () => { return const todoSwap: () => booleantodoSwap(); }, }), ], } ); const [const doneList: Setter<HTMLUListElement | null>doneList, const dones: Accessor<string[]>dones] = useDragAndDrop<HTMLUListElement, string>(initValues: string[], options?: Partial<ParentConfig<string>>): [Setter<HTMLUListElement | null>, Accessor<string[]>, SetStoreFunction<string[]>, (config?: Partial<ParentConfig<string>> | undefined) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paraminitValues - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
<HTMLUListElement, string>(
const doneItems: string[]doneItems, { group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "todoList",
plugins?: DNDPlugin[] | undefined
An array of functions to use for a given parent.
plugins
: [
dropOrSwap<unknown>(dropSwapConfig?: DropSwapConfig<unknown>): (parent: HTMLElement) => {
    setup(): void;
} | undefined
dropOrSwap
({
DropSwapConfig<unknown>.shouldSwap?: ((data: ShouldSwapData<unknown>) => boolean) | undefinedshouldSwap: () => { return const doneSwap: () => booleandoneSwap(); }, }), ], } ); function function (local function) toggleTodoSwap(): voidtoggleTodoSwap() { const setTodoSwap: <boolean>(value: boolean | ((prev: boolean) => boolean)) => boolean (+3 overloads)setTodoSwap(!const todoSwap: () => booleantodoSwap()); } function function (local function) toggleDoneSwap(): voidtoggleDoneSwap() { const setDoneSwap: <boolean>(value: boolean | ((prev: boolean) => boolean)) => boolean (+3 overloads)setDoneSwap(!const doneSwap: () => booleandoneSwap()); } return ( <JSX.HTMLElementTags.div: JSX.HTMLAttributes<HTMLDivElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/div@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLDivElement
div
JSX.DOMAttributes<HTMLDivElement>.class?: string | undefinedclass="kanban-board">
<JSX.HTMLElementTags.ul: JSX.HTMLAttributes<HTMLUListElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLUListElement
ul
ref?: HTMLUListElement | ((el: HTMLUListElement) => void) | undefinedref={const todoList: Setter<HTMLUListElement | null>todoList}>
<
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
each: false | string[] | null | undefinedeach={const todos: () => string[]todos()}>
{(todo: stringtodo) => ( <JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
JSX.DOMAttributes<T>.class?: string | undefinedclass="kanban-item" data-key: stringdata-key={todo: stringtodo}>
{todo: stringtodo} </JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
>
)} </
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
>
</JSX.HTMLElementTags.ul: JSX.HTMLAttributes<HTMLUListElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLUListElement
ul
>
<JSX.HTMLElementTags.button: JSX.ButtonHTMLAttributes<HTMLButtonElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/button@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLButtonElement
button
JSX.CustomEventHandlersCamelCase<HTMLButtonElement>.onClick?: JSX.EventHandlerUnion<HTMLButtonElement, MouseEvent, JSX.EventHandler<HTMLButtonElement, MouseEvent>> | undefinedonClick={function (local function) toggleTodoSwap(): voidtoggleTodoSwap}>
Toggle {const todoSwap: () => booleantodoSwap() ? "Drop" : "Swap"} </JSX.HTMLElementTags.button: JSX.ButtonHTMLAttributes<HTMLButtonElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/button@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLButtonElement
button
>
<JSX.HTMLElementTags.ul: JSX.HTMLAttributes<HTMLUListElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLUListElement
ul
ref?: HTMLUListElement | ((el: HTMLUListElement) => void) | undefinedref={const doneList: Setter<HTMLUListElement | null>doneList}>
<
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
each: false | string[] | null | undefinedeach={const dones: () => string[]dones()}>
{(done: stringdone) => ( <JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
JSX.DOMAttributes<T>.class?: string | undefinedclass="kanban-item" data-key: stringdata-key={done: stringdone}>
{done: stringdone} </JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
>
)} </
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
>
</JSX.HTMLElementTags.ul: JSX.HTMLAttributes<HTMLUListElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLUListElement
ul
>
<JSX.HTMLElementTags.button: JSX.ButtonHTMLAttributes<HTMLButtonElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/button@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLButtonElement
button
JSX.CustomEventHandlersCamelCase<HTMLButtonElement>.onClick?: JSX.EventHandlerUnion<HTMLButtonElement, MouseEvent, JSX.EventHandler<HTMLButtonElement, MouseEvent>> | undefinedonClick={function (local function) toggleDoneSwap(): voidtoggleDoneSwap}>
Toggle {const doneSwap: () => booleandoneSwap() ? "Drop" : "Swap"} </JSX.HTMLElementTags.button: JSX.ButtonHTMLAttributes<HTMLButtonElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/button@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLButtonElement
button
>
</JSX.HTMLElementTags.div: JSX.HTMLAttributes<HTMLDivElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/div@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLDivElement
div
>
); }
import { function reactive<T>(effect: () => T): Computed<T> (+1 overload)
A reactive object is a proxy of the original object that allows for reactive dependency watching. It is created by calling `reactive()` and should be used to store reactive data in your app and components.
@paramdata - The data to make reactive, typically a plain object.@returnsA reactive proxy of the original data.
reactive
, function html(strings: TemplateStringsArray | string[], ...expSlots: ArrowExpression[]): ArrowTemplatehtml } from "@arrow-js/core";
import { function dragAndDrop<T>({ parent, getValues, setValues, config, }: DragAndDrop<T>): void
Initializes the drag and drop functionality for a given parent.
@paramdragAndDrop - The drag and drop configuration.@returnsvoid
dragAndDrop
,
function dropOrSwap<T>(dropSwapConfig?: DropSwapConfig<T>): (parent: HTMLElement) => {
    setup(): void;
} | undefined
dropOrSwap
} from "@formkit/drag-and-drop";
const
const state: Reactive<{
    todos: string[];
    dones: string[];
    todoSwap: boolean;
    doneSwap: boolean;
}>
state
=
reactive<{
    todos: string[];
    dones: string[];
    todoSwap: boolean;
    doneSwap: boolean;
}>(data: {
    todos: string[];
    dones: string[];
    todoSwap: boolean;
    doneSwap: boolean;
}): Reactive<{
    todos: string[];
    dones: string[];
    todoSwap: boolean;
    doneSwap: boolean;
}> (+1 overload)
A reactive object is a proxy of the original object that allows for reactive dependency watching. It is created by calling `reactive()` and should be used to store reactive data in your app and components.
@paramdata - The data to make reactive, typically a plain object.@returnsA reactive proxy of the original data.
reactive
({
todos: string[]todos: [ "Schedule perm", "Rewind VHS tapes", "Make change for the arcade", "Get disposable camera developed", "Learn C++", "Return Nintendo Power Glove", ], dones: string[]dones: ["Pickup new mix-tape from Beth"], todoSwap: booleantodoSwap: false, doneSwap: booleandoneSwap: false, }); dragAndDrop<string>({ parent, getValues, setValues, config, }: DragAndDrop<string>): void
Initializes the drag and drop functionality for a given parent.
@paramdragAndDrop - The drag and drop configuration.@returnsvoid
dragAndDrop
<string>({
DragAndDrop<string>.parent: HTMLElement
The parent element that will contain the draggable nodes.
parent
: var document: Document
**`window.document`** returns a reference to the document contained in the window. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)
document
.Document.getElementById(elementId: string): HTMLElement | null
The **`getElementById()`** method of the Document interface returns an Element object representing the element whose id property matches the specified string. Since element IDs are required to be unique if specified, they're a useful way to get access to a specific element quickly.
getElementById
("todo-list")!,
DragAndDrop<string>.getValues: (parent: HTMLElement) => string[]
A function that returns the values assigned to the parent.
getValues
: () =>
const state: Reactive<{
    todos: string[];
    dones: string[];
    todoSwap: boolean;
    doneSwap: boolean;
}>
state
.todos: string[] | Reactive<string[]>todos,
DragAndDrop<string>.setValues: (values: string[], parent: HTMLElement) => void
A function that sets the values assigned to the parent.
setValues
: (newValues: string[]newValues) => {
const state: Reactive<{
    todos: string[];
    dones: string[];
    todoSwap: boolean;
    doneSwap: boolean;
}>
state
.todos: string[] | Reactive<string[]>todos = reactive<string[]>(data: string[]): Reactive<string[]> (+1 overload)
A reactive object is a proxy of the original object that allows for reactive dependency watching. It is created by calling `reactive()` and should be used to store reactive data in your app and components.
@paramdata - The data to make reactive, typically a plain object.@returnsA reactive proxy of the original data.
reactive
(newValues: string[]newValues);
}, DragAndDrop<string>.config?: Partial<ParentConfig<string>> | undefined
An optional configuration object.
config
: {
group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "todoList",
plugins?: DNDPlugin[] | undefined
An array of functions to use for a given parent.
plugins
: [
dropOrSwap<unknown>(dropSwapConfig?: DropSwapConfig<unknown>): (parent: HTMLElement) => {
    setup(): void;
} | undefined
dropOrSwap
({
DropSwapConfig<unknown>.shouldSwap?: ((data: ShouldSwapData<unknown>) => boolean) | undefinedshouldSwap: () =>
const state: Reactive<{
    todos: string[];
    dones: string[];
    todoSwap: boolean;
    doneSwap: boolean;
}>
state
.todoSwap: booleantodoSwap,
}), ], }, }); dragAndDrop<string>({ parent, getValues, setValues, config, }: DragAndDrop<string>): void
Initializes the drag and drop functionality for a given parent.
@paramdragAndDrop - The drag and drop configuration.@returnsvoid
dragAndDrop
<string>({
DragAndDrop<string>.parent: HTMLElement
The parent element that will contain the draggable nodes.
parent
: var document: Document
**`window.document`** returns a reference to the document contained in the window. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)
document
.Document.getElementById(elementId: string): HTMLElement | null
The **`getElementById()`** method of the Document interface returns an Element object representing the element whose id property matches the specified string. Since element IDs are required to be unique if specified, they're a useful way to get access to a specific element quickly.
getElementById
("done-list")!,
DragAndDrop<string>.getValues: (parent: HTMLElement) => string[]
A function that returns the values assigned to the parent.
getValues
: () =>
const state: Reactive<{
    todos: string[];
    dones: string[];
    todoSwap: boolean;
    doneSwap: boolean;
}>
state
.dones: string[] | Reactive<string[]>dones,
DragAndDrop<string>.setValues: (values: string[], parent: HTMLElement) => void
A function that sets the values assigned to the parent.
setValues
: (newValues: string[]newValues) => {
const state: Reactive<{
    todos: string[];
    dones: string[];
    todoSwap: boolean;
    doneSwap: boolean;
}>
state
.dones: string[] | Reactive<string[]>dones = reactive<string[]>(data: string[]): Reactive<string[]> (+1 overload)
A reactive object is a proxy of the original object that allows for reactive dependency watching. It is created by calling `reactive()` and should be used to store reactive data in your app and components.
@paramdata - The data to make reactive, typically a plain object.@returnsA reactive proxy of the original data.
reactive
(newValues: string[]newValues);
}, DragAndDrop<string>.config?: Partial<ParentConfig<string>> | undefined
An optional configuration object.
config
: {
group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "todoList",
plugins?: DNDPlugin[] | undefined
An array of functions to use for a given parent.
plugins
: [
dropOrSwap<unknown>(dropSwapConfig?: DropSwapConfig<unknown>): (parent: HTMLElement) => {
    setup(): void;
} | undefined
dropOrSwap
({
DropSwapConfig<unknown>.shouldSwap?: ((data: ShouldSwapData<unknown>) => boolean) | undefinedshouldSwap: () =>
const state: Reactive<{
    todos: string[];
    dones: string[];
    todoSwap: boolean;
    doneSwap: boolean;
}>
state
.doneSwap: booleandoneSwap,
}), ], }, }); function html(strings: TemplateStringsArray | string[], ...expSlots: ArrowExpression[]): ArrowTemplatehtml` <div class="kanban-board"> <ul class="kanban-list" id="todo-list"> ${() =>
const state: Reactive<{
    todos: string[];
    dones: string[];
    todoSwap: boolean;
    doneSwap: boolean;
}>
state
.todos: string[] | Reactive<string[]>todos.Array<T>.map<ArrowTemplate>(callbackfn: (value: string, index: number, array: string[]) => ArrowTemplate, thisArg?: any): ArrowTemplate[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
((todo: stringtodo) =>
function html(strings: TemplateStringsArray | string[], ...expSlots: ArrowExpression[]): ArrowTemplatehtml`<li class="kanban-item">${todo: stringtodo}</li>`.ArrowTemplate.key: (key: ArrowTemplateKey) => ArrowTemplatekey(todo: stringtodo) )} </ul> <button onclick=${() => (
const state: Reactive<{
    todos: string[];
    dones: string[];
    todoSwap: boolean;
    doneSwap: boolean;
}>
state
.todoSwap: booleantodoSwap = !
const state: Reactive<{
    todos: string[];
    dones: string[];
    todoSwap: boolean;
    doneSwap: boolean;
}>
state
.todoSwap: booleantodoSwap)}>
${() => (
const state: Reactive<{
    todos: string[];
    dones: string[];
    todoSwap: boolean;
    doneSwap: boolean;
}>
state
.todoSwap: booleantodoSwap ? "Disable" : "Enable")} swap
</button> <ul class="kanban-list" id="done-list"> ${
const state: Reactive<{
    todos: string[];
    dones: string[];
    todoSwap: boolean;
    doneSwap: boolean;
}>
state
.dones: string[] | Reactive<string[]>dones.Array<T>.map<ArrowTemplate>(callbackfn: (value: string, index: number, array: string[]) => ArrowTemplate, thisArg?: any): ArrowTemplate[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
((done: stringdone) =>
function html(strings: TemplateStringsArray | string[], ...expSlots: ArrowExpression[]): ArrowTemplatehtml`<li class="kanban-item">${done: stringdone}</li>`.ArrowTemplate.key: (key: ArrowTemplateKey) => ArrowTemplatekey(done: stringdone) )} </ul> <button onclick=${() => (
const state: Reactive<{
    todos: string[];
    dones: string[];
    todoSwap: boolean;
    doneSwap: boolean;
}>
state
.doneSwap: booleandoneSwap = !
const state: Reactive<{
    todos: string[];
    dones: string[];
    todoSwap: boolean;
    doneSwap: boolean;
}>
state
.doneSwap: booleandoneSwap)}>
${() => (
const state: Reactive<{
    todos: string[];
    dones: string[];
    todoSwap: boolean;
    doneSwap: boolean;
}>
state
.doneSwap: booleandoneSwap ? "Disable" : "Enable")} swap
</button> </div> `(var document: Document
**`window.document`** returns a reference to the document contained in the window. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)
document
.Document.getElementById(elementId: string): HTMLElement | null
The **`getElementById()`** method of the Document interface returns an Element object representing the element whose id property matches the specified string. Since element IDs are required to be unique if specified, they're a useful way to get access to a specific element quickly.
getElementById
("app")!);
import { dropOrSwap } from "@formkit/drag-and-drop";

static const todoItems = ["Schedule perm", "Rewind VHS tapes", "Make change for the arcade", "Get disposable camera developed", "Learn C++", "Return Nintendo Power Glove"];
static const doneItems = ["Pickup new mix-tape from Beth"];

<let/todos=todoItems>
<let/dones=doneItems>
<let/todoSwap=false>
<let/doneSwap=false>

<!-- Config objects are initialized once; the shouldSwap callbacks close
     over reactive variables and always read the current value. -->
<let/todoConfig={ group: "todoList", plugins: [dropOrSwap({ shouldSwap: () => todoSwap })] }>
<let/doneConfig={ group: "todoList", plugins: [dropOrSwap({ shouldSwap: () => doneSwap })] }>

<div class="kanban-board">
  <ul/todoList class="kanban-column">
    <for|todo| of=todos by=(t => t)>
      <li class="kanban-item">${todo}</li>
    </for>
  </ul>
  <div>
    <button
      onClick() { todoSwap = !todoSwap; }
      class="bg-indigo-500 text-white font-bold py-2 px-4 rounded-lg mt-4"
    >
      Toggle ${todoSwap ? "Drop" : "Swap"}
    </button>
  </div>
  <ul/doneList class="kanban-column">
    <for|done| of=dones by=(t => t)>
      <li class="kanban-item">${done}</li>
    </for>
  </ul>
  <div>
    <button
      onClick() { doneSwap = !doneSwap; }
      class="bg-indigo-500 text-white font-bold py-2 px-4 rounded-lg mt-4"
    >
      Toggle ${doneSwap ? "Drop" : "Swap"}
    </button>
  </div>
</div>

<dnd:=todos parent=todoList config=todoConfig/>
<dnd:=dones parent=doneList config=doneConfig/>

Insert (Experimental)

Similar to the dropOrSwap plugin, the insert plugin does not update values until the user drops the item. In addition, the insert plugin will render an insert point between the items to indicate where the item will be placed.

  • React
  • Vue
  • Solid
  • Native
  • Marko
import React from "react";
import { 
function insert<T>(insertConfig: InsertConfig<T>): (parent: HTMLElement) => {
    teardown(): void;
    setup(): void;
} | undefined
insert
} from "@formkit/drag-and-drop";
import { function useDragAndDrop<E extends HTMLElement, T = unknown>(list: T[], options?: Partial<ParentConfig<T>>): [React.RefObject<E | null>, T[], React.Dispatch<React.SetStateAction<T[]>>, (config: Partial<ParentConfig<T>>) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paramlist - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
} from "@formkit/drag-and-drop/react";
const const insertPointClasses: string[]insertPointClasses = [ "absolute", "bg-blue-500", "z-[1000]", "rounded-full", "duration-[5ms]", "before:block", 'before:content-["Insert"]', "before:whitespace-nowrap", "before:block", "before:bg-blue-500", "before:py-1", "before:px-2", "before:rounded-full", "before:text-xs", "before:absolute", "before:top-1/2", "before:left-1/2", "before:-translate-y-1/2", "before:-translate-x-1/2", "before:text-white", "before:text-xs", ]; export function function myComponent(): React.JSX.ElementmyComponent() { const const todoItems: string[]todoItems = [ "Schedule perm", "Rewind VHS tapes", "Make change for the arcade", "Get disposable camera developed", "Learn C++", "Return Nintendo Power Glove", ]; const [const todoSwap: booleantodoSwap, const setTodoSwap: React.Dispatch<React.SetStateAction<boolean>>setTodoSwap] = React.function React.useState<boolean>(initialState: boolean | (() => boolean)): [boolean, React.Dispatch<React.SetStateAction<boolean>>] (+1 overload)
Returns a stateful value, and a function to update it.
@version16.8.0@see{@link https://react.dev/reference/react/useState}
useState
(false);
const [const doneSwap: booleandoneSwap, const setDoneSwap: React.Dispatch<React.SetStateAction<boolean>>setDoneSwap] = React.function React.useState<boolean>(initialState: boolean | (() => boolean)): [boolean, React.Dispatch<React.SetStateAction<boolean>>] (+1 overload)
Returns a stateful value, and a function to update it.
@version16.8.0@see{@link https://react.dev/reference/react/useState}
useState
(false);
const const doneItems: string[]doneItems = ["Pickup new mix-tape from Beth"]; const [const todoList: React.RefObject<HTMLUListElement | null>todoList, const todos: string[]todos] = useDragAndDrop<HTMLUListElement, string>(list: string[], options?: Partial<ParentConfig<string>>): [React.RefObject<HTMLUListElement | null>, string[], React.Dispatch<React.SetStateAction<string[]>>, (config: Partial<ParentConfig<string>>) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paramlist - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
<HTMLUListElement, string>(
const todoItems: string[]todoItems, { group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "todoList",
plugins?: DNDPlugin[] | undefined
An array of functions to use for a given parent.
plugins
: [
insert<unknown>(insertConfig: InsertConfig<unknown>): (parent: HTMLElement) => {
    teardown(): void;
    setup(): void;
} | undefined
insert
({
InsertConfig<unknown>.insertPoint: (parent: ParentRecord<unknown>) => HTMLElementinsertPoint: (parent: ParentRecord<unknown>parent) => { const const div: HTMLDivElementdiv = var document: Document
**`window.document`** returns a reference to the document contained in the window. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)
document
.Document.createElement<"div">(tagName: "div", options?: ElementCreationOptions): HTMLDivElement (+2 overloads)
In an HTML document, the **`document.createElement()`** method creates the HTML element specified by localName, or an HTMLUnknownElement if localName isn't recognized. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Document/createElement)
createElement
("div");
for (const const cls: stringcls of const insertPointClasses: string[]insertPointClasses) const div: HTMLDivElementdiv.Element.classList: DOMTokenList
The read-only **`classList`** property of the Element interface contains a live DOMTokenList collection representing the class attribute of the element. This can then be used to manipulate the class list. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Element/classList)
classList
.DOMTokenList.add(...tokens: string[]): void
The **`add()`** method of the DOMTokenList interface adds the given tokens to the list, omitting any that are already present. [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMTokenList/add)
add
(const cls: stringcls);
return const div: HTMLDivElementdiv; }, }), ], } ); const [const doneList: React.RefObject<HTMLUListElement | null>doneList, const dones: string[]dones] = useDragAndDrop<HTMLUListElement, string>(list: string[], options?: Partial<ParentConfig<string>>): [React.RefObject<HTMLUListElement | null>, string[], React.Dispatch<React.SetStateAction<string[]>>, (config: Partial<ParentConfig<string>>) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paramlist - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
<HTMLUListElement, string>(
const doneItems: string[]doneItems, { group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "todoList",
plugins?: DNDPlugin[] | undefined
An array of functions to use for a given parent.
plugins
: [
insert<unknown>(insertConfig: InsertConfig<unknown>): (parent: HTMLElement) => {
    teardown(): void;
    setup(): void;
} | undefined
insert
({
InsertConfig<unknown>.insertPoint: (parent: ParentRecord<unknown>) => HTMLElementinsertPoint: (parent: ParentRecord<unknown>parent) => { const const div: HTMLDivElementdiv = var document: Document
**`window.document`** returns a reference to the document contained in the window. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)
document
.Document.createElement<"div">(tagName: "div", options?: ElementCreationOptions): HTMLDivElement (+2 overloads)
In an HTML document, the **`document.createElement()`** method creates the HTML element specified by localName, or an HTMLUnknownElement if localName isn't recognized. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Document/createElement)
createElement
("div");
for (const const cls: stringcls of const insertPointClasses: string[]insertPointClasses) const div: HTMLDivElementdiv.Element.classList: DOMTokenList
The read-only **`classList`** property of the Element interface contains a live DOMTokenList collection representing the class attribute of the element. This can then be used to manipulate the class list. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Element/classList)
classList
.DOMTokenList.add(...tokens: string[]): void
The **`add()`** method of the DOMTokenList interface adds the given tokens to the list, omitting any that are already present. [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMTokenList/add)
add
(const cls: stringcls);
return const div: HTMLDivElementdiv; }, }), ], } ); return ( <React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div React.HTMLAttributes<HTMLDivElement>.className?: string | undefinedclassName="kanban-board"> <React.JSX.IntrinsicElements.ul: React.DetailedHTMLProps<React.HTMLAttributes<HTMLUListElement>, HTMLUListElement>ul React.RefAttributes<HTMLUListElement>.ref?: React.Ref<HTMLUListElement> | undefined
Allows getting a ref to the component instance. Once the component unmounts, React will set `ref.current` to `null` (or call the ref with `null` if you passed a callback ref).
@see{@link https://react.dev/learn/referencing-values-with-refs#refs-and-the-dom React Docs}
ref
={const todoList: React.RefObject<HTMLUListElement | null>todoList}>
{const todos: string[]todos.Array<string>.map<React.JSX.Element>(callbackfn: (value: string, index: number, array: string[]) => React.JSX.Element, thisArg?: any): React.JSX.Element[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
((todo: stringtodo) => (
<React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li React.HTMLAttributes<T>.className?: string | undefinedclassName="kanban-item" React.Attributes.key?: React.Key | null | undefinedkey={todo: stringtodo}> {todo: stringtodo} </React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li> ))} </React.JSX.IntrinsicElements.ul: React.DetailedHTMLProps<React.HTMLAttributes<HTMLUListElement>, HTMLUListElement>ul> <React.JSX.IntrinsicElements.ul: React.DetailedHTMLProps<React.HTMLAttributes<HTMLUListElement>, HTMLUListElement>ul React.RefAttributes<HTMLUListElement>.ref?: React.Ref<HTMLUListElement> | undefined
Allows getting a ref to the component instance. Once the component unmounts, React will set `ref.current` to `null` (or call the ref with `null` if you passed a callback ref).
@see{@link https://react.dev/learn/referencing-values-with-refs#refs-and-the-dom React Docs}
ref
={const doneList: React.RefObject<HTMLUListElement | null>doneList}>
{const dones: string[]dones.Array<string>.map<React.JSX.Element>(callbackfn: (value: string, index: number, array: string[]) => React.JSX.Element, thisArg?: any): React.JSX.Element[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
((done: stringdone) => (
<React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li React.HTMLAttributes<T>.className?: string | undefinedclassName="kanban-item" React.Attributes.key?: React.Key | null | undefinedkey={done: stringdone}> {done: stringdone} </React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li> ))} </React.JSX.IntrinsicElements.ul: React.DetailedHTMLProps<React.HTMLAttributes<HTMLUListElement>, HTMLUListElement>ul> </React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div> ); }
<script setup lang="ts">
import { function ref<T>(value: T): [T] extends [Ref] ? IfAny<T, Ref<T>, T> : Ref<UnwrapRef<T>, UnwrapRef<T> | T> (+1 overload)
Takes an inner value and returns a reactive and mutable ref object, which has a single property `.value` that points to the inner value.
@paramvalue - The object to wrap in the ref.@see{@link https://vuejs.org/api/reactivity-core.html#ref}
ref
} from "vue";
import {
function insert<T>(insertConfig: InsertConfig<T>): (parent: HTMLElement) => {
    teardown(): void;
    setup(): void;
} | undefined
insert
} from "@formkit/drag-and-drop";
import { function useDragAndDrop<T>(initialValues: T[], options?: Partial<VueParentConfig<T>>): [Ref<HTMLElement | undefined>, Ref<T[]>, (config: Partial<VueParentConfig<T>>) => void]
Creates a new instance of drag and drop and returns the parent element and a ref of the values to use in your template.
@paraminitialValues - The initial values of the parent element.@returnsThe parent element and values for drag and drop.
useDragAndDrop
} from "@formkit/drag-and-drop/vue";
const const insertPointClasses: string[]insertPointClasses = [ "absolute", "bg-blue-500", "z-[1000]", "rounded-full", "duration-[5ms]", "before:block", 'before:content-["Insert"]', "before:whitespace-nowrap", "before:block", "before:bg-blue-500", "before:py-1", "before:px-2", "before:rounded-full", "before:text-xs", "before:absolute", "before:top-1/2", "before:left-1/2", "before:-translate-y-1/2", "before:-translate-x-1/2", "before:text-white", "before:text-xs", ]; const const todoItems: string[]todoItems = [ "Schedule perm", "Rewind VHS tapes", "Make change for the arcade", "Get disposable camera developed", "Learn C++", "Return Nintendo Power Glove", ]; const const doneItems: string[]doneItems = ["Pickup new mix-tape from Beth"]; const const todoShouldSwap: Ref<boolean, boolean>todoShouldSwap = ref<boolean>(value: boolean): Ref<boolean, boolean> (+1 overload)
Takes an inner value and returns a reactive and mutable ref object, which has a single property `.value` that points to the inner value.
@paramvalue - The object to wrap in the ref.@see{@link https://vuejs.org/api/reactivity-core.html#ref}
ref
(false);
const const doneShouldSwap: Ref<boolean, boolean>doneShouldSwap = ref<boolean>(value: boolean): Ref<boolean, boolean> (+1 overload)
Takes an inner value and returns a reactive and mutable ref object, which has a single property `.value` that points to the inner value.
@paramvalue - The object to wrap in the ref.@see{@link https://vuejs.org/api/reactivity-core.html#ref}
ref
(false);
const [const todoList: Ref<HTMLElement | undefined, HTMLElement | undefined>todoList, const todos: Ref<string[], string[]>todos] = useDragAndDrop<string>(initialValues: string[], options?: Partial<Partial<ParentConfig<string>>>): [Ref<HTMLElement | undefined, HTMLElement | undefined>, Ref<string[], string[]>, (config: Partial<Partial<ParentConfig<string>>>) => void]
Creates a new instance of drag and drop and returns the parent element and a ref of the values to use in your template.
@paraminitialValues - The initial values of the parent element.@returnsThe parent element and values for drag and drop.
useDragAndDrop
(const todoItems: string[]todoItems, {
group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "todoList",
plugins?: DNDPlugin[] | undefined
An array of functions to use for a given parent.
plugins
: [
insert<unknown>(insertConfig: InsertConfig<unknown>): (parent: HTMLElement) => {
    teardown(): void;
    setup(): void;
} | undefined
insert
({
InsertConfig<unknown>.insertPoint: (parent: ParentRecord<unknown>) => HTMLElementinsertPoint: (parent: ParentRecord<unknown>parent) => { const const div: HTMLDivElementdiv = var document: Document
**`window.document`** returns a reference to the document contained in the window. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)
document
.Document.createElement<"div">(tagName: "div", options?: ElementCreationOptions): HTMLDivElement (+2 overloads)
In an HTML document, the **`document.createElement()`** method creates the HTML element specified by localName, or an HTMLUnknownElement if localName isn't recognized. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Document/createElement)
createElement
("div");
for (const const cls: stringcls of const insertPointClasses: string[]insertPointClasses) const div: HTMLDivElementdiv.Element.classList: DOMTokenList
The read-only **`classList`** property of the Element interface contains a live DOMTokenList collection representing the class attribute of the element. This can then be used to manipulate the class list. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Element/classList)
classList
.DOMTokenList.add(...tokens: string[]): void
The **`add()`** method of the DOMTokenList interface adds the given tokens to the list, omitting any that are already present. [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMTokenList/add)
add
(const cls: stringcls);
return const div: HTMLDivElementdiv; }, }), ], }); const [const doneList: Ref<HTMLElement | undefined, HTMLElement | undefined>doneList, const dones: Ref<string[], string[]>dones] = useDragAndDrop<string>(initialValues: string[], options?: Partial<Partial<ParentConfig<string>>>): [Ref<HTMLElement | undefined, HTMLElement | undefined>, Ref<string[], string[]>, (config: Partial<Partial<ParentConfig<string>>>) => void]
Creates a new instance of drag and drop and returns the parent element and a ref of the values to use in your template.
@paraminitialValues - The initial values of the parent element.@returnsThe parent element and values for drag and drop.
useDragAndDrop
(const doneItems: string[]doneItems, {
group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "todoList",
plugins?: DNDPlugin[] | undefined
An array of functions to use for a given parent.
plugins
: [
insert<unknown>(insertConfig: InsertConfig<unknown>): (parent: HTMLElement) => {
    teardown(): void;
    setup(): void;
} | undefined
insert
({
InsertConfig<unknown>.insertPoint: (parent: ParentRecord<unknown>) => HTMLElementinsertPoint: (parent: ParentRecord<unknown>parent) => { const const div: HTMLDivElementdiv = var document: Document
**`window.document`** returns a reference to the document contained in the window. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)
document
.Document.createElement<"div">(tagName: "div", options?: ElementCreationOptions): HTMLDivElement (+2 overloads)
In an HTML document, the **`document.createElement()`** method creates the HTML element specified by localName, or an HTMLUnknownElement if localName isn't recognized. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Document/createElement)
createElement
("div");
for (const const cls: stringcls of const insertPointClasses: string[]insertPointClasses) const div: HTMLDivElementdiv.Element.classList: DOMTokenList
The read-only **`classList`** property of the Element interface contains a live DOMTokenList collection representing the class attribute of the element. This can then be used to manipulate the class list. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Element/classList)
classList
.DOMTokenList.add(...tokens: string[]): void
The **`add()`** method of the DOMTokenList interface adds the given tokens to the list, omitting any that are already present. [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMTokenList/add)
add
(const cls: stringcls);
return const div: HTMLDivElementdiv; }, }), ], }); function function toggleTodoSwap(): voidtoggleTodoSwap() { const todoShouldSwap: Ref<boolean, boolean>todoShouldSwap.Ref<boolean, boolean>.value: booleanvalue = !const todoShouldSwap: Ref<boolean, boolean>todoShouldSwap.Ref<boolean, boolean>.value: booleanvalue; } function function toggleDoneSwap(): voidtoggleDoneSwap() { const doneShouldSwap: Ref<boolean, boolean>doneShouldSwap.Ref<boolean, boolean>.value: booleanvalue = !const doneShouldSwap: Ref<boolean, boolean>doneShouldSwap.Ref<boolean, boolean>.value: booleanvalue; } </script> <template> <div: HTMLAttributes & ReservedPropsdiv HTMLAttributes.class?: ClassValueclass="kanban-board"> <ul: HTMLAttributes & ReservedPropsul ReservedProps.ref?: VNodeRef | undefinedref="todoList: HTMLUListElementtodoList" HTMLAttributes.class?: ClassValueclass="kanban-column"> <li: LiHTMLAttributes & ReservedPropsli v-for="const todo: stringtodo in const todos: Ref<string[], string[]>todos" ReservedProps.key?: PropertyKey | undefined:key="const todo: stringtodo" HTMLAttributes.class?: ClassValueclass="kanban-item"> {{ const todo: stringtodo }} </li: LiHTMLAttributes & ReservedPropsli> </ul: HTMLAttributes & ReservedPropsul> <div: HTMLAttributes & ReservedPropsdiv> <button: ButtonHTMLAttributes & ReservedPropsbutton @onClick?: ((payload: PointerEvent) => void) | undefinedclick="function toggleTodoSwap(): voidtoggleTodoSwap()" HTMLAttributes.class?: ClassValueclass="bg-indigo-500 text-white font-bold py-2 px-4 rounded-lg mt-4" > Toggle {{ const todoShouldSwap: Ref<boolean, boolean>todoShouldSwap ? "Drop" : "Swap" }} </button: ButtonHTMLAttributes & ReservedPropsbutton> </div: HTMLAttributes & ReservedPropsdiv> <ul: HTMLAttributes & ReservedPropsul ReservedProps.ref?: VNodeRef | undefinedref="doneList: HTMLUListElementdoneList" HTMLAttributes.class?: ClassValueclass="kanban-column"> <li: LiHTMLAttributes & ReservedPropsli v-for="const done: stringdone in const dones: Ref<string[], string[]>dones" ReservedProps.key?: PropertyKey | undefined:key="const done: stringdone" HTMLAttributes.class?: ClassValueclass="kanban-item"> {{ const done: stringdone }} </li: LiHTMLAttributes & ReservedPropsli> </ul: HTMLAttributes & ReservedPropsul> <div: HTMLAttributes & ReservedPropsdiv> <button: ButtonHTMLAttributes & ReservedPropsbutton @onClick?: ((payload: PointerEvent) => void) | undefinedclick="function toggleDoneSwap(): voidtoggleDoneSwap()" HTMLAttributes.class?: ClassValueclass="bg-indigo-500 text-white font-bold py-2 px-4 rounded-lg mt-4" > Toggle {{ const doneShouldSwap: Ref<boolean, boolean>doneShouldSwap ? "Drop" : "Swap" }} </button: ButtonHTMLAttributes & ReservedPropsbutton> </div: HTMLAttributes & ReservedPropsdiv> </div: HTMLAttributes & ReservedPropsdiv> </template>
/** @jsxImportSource solid-js */
import { function createSignal<T>(): Signal<T | undefined> (+1 overload)
Creates a simple reactive state with a getter and setter ```typescript const [state: Accessor<T>, setState: Setter<T>] = createSignal<T>( value: T, options?: { name?: string, equals?: false | ((prev: T, next: T) => boolean) } ) ```
@paramvalue initial value of the state; if empty, the state's type will automatically extended with undefined; otherwise you need to extend the type manually if you want setting to undefined not be an error@paramoptions optional object with a name for debugging purposes and equals, a comparator function for the previous and next value to allow fine-grained control over the reactivity@returns```typescript [state: Accessor<T>, setState: Setter<T>] ``` * the Accessor is merely a function that returns the current value and registers each call to the reactive root * the Setter is a function that allows directly setting or mutating the value: ```typescript const [count, setCount] = createSignal(0); setCount(count => count + 1); ```@descriptionhttps://docs.solidjs.com/reference/basic-reactivity/create-signal
createSignal
} from "solid-js";
import {
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
} from "solid-js";
import {
function insert<T>(insertConfig: InsertConfig<T>): (parent: HTMLElement) => {
    teardown(): void;
    setup(): void;
} | undefined
insert
} from "@formkit/drag-and-drop";
import { function useDragAndDrop<E extends HTMLElement, T = unknown>(initValues: T[], options?: Partial<ParentConfig<T>>): [Setter<E | null>, Accessor<Store<T[]>>, ReturnType<typeof createStore>[1], (config?: Partial<ParentConfig<T>>) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paraminitValues - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
} from "@formkit/drag-and-drop/solid";
const const insertPointClasses: string[]insertPointClasses = [ "absolute", "bg-blue-500", "z-[1000]", "rounded-full", "duration-[5ms]", "before:block", 'before:content-["Insert"]', "before:whitespace-nowrap", "before:block", "before:bg-blue-500", "before:py-1", "before:px-2", "before:rounded-full", "before:text-xs", "before:absolute", "before:top-1/2", "before:left-1/2", "before:-translate-y-1/2", "before:-translate-x-1/2", "before:text-white", "before:text-xs", ]; export function function MyComponent(): JSX.ElementMyComponent() { const const todoItems: string[]todoItems = [ "Schedule perm", "Rewind VHS tapes", "Make change for the arcade", "Get disposable camera developed", "Learn C++", "Return Nintendo Power Glove", ]; const [const todoSwap: Accessor<boolean>todoSwap, const setTodoSwap: Setter<boolean>setTodoSwap] = createSignal<boolean>(value: boolean, options?: SignalOptions<boolean> | undefined): Signal<boolean> (+1 overload)
Creates a simple reactive state with a getter and setter ```typescript const [state: Accessor<T>, setState: Setter<T>] = createSignal<T>( value: T, options?: { name?: string, equals?: false | ((prev: T, next: T) => boolean) } ) ```
@paramvalue initial value of the state; if empty, the state's type will automatically extended with undefined; otherwise you need to extend the type manually if you want setting to undefined not be an error@paramoptions optional object with a name for debugging purposes and equals, a comparator function for the previous and next value to allow fine-grained control over the reactivity@returns```typescript [state: Accessor<T>, setState: Setter<T>] ``` * the Accessor is merely a function that returns the current value and registers each call to the reactive root * the Setter is a function that allows directly setting or mutating the value: ```typescript const [count, setCount] = createSignal(0); setCount(count => count + 1); ```@descriptionhttps://docs.solidjs.com/reference/basic-reactivity/create-signal
createSignal
(false);
const [const doneSwap: Accessor<boolean>doneSwap, const setDoneSwap: Setter<boolean>setDoneSwap] = createSignal<boolean>(value: boolean, options?: SignalOptions<boolean> | undefined): Signal<boolean> (+1 overload)
Creates a simple reactive state with a getter and setter ```typescript const [state: Accessor<T>, setState: Setter<T>] = createSignal<T>( value: T, options?: { name?: string, equals?: false | ((prev: T, next: T) => boolean) } ) ```
@paramvalue initial value of the state; if empty, the state's type will automatically extended with undefined; otherwise you need to extend the type manually if you want setting to undefined not be an error@paramoptions optional object with a name for debugging purposes and equals, a comparator function for the previous and next value to allow fine-grained control over the reactivity@returns```typescript [state: Accessor<T>, setState: Setter<T>] ``` * the Accessor is merely a function that returns the current value and registers each call to the reactive root * the Setter is a function that allows directly setting or mutating the value: ```typescript const [count, setCount] = createSignal(0); setCount(count => count + 1); ```@descriptionhttps://docs.solidjs.com/reference/basic-reactivity/create-signal
createSignal
(false);
const const doneItems: string[]doneItems = ["Pickup new mix-tape from Beth"]; const [const todoList: Setter<HTMLUListElement | null>todoList, const todos: Accessor<string[]>todos] = useDragAndDrop<HTMLUListElement, string>(initValues: string[], options?: Partial<ParentConfig<string>>): [Setter<HTMLUListElement | null>, Accessor<string[]>, SetStoreFunction<string[]>, (config?: Partial<ParentConfig<string>> | undefined) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paraminitValues - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
<HTMLUListElement, string>(
const todoItems: string[]todoItems, { group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "todoList",
plugins?: DNDPlugin[] | undefined
An array of functions to use for a given parent.
plugins
: [
insert<unknown>(insertConfig: InsertConfig<unknown>): (parent: HTMLElement) => {
    teardown(): void;
    setup(): void;
} | undefined
insert
({
InsertConfig<unknown>.insertPoint: (parent: ParentRecord<unknown>) => HTMLElementinsertPoint: (parent: ParentRecord<unknown>parent) => { const const div: HTMLDivElementdiv = var document: Document
**`window.document`** returns a reference to the document contained in the window. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)
document
.Document.createElement<"div">(tagName: "div", options?: ElementCreationOptions): HTMLDivElement (+2 overloads)
In an HTML document, the **`document.createElement()`** method creates the HTML element specified by localName, or an HTMLUnknownElement if localName isn't recognized. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Document/createElement)
createElement
("div");
for (const const cls: stringcls of const insertPointClasses: string[]insertPointClasses) const div: HTMLDivElementdiv.Element.classList: DOMTokenList
The read-only **`classList`** property of the Element interface contains a live DOMTokenList collection representing the class attribute of the element. This can then be used to manipulate the class list. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Element/classList)
classList
.DOMTokenList.add(...tokens: string[]): void
The **`add()`** method of the DOMTokenList interface adds the given tokens to the list, omitting any that are already present. [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMTokenList/add)
add
(const cls: stringcls);
return const div: HTMLDivElementdiv; }, }), ], } ); const [const doneList: Setter<HTMLUListElement | null>doneList, const dones: Accessor<string[]>dones] = useDragAndDrop<HTMLUListElement, string>(initValues: string[], options?: Partial<ParentConfig<string>>): [Setter<HTMLUListElement | null>, Accessor<string[]>, SetStoreFunction<string[]>, (config?: Partial<ParentConfig<string>> | undefined) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paraminitValues - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
<HTMLUListElement, string>(
const doneItems: string[]doneItems, { group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "todoList",
plugins?: DNDPlugin[] | undefined
An array of functions to use for a given parent.
plugins
: [
insert<unknown>(insertConfig: InsertConfig<unknown>): (parent: HTMLElement) => {
    teardown(): void;
    setup(): void;
} | undefined
insert
({
InsertConfig<unknown>.insertPoint: (parent: ParentRecord<unknown>) => HTMLElementinsertPoint: (parent: ParentRecord<unknown>parent) => { const const div: HTMLDivElementdiv = var document: Document
**`window.document`** returns a reference to the document contained in the window. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)
document
.Document.createElement<"div">(tagName: "div", options?: ElementCreationOptions): HTMLDivElement (+2 overloads)
In an HTML document, the **`document.createElement()`** method creates the HTML element specified by localName, or an HTMLUnknownElement if localName isn't recognized. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Document/createElement)
createElement
("div");
for (const const cls: stringcls of const insertPointClasses: string[]insertPointClasses) const div: HTMLDivElementdiv.Element.classList: DOMTokenList
The read-only **`classList`** property of the Element interface contains a live DOMTokenList collection representing the class attribute of the element. This can then be used to manipulate the class list. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Element/classList)
classList
.DOMTokenList.add(...tokens: string[]): void
The **`add()`** method of the DOMTokenList interface adds the given tokens to the list, omitting any that are already present. [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMTokenList/add)
add
(const cls: stringcls);
return const div: HTMLDivElementdiv; }, }), ], } ); function function (local function) toggleTodoSwap(): voidtoggleTodoSwap() { const setTodoSwap: <boolean>(value: boolean | ((prev: boolean) => boolean)) => boolean (+3 overloads)setTodoSwap(!const todoSwap: () => booleantodoSwap()); } function function (local function) toggleDoneSwap(): voidtoggleDoneSwap() { const setDoneSwap: <boolean>(value: boolean | ((prev: boolean) => boolean)) => boolean (+3 overloads)setDoneSwap(!const doneSwap: () => booleandoneSwap()); } return ( <JSX.HTMLElementTags.div: JSX.HTMLAttributes<HTMLDivElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/div@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLDivElement
div
JSX.DOMAttributes<HTMLDivElement>.class?: string | undefinedclass="kanban-board">
<JSX.HTMLElementTags.ul: JSX.HTMLAttributes<HTMLUListElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLUListElement
ul
ref?: HTMLUListElement | ((el: HTMLUListElement) => void) | undefinedref={const todoList: Setter<HTMLUListElement | null>todoList}>
<
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
each: false | string[] | null | undefinedeach={const todos: () => string[]todos()}>
{(todo: stringtodo) => <JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
JSX.DOMAttributes<T>.class?: string | undefinedclass="kanban-item">{todo: stringtodo}</JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
>}
</
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
>
</JSX.HTMLElementTags.ul: JSX.HTMLAttributes<HTMLUListElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLUListElement
ul
>
<JSX.HTMLElementTags.ul: JSX.HTMLAttributes<HTMLUListElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLUListElement
ul
ref?: HTMLUListElement | ((el: HTMLUListElement) => void) | undefinedref={const doneList: Setter<HTMLUListElement | null>doneList}>
<
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
each: false | string[] | null | undefinedeach={const dones: () => string[]dones()}>
{(done: stringdone) => <JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
JSX.DOMAttributes<T>.class?: string | undefinedclass="kanban-item">{done: stringdone}</JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
>}
</
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
>
</JSX.HTMLElementTags.ul: JSX.HTMLAttributes<HTMLUListElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLUListElement
ul
>
</JSX.HTMLElementTags.div: JSX.HTMLAttributes<HTMLDivElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/div@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLDivElement
div
>
); }
import { function reactive<T>(effect: () => T): Computed<T> (+1 overload)
A reactive object is a proxy of the original object that allows for reactive dependency watching. It is created by calling `reactive()` and should be used to store reactive data in your app and components.
@paramdata - The data to make reactive, typically a plain object.@returnsA reactive proxy of the original data.
reactive
, function html(strings: TemplateStringsArray | string[], ...expSlots: ArrowExpression[]): ArrowTemplatehtml } from "@arrow-js/core";
import { function dragAndDrop<T>({ parent, getValues, setValues, config, }: DragAndDrop<T>): void
Initializes the drag and drop functionality for a given parent.
@paramdragAndDrop - The drag and drop configuration.@returnsvoid
dragAndDrop
,
function insert<T>(insertConfig: InsertConfig<T>): (parent: HTMLElement) => {
    teardown(): void;
    setup(): void;
} | undefined
insert
} from "@formkit/drag-and-drop";
const const insertPointClasses: string[]insertPointClasses = [ "absolute", "bg-blue-500", "z-[1000]", "rounded-full", "duration-[5ms]", "before:block", 'before:content-["Insert"]', "before:whitespace-nowrap", "before:block", "before:bg-blue-500", "before:py-1", "before:px-2", "before:rounded-full", "before:text-xs", "before:absolute", "before:top-1/2", "before:left-1/2", "before:-translate-y-1/2", "before:-translate-x-1/2", "before:text-white", "before:text-xs", ]; const
const state: Reactive<{
    todos: string[];
    dones: string[];
    todoSwap: boolean;
    doneSwap: boolean;
}>
state
=
reactive<{
    todos: string[];
    dones: string[];
    todoSwap: boolean;
    doneSwap: boolean;
}>(data: {
    todos: string[];
    dones: string[];
    todoSwap: boolean;
    doneSwap: boolean;
}): Reactive<{
    todos: string[];
    dones: string[];
    todoSwap: boolean;
    doneSwap: boolean;
}> (+1 overload)
A reactive object is a proxy of the original object that allows for reactive dependency watching. It is created by calling `reactive()` and should be used to store reactive data in your app and components.
@paramdata - The data to make reactive, typically a plain object.@returnsA reactive proxy of the original data.
reactive
({
todos: string[]todos: [ "Schedule perm", "Rewind VHS tapes", "Make change for the arcade", "Get disposable camera developed", "Learn C++", "Return Nintendo Power Glove", ], dones: string[]dones: ["Pickup new mix-tape from Beth"], todoSwap: booleantodoSwap: false, doneSwap: booleandoneSwap: false, }); dragAndDrop<string>({ parent, getValues, setValues, config, }: DragAndDrop<string>): void
Initializes the drag and drop functionality for a given parent.
@paramdragAndDrop - The drag and drop configuration.@returnsvoid
dragAndDrop
<string>({
DragAndDrop<string>.parent: HTMLElement
The parent element that will contain the draggable nodes.
parent
: var document: Document
**`window.document`** returns a reference to the document contained in the window. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)
document
.Document.getElementById(elementId: string): HTMLElement | null
The **`getElementById()`** method of the Document interface returns an Element object representing the element whose id property matches the specified string. Since element IDs are required to be unique if specified, they're a useful way to get access to a specific element quickly.
getElementById
("todo-list")!,
DragAndDrop<string>.getValues: (parent: HTMLElement) => string[]
A function that returns the values assigned to the parent.
getValues
: () =>
const state: Reactive<{
    todos: string[];
    dones: string[];
    todoSwap: boolean;
    doneSwap: boolean;
}>
state
.todos: string[] | Reactive<string[]>todos,
DragAndDrop<string>.setValues: (values: string[], parent: HTMLElement) => void
A function that sets the values assigned to the parent.
setValues
: (newValues: string[]newValues) => {
const state: Reactive<{
    todos: string[];
    dones: string[];
    todoSwap: boolean;
    doneSwap: boolean;
}>
state
.todos: string[] | Reactive<string[]>todos = reactive<string[]>(data: string[]): Reactive<string[]> (+1 overload)
A reactive object is a proxy of the original object that allows for reactive dependency watching. It is created by calling `reactive()` and should be used to store reactive data in your app and components.
@paramdata - The data to make reactive, typically a plain object.@returnsA reactive proxy of the original data.
reactive
(newValues: string[]newValues);
}, DragAndDrop<string>.config?: Partial<ParentConfig<string>> | undefined
An optional configuration object.
config
: {
group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "todoList",
plugins?: DNDPlugin[] | undefined
An array of functions to use for a given parent.
plugins
: [
insert<unknown>(insertConfig: InsertConfig<unknown>): (parent: HTMLElement) => {
    teardown(): void;
    setup(): void;
} | undefined
insert
({
InsertConfig<unknown>.insertPoint: (parent: ParentRecord<unknown>) => HTMLElementinsertPoint: (parent: ParentRecord<unknown>parent) => { const const div: HTMLDivElementdiv = var document: Document
**`window.document`** returns a reference to the document contained in the window. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)
document
.Document.createElement<"div">(tagName: "div", options?: ElementCreationOptions): HTMLDivElement (+2 overloads)
In an HTML document, the **`document.createElement()`** method creates the HTML element specified by localName, or an HTMLUnknownElement if localName isn't recognized. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Document/createElement)
createElement
("div");
for (const const cls: stringcls of const insertPointClasses: string[]insertPointClasses) const div: HTMLDivElementdiv.Element.classList: DOMTokenList
The read-only **`classList`** property of the Element interface contains a live DOMTokenList collection representing the class attribute of the element. This can then be used to manipulate the class list. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Element/classList)
classList
.DOMTokenList.add(...tokens: string[]): void
The **`add()`** method of the DOMTokenList interface adds the given tokens to the list, omitting any that are already present. [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMTokenList/add)
add
(const cls: stringcls);
return const div: HTMLDivElementdiv; }, }), ], }, }); dragAndDrop<string>({ parent, getValues, setValues, config, }: DragAndDrop<string>): void
Initializes the drag and drop functionality for a given parent.
@paramdragAndDrop - The drag and drop configuration.@returnsvoid
dragAndDrop
<string>({
DragAndDrop<string>.parent: HTMLElement
The parent element that will contain the draggable nodes.
parent
: var document: Document
**`window.document`** returns a reference to the document contained in the window. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)
document
.Document.getElementById(elementId: string): HTMLElement | null
The **`getElementById()`** method of the Document interface returns an Element object representing the element whose id property matches the specified string. Since element IDs are required to be unique if specified, they're a useful way to get access to a specific element quickly.
getElementById
("done-list")!,
DragAndDrop<string>.getValues: (parent: HTMLElement) => string[]
A function that returns the values assigned to the parent.
getValues
: () =>
const state: Reactive<{
    todos: string[];
    dones: string[];
    todoSwap: boolean;
    doneSwap: boolean;
}>
state
.dones: string[] | Reactive<string[]>dones,
DragAndDrop<string>.setValues: (values: string[], parent: HTMLElement) => void
A function that sets the values assigned to the parent.
setValues
: (newValues: string[]newValues) => {
const state: Reactive<{
    todos: string[];
    dones: string[];
    todoSwap: boolean;
    doneSwap: boolean;
}>
state
.dones: string[] | Reactive<string[]>dones = reactive<string[]>(data: string[]): Reactive<string[]> (+1 overload)
A reactive object is a proxy of the original object that allows for reactive dependency watching. It is created by calling `reactive()` and should be used to store reactive data in your app and components.
@paramdata - The data to make reactive, typically a plain object.@returnsA reactive proxy of the original data.
reactive
(newValues: string[]newValues);
}, DragAndDrop<string>.config?: Partial<ParentConfig<string>> | undefined
An optional configuration object.
config
: {
group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "todoList",
plugins?: DNDPlugin[] | undefined
An array of functions to use for a given parent.
plugins
: [
insert<unknown>(insertConfig: InsertConfig<unknown>): (parent: HTMLElement) => {
    teardown(): void;
    setup(): void;
} | undefined
insert
({
InsertConfig<unknown>.insertPoint: (parent: ParentRecord<unknown>) => HTMLElementinsertPoint: () => var document: Document
**`window.document`** returns a reference to the document contained in the window. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)
document
.Document.createElement<"div">(tagName: "div", options?: ElementCreationOptions): HTMLDivElement (+2 overloads)
In an HTML document, the **`document.createElement()`** method creates the HTML element specified by localName, or an HTMLUnknownElement if localName isn't recognized. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Document/createElement)
createElement
("div"),
}), ], }, }); function html(strings: TemplateStringsArray | string[], ...expSlots: ArrowExpression[]): ArrowTemplatehtml` <div class="kanban-board"> <ul class="kanban-list" id="todo-list"> ${() =>
const state: Reactive<{
    todos: string[];
    dones: string[];
    todoSwap: boolean;
    doneSwap: boolean;
}>
state
.todos: string[] | Reactive<string[]>todos.Array<T>.map<ArrowTemplate>(callbackfn: (value: string, index: number, array: string[]) => ArrowTemplate, thisArg?: any): ArrowTemplate[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
((todo: stringtodo) =>
function html(strings: TemplateStringsArray | string[], ...expSlots: ArrowExpression[]): ArrowTemplatehtml`<li class="kanban-item">${todo: stringtodo}</li>`.ArrowTemplate.key: (key: ArrowTemplateKey) => ArrowTemplatekey(todo: stringtodo) )} </ul> <ul class="kanban-list" id="done-list"> ${
const state: Reactive<{
    todos: string[];
    dones: string[];
    todoSwap: boolean;
    doneSwap: boolean;
}>
state
.dones: string[] | Reactive<string[]>dones.Array<T>.map<ArrowTemplate>(callbackfn: (value: string, index: number, array: string[]) => ArrowTemplate, thisArg?: any): ArrowTemplate[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
((done: stringdone) =>
function html(strings: TemplateStringsArray | string[], ...expSlots: ArrowExpression[]): ArrowTemplatehtml`<li class="kanban-item">${done: stringdone}</li>`.ArrowTemplate.key: (key: ArrowTemplateKey) => ArrowTemplatekey(done: stringdone) )} </ul> </div> `(var document: Document
**`window.document`** returns a reference to the document contained in the window. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)
document
.Document.getElementById(elementId: string): HTMLElement | null
The **`getElementById()`** method of the Document interface returns an Element object representing the element whose id property matches the specified string. Since element IDs are required to be unique if specified, they're a useful way to get access to a specific element quickly.
getElementById
("app")!);
import { insert } from "@formkit/drag-and-drop";

static const insertPointClasses = [
  "absolute",
  "bg-blue-500",
  "z-[1000]",
  "rounded-full",
  "duration-[5ms]",
  "before:block",
  'before:content-["Insert"]',
  "before:whitespace-nowrap",
  "before:block",
  "before:bg-blue-500",
  "before:py-1",
  "before:px-2",
  "before:rounded-full",
  "before:text-xs",
  "before:absolute",
  "before:top-1/2",
  "before:left-1/2",
  "before:-translate-y-1/2",
  "before:-translate-x-1/2",
  "before:text-white",
  "before:text-xs",
];

static function makeInsertPoint() {
  const div = document.createElement("div");
  for (const cls of insertPointClasses) div.classList.add(cls);
  return div;
}

static const todoItems = ["Schedule perm", "Rewind VHS tapes", "Make change for the arcade", "Get disposable camera developed", "Learn C++", "Return Nintendo Power Glove"];
static const doneItems = ["Pickup new mix-tape from Beth"];
static const config = {
  group: "todoList",
  plugins: [insert({ insertPoint: makeInsertPoint })],
};

<let/todos=todoItems>
<let/dones=doneItems>

<div class="kanban-board">
  <ul/todoList class="kanban-column">
    <for|todo| of=todos by=(t => t)>
      <li class="kanban-item">${todo}</li>
    </for>
  </ul>
  <ul/doneList class="kanban-column">
    <for|done| of=dones by=(t => t)>
      <li class="kanban-item">${done}</li>
    </for>
  </ul>
</div>

<dnd:=todos parent=todoList config=config/>
<dnd:=dones parent=doneList config=config/>

Animations (Experimenal)

To add animations to your drag and drop experience, you can use the animations plugin.

  • React
  • Vue
  • Solid
  • Native
  • Marko
import React from "react";
import { 
function animations(animationsConfig?: Partial<AnimationsConfig>): (parent: HTMLElement) => {
    setup(): void;
    setupNodeRemap<T>(data: SetupNodeData<T>): void;
} | undefined
animations
} from "@formkit/drag-and-drop";
import { function useDragAndDrop<E extends HTMLElement, T = unknown>(list: T[], options?: Partial<ParentConfig<T>>): [React.RefObject<E | null>, T[], React.Dispatch<React.SetStateAction<T[]>>, (config: Partial<ParentConfig<T>>) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paramlist - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
} from "@formkit/drag-and-drop/react";
export function function myComponent(): React.JSX.ElementmyComponent() { const [const parent: React.RefObject<HTMLUListElement | null>parent, const tapes: string[]tapes] = useDragAndDrop<HTMLUListElement, string>(list: string[], options?: Partial<ParentConfig<string>>): [React.RefObject<HTMLUListElement | null>, string[], React.Dispatch<React.SetStateAction<string[]>>, (config: Partial<ParentConfig<string>>) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paramlist - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
<HTMLUListElement, string>(
[ "Depeche Mode", "Duran Duran", "Pet Shop Boys", "Kraftwerk", "Tears for Fears", "Spandau Ballet", ], { plugins?: DNDPlugin[] | undefined
An array of functions to use for a given parent.
plugins
: [
function animations(animationsConfig?: Partial<AnimationsConfig>): (parent: HTMLElement) => {
    setup(): void;
    setupNodeRemap<T>(data: SetupNodeData<T>): void;
} | undefined
animations
()] }
); return ( <React.JSX.IntrinsicElements.ul: React.DetailedHTMLProps<React.HTMLAttributes<HTMLUListElement>, HTMLUListElement>ul React.RefAttributes<HTMLUListElement>.ref?: React.Ref<HTMLUListElement> | undefined
Allows getting a ref to the component instance. Once the component unmounts, React will set `ref.current` to `null` (or call the ref with `null` if you passed a callback ref).
@see{@link https://react.dev/learn/referencing-values-with-refs#refs-and-the-dom React Docs}
ref
={const parent: React.RefObject<HTMLUListElement | null>parent}>
{const tapes: string[]tapes.Array<string>.map<React.JSX.Element>(callbackfn: (value: string, index: number, array: string[]) => React.JSX.Element, thisArg?: any): React.JSX.Element[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
((tape: stringtape) => (
<React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li React.HTMLAttributes<HTMLLIElement>.className?: string | undefinedclassName="cassette" data-label: stringdata-label={tape: stringtape} React.Attributes.key?: React.Key | null | undefinedkey={tape: stringtape}> {tape: stringtape} </React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li> ))} </React.JSX.IntrinsicElements.ul: React.DetailedHTMLProps<React.HTMLAttributes<HTMLUListElement>, HTMLUListElement>ul> ); }
<script setup lang="ts">
import { 
function animations(animationsConfig?: Partial<AnimationsConfig>): (parent: HTMLElement) => {
    setup(): void;
    setupNodeRemap<T>(data: SetupNodeData<T>): void;
} | undefined
animations
} from "@formkit/drag-and-drop";
import { function useDragAndDrop<T>(initialValues: T[], options?: Partial<VueParentConfig<T>>): [Ref<HTMLElement | undefined>, Ref<T[]>, (config: Partial<VueParentConfig<T>>) => void]
Creates a new instance of drag and drop and returns the parent element and a ref of the values to use in your template.
@paraminitialValues - The initial values of the parent element.@returnsThe parent element and values for drag and drop.
useDragAndDrop
} from "@formkit/drag-and-drop/vue";
const [const parent: Ref<HTMLElement | undefined, HTMLElement | undefined>parent, const tapes: Ref<string[], string[]>tapes] = useDragAndDrop<string>(initialValues: string[], options?: Partial<Partial<ParentConfig<string>>>): [Ref<HTMLElement | undefined, HTMLElement | undefined>, Ref<string[], string[]>, (config: Partial<Partial<ParentConfig<string>>>) => void]
Creates a new instance of drag and drop and returns the parent element and a ref of the values to use in your template.
@paraminitialValues - The initial values of the parent element.@returnsThe parent element and values for drag and drop.
useDragAndDrop
(
[ "Depeche Mode", "Duran Duran", "Pet Shop Boys", "Kraftwerk", "Tears for Fears", "Spandau Ballet", ], { plugins?: DNDPlugin[] | undefined
An array of functions to use for a given parent.
plugins
: [
function animations(animationsConfig?: Partial<AnimationsConfig>): (parent: HTMLElement) => {
    setup(): void;
    setupNodeRemap<T>(data: SetupNodeData<T>): void;
} | undefined
animations
()] }
); </script> <template> <ul: HTMLAttributes & ReservedPropsul ReservedProps.ref?: VNodeRef | undefinedref="parent: HTMLUListElementparent"> <li: LiHTMLAttributes & ReservedPropsli v-for="const tape: stringtape in const tapes: Ref<string[], string[]>tapes" ReservedProps.key?: PropertyKey | undefined:key="const tape: stringtape" HTMLAttributes.class?: ClassValueclass="cassette"> {{ const tape: stringtape }} </li: LiHTMLAttributes & ReservedPropsli> </ul: HTMLAttributes & ReservedPropsul> </template>
/** @jsxImportSource solid-js */
import { 
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
} from "solid-js";
import {
function animations(animationsConfig?: Partial<AnimationsConfig>): (parent: HTMLElement) => {
    setup(): void;
    setupNodeRemap<T>(data: SetupNodeData<T>): void;
} | undefined
animations
} from "@formkit/drag-and-drop";
import { function useDragAndDrop<E extends HTMLElement, T = unknown>(initValues: T[], options?: Partial<ParentConfig<T>>): [Setter<E | null>, Accessor<Store<T[]>>, ReturnType<typeof createStore>[1], (config?: Partial<ParentConfig<T>>) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paraminitValues - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
} from "@formkit/drag-and-drop/solid";
export function function MyComponent(): JSX.ElementMyComponent() { const [const parent: Setter<HTMLUListElement | null>parent, const tapes: Accessor<string[]>tapes] = useDragAndDrop<HTMLUListElement, string>(initValues: string[], options?: Partial<ParentConfig<string>>): [Setter<HTMLUListElement | null>, Accessor<string[]>, SetStoreFunction<string[]>, (config?: Partial<ParentConfig<string>> | undefined) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paraminitValues - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
<HTMLUListElement, string>(
[ "Depeche Mode", "Duran Duran", "Pet Shop Boys", "Kraftwerk", "Tears for Fears", "Spandau Ballet", ], { plugins?: DNDPlugin[] | undefined
An array of functions to use for a given parent.
plugins
: [
function animations(animationsConfig?: Partial<AnimationsConfig>): (parent: HTMLElement) => {
    setup(): void;
    setupNodeRemap<T>(data: SetupNodeData<T>): void;
} | undefined
animations
()] }
); return ( <JSX.HTMLElementTags.ul: JSX.HTMLAttributes<HTMLUListElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLUListElement
ul
ref?: HTMLUListElement | ((el: HTMLUListElement) => void) | undefinedref={const parent: Setter<HTMLUListElement | null>parent}>
<
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
each: false | string[] | null | undefinedeach={const tapes: () => string[]tapes()}>
{(tape: stringtape) => ( <JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
JSX.DOMAttributes<HTMLLIElement>.class?: string | undefinedclass="cassette" data-label: stringdata-label={tape: stringtape}>
{tape: stringtape} </JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
>
)} </
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
>
</JSX.HTMLElementTags.ul: JSX.HTMLAttributes<HTMLUListElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLUListElement
ul
>
); }
import { function reactive<T>(effect: () => T): Computed<T> (+1 overload)
A reactive object is a proxy of the original object that allows for reactive dependency watching. It is created by calling `reactive()` and should be used to store reactive data in your app and components.
@paramdata - The data to make reactive, typically a plain object.@returnsA reactive proxy of the original data.
reactive
, function html(strings: TemplateStringsArray | string[], ...expSlots: ArrowExpression[]): ArrowTemplatehtml } from "@arrow-js/core";
import { function dragAndDrop<T>({ parent, getValues, setValues, config, }: DragAndDrop<T>): void
Initializes the drag and drop functionality for a given parent.
@paramdragAndDrop - The drag and drop configuration.@returnsvoid
dragAndDrop
,
function animations(animationsConfig?: Partial<AnimationsConfig>): (parent: HTMLElement) => {
    setup(): void;
    setupNodeRemap<T>(data: SetupNodeData<T>): void;
} | undefined
animations
} from "@formkit/drag-and-drop";
const
const state: Reactive<{
    tapes: string[];
}>
state
=
reactive<{
    tapes: string[];
}>(data: {
    tapes: string[];
}): Reactive<{
    tapes: string[];
}> (+1 overload)
A reactive object is a proxy of the original object that allows for reactive dependency watching. It is created by calling `reactive()` and should be used to store reactive data in your app and components.
@paramdata - The data to make reactive, typically a plain object.@returnsA reactive proxy of the original data.
reactive
({
tapes: string[]tapes: [ "Depeche Mode", "Duran Duran", "Pet Shop Boys", "Kraftwerk", "Tears for Fears", "Spandau Ballet", ], }); function html(strings: TemplateStringsArray | string[], ...expSlots: ArrowExpression[]): ArrowTemplatehtml` <ul id="cassettes"> ${() =>
const state: Reactive<{
    tapes: string[];
}>
state
.tapes: string[] | Reactive<string[]>tapes.Array<T>.map<ArrowTemplate>(callbackfn: (value: string, index: number, array: string[]) => ArrowTemplate, thisArg?: any): ArrowTemplate[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
((tape: stringtape) =>
function html(strings: TemplateStringsArray | string[], ...expSlots: ArrowExpression[]): ArrowTemplatehtml`<li class="cassette" data-label="${tape: stringtape}">${tape: stringtape}</li>`.ArrowTemplate.key: (key: ArrowTemplateKey) => ArrowTemplatekey(tape: stringtape) )} </ul> `(var document: Document
**`window.document`** returns a reference to the document contained in the window. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)
document
.Document.getElementById(elementId: string): HTMLElement | null
The **`getElementById()`** method of the Document interface returns an Element object representing the element whose id property matches the specified string. Since element IDs are required to be unique if specified, they're a useful way to get access to a specific element quickly.
getElementById
("app")!);
dragAndDrop<string>({ parent, getValues, setValues, config, }: DragAndDrop<string>): void
Initializes the drag and drop functionality for a given parent.
@paramdragAndDrop - The drag and drop configuration.@returnsvoid
dragAndDrop
<string>({
DragAndDrop<string>.parent: HTMLElement
The parent element that will contain the draggable nodes.
parent
: var document: Document
**`window.document`** returns a reference to the document contained in the window. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)
document
.Document.getElementById(elementId: string): HTMLElement | null
The **`getElementById()`** method of the Document interface returns an Element object representing the element whose id property matches the specified string. Since element IDs are required to be unique if specified, they're a useful way to get access to a specific element quickly.
getElementById
("cassettes")!,
DragAndDrop<string>.getValues: (parent: HTMLElement) => string[]
A function that returns the values assigned to the parent.
getValues
: () =>
const state: Reactive<{
    tapes: string[];
}>
state
.tapes: string[] | Reactive<string[]>tapes,
DragAndDrop<string>.setValues: (values: string[], parent: HTMLElement) => void
A function that sets the values assigned to the parent.
setValues
: (newValues: string[]newValues) => {
const state: Reactive<{
    tapes: string[];
}>
state
.tapes: string[] | Reactive<string[]>tapes = reactive<string[]>(data: string[]): Reactive<string[]> (+1 overload)
A reactive object is a proxy of the original object that allows for reactive dependency watching. It is created by calling `reactive()` and should be used to store reactive data in your app and components.
@paramdata - The data to make reactive, typically a plain object.@returnsA reactive proxy of the original data.
reactive
(newValues: string[]newValues);
}, DragAndDrop<string>.config?: Partial<ParentConfig<string>> | undefined
An optional configuration object.
config
: {
plugins?: DNDPlugin[] | undefined
An array of functions to use for a given parent.
plugins
: [
function animations(animationsConfig?: Partial<AnimationsConfig>): (parent: HTMLElement) => {
    setup(): void;
    setupNodeRemap<T>(data: SetupNodeData<T>): void;
} | undefined
animations
()],
}, });
import { animations } from "@formkit/drag-and-drop";

static const config = { plugins: [animations()] };

<let/tapes=[
  "Depeche Mode",
  "Duran Duran",
  "Pet Shop Boys",
  "Kraftwerk",
  "Tears for Fears",
  "Spandau Ballet",
]>

<ul/parent>
  <for|tape| of=tapes by=(t => t)>
    <li class="cassette">${tape}</li>
  </for>
</ul>

<dnd:=tapes parent=parent config=config/>

Events

When using a drag and drop library, often it is useful to be able to listen to particular events, such as when a drag starts or ends. Event listeners can be set at either a global level or at the parent level.

Global

Two global events are available, `dragStarted` and `dragEnded`. In order to listen to global events, import the state object from @formkit/drag-and-drop and register your event listener using the on method.

  • React
  • Vue
  • Solid
  • Native
  • Marko
import React from "react";
import { function useState<S>(initialState: S | (() => S)): [S, React.Dispatch<React.SetStateAction<S>>] (+1 overload)
Returns a stateful value, and a function to update it.
@version16.8.0@see{@link https://react.dev/reference/react/useState}
useState
} from "react";
import { let state: BaseDragState<unknown>
The state of the drag and drop.
@type{BaseDragState<unknown>}
state
} from "@formkit/drag-and-drop";
import { function useDragAndDrop<E extends HTMLElement, T = unknown>(list: T[], options?: Partial<ParentConfig<T>>): [React.RefObject<E | null>, T[], React.Dispatch<React.SetStateAction<T[]>>, (config: Partial<ParentConfig<T>>) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paramlist - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
} from "@formkit/drag-and-drop/react";
export function function App(): React.JSX.ElementApp() { const [const dragStatus: stringdragStatus, const setDragStatus: React.Dispatch<React.SetStateAction<string>>setDragStatus] = useState<string>(initialState: string | (() => string)): [string, React.Dispatch<React.SetStateAction<string>>] (+1 overload)
Returns a stateful value, and a function to update it.
@version16.8.0@see{@link https://react.dev/reference/react/useState}
useState
("Not dragging");
const [const parent: React.RefObject<HTMLUListElement | null>parent, const items: string[]items] = useDragAndDrop<HTMLUListElement, string>(list: string[], options?: Partial<ParentConfig<string>>): [React.RefObject<HTMLUListElement | null>, string[], React.Dispatch<React.SetStateAction<string[]>>, (config: Partial<ParentConfig<string>>) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paramlist - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
<HTMLUListElement, string>([
"🍦 vanilla", "🍫 chocolate", "🍓 strawberry", ]); let state: BaseDragState<unknown>
The state of the drag and drop.
@type{BaseDragState<unknown>}
state
.on: (event: string, callback: (data: unknown) => void) => voidon("dragStarted", () => const setDragStatus: (value: React.SetStateAction<string>) => voidsetDragStatus("Dragging"));
let state: BaseDragState<unknown>
The state of the drag and drop.
@type{BaseDragState<unknown>}
state
.on: (event: string, callback: (data: unknown) => void) => voidon("dragEnded", () => const setDragStatus: (value: React.SetStateAction<string>) => voidsetDragStatus("Not dragging"));
return ( <React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div> <React.JSX.IntrinsicElements.strong: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>strong>Rank your favorite flavors</React.JSX.IntrinsicElements.strong: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>strong> <React.JSX.IntrinsicElements.br: React.DetailedHTMLProps<React.HTMLAttributes<HTMLBRElement>, HTMLBRElement>br /> <React.JSX.IntrinsicElements.span: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>span>{const dragStatus: stringdragStatus}</React.JSX.IntrinsicElements.span: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>span> <React.JSX.IntrinsicElements.br: React.DetailedHTMLProps<React.HTMLAttributes<HTMLBRElement>, HTMLBRElement>br /> <React.JSX.IntrinsicElements.ul: React.DetailedHTMLProps<React.HTMLAttributes<HTMLUListElement>, HTMLUListElement>ul React.RefAttributes<HTMLUListElement>.ref?: React.Ref<HTMLUListElement> | undefined
Allows getting a ref to the component instance. Once the component unmounts, React will set `ref.current` to `null` (or call the ref with `null` if you passed a callback ref).
@see{@link https://react.dev/learn/referencing-values-with-refs#refs-and-the-dom React Docs}
ref
={const parent: React.RefObject<HTMLUListElement | null>parent}>
{const items: string[]items.Array<string>.map<React.JSX.Element>(callbackfn: (value: string, index: number, array: string[]) => React.JSX.Element, thisArg?: any): React.JSX.Element[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
((item: stringitem) => {
return <React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li React.Attributes.key?: React.Key | null | undefinedkey={item: stringitem}>{item: stringitem}</React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li>; })} </React.JSX.IntrinsicElements.ul: React.DetailedHTMLProps<React.HTMLAttributes<HTMLUListElement>, HTMLUListElement>ul> </React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div> ); }
<script setup lang="ts">
import { function ref<T>(value: T): [T] extends [Ref] ? IfAny<T, Ref<T>, T> : Ref<UnwrapRef<T>, UnwrapRef<T> | T> (+1 overload)
Takes an inner value and returns a reactive and mutable ref object, which has a single property `.value` that points to the inner value.
@paramvalue - The object to wrap in the ref.@see{@link https://vuejs.org/api/reactivity-core.html#ref}
ref
} from "vue";
import { let state: BaseDragState<unknown>
The state of the drag and drop.
@type{BaseDragState<unknown>}
state
} from "@formkit/drag-and-drop";
import { function useDragAndDrop<T>(initialValues: T[], options?: Partial<VueParentConfig<T>>): [Ref<HTMLElement | undefined>, Ref<T[]>, (config: Partial<VueParentConfig<T>>) => void]
Creates a new instance of drag and drop and returns the parent element and a ref of the values to use in your template.
@paraminitialValues - The initial values of the parent element.@returnsThe parent element and values for drag and drop.
useDragAndDrop
} from "@formkit/drag-and-drop/vue";
const const dragStatus: Ref<string, string>dragStatus = ref<string>(value: string): Ref<string, string> (+1 overload)
Takes an inner value and returns a reactive and mutable ref object, which has a single property `.value` that points to the inner value.
@paramvalue - The object to wrap in the ref.@see{@link https://vuejs.org/api/reactivity-core.html#ref}
ref
("Not dragging");
const [const parent: Ref<HTMLElement | undefined, HTMLElement | undefined>parent, const flavors: Ref<string[], string[]>flavors] = useDragAndDrop<string>(initialValues: string[], options?: Partial<Partial<ParentConfig<string>>>): [Ref<HTMLElement | undefined, HTMLElement | undefined>, Ref<string[], string[]>, (config: Partial<Partial<ParentConfig<string>>>) => void]
Creates a new instance of drag and drop and returns the parent element and a ref of the values to use in your template.
@paraminitialValues - The initial values of the parent element.@returnsThe parent element and values for drag and drop.
useDragAndDrop
([
"🍦 vanilla", "🍫 chocolate", "🍓 strawberry", ]); let state: BaseDragState<unknown>
The state of the drag and drop.
@type{BaseDragState<unknown>}
state
.on: (event: string, callback: (data: unknown) => void) => voidon("dragStarted", () => {
const dragStatus: Ref<string, string>dragStatus.Ref<string, string>.value: stringvalue = "Dragging"; }); let state: BaseDragState<unknown>
The state of the drag and drop.
@type{BaseDragState<unknown>}
state
.on: (event: string, callback: (data: unknown) => void) => voidon("dragEnded", () => {
const dragStatus: Ref<string, string>dragStatus.Ref<string, string>.value: stringvalue = "Not dragging"; }); </script> <template> <div: HTMLAttributes & ReservedPropsdiv HTMLAttributes.class?: ClassValueclass="border-4 p-4 border-indigo-300 dark:bg-slate-800 antialiased"> <div: HTMLAttributes & ReservedPropsdiv HTMLAttributes.class?: ClassValueclass="font-oldschool mb-4 text-lg md:text-xl lg:text-2xl"> <span: HTMLAttributes & ReservedPropsspan HTMLAttributes.class?: ClassValueclass="antialiased">=== Rank your favorite flavors ===</span: HTMLAttributes & ReservedPropsspan> <div: HTMLAttributes & ReservedPropsdiv>Drag status: {{ const dragStatus: Ref<string, string>dragStatus }}</div: HTMLAttributes & ReservedPropsdiv> </div: HTMLAttributes & ReservedPropsdiv> <div: HTMLAttributes & ReservedPropsdiv ReservedProps.ref?: VNodeRef | undefinedref="parent: HTMLDivElementparent" HTMLAttributes.class?: ClassValueclass="border-2 border-indigo-300 font-oldschool text-lg md:text-xl lg:text-2xl antialiased" > <div: HTMLAttributes & ReservedPropsdiv v-for="const flavor: stringflavor in const flavors: Ref<string[], string[]>flavors" ReservedProps.key?: PropertyKey | undefined:key="const flavor: stringflavor" HTMLAttributes.class?: ClassValueclass="border-2 border-indigo-300 p-2" > {{ const flavor: stringflavor }} </div: HTMLAttributes & ReservedPropsdiv> </div: HTMLAttributes & ReservedPropsdiv> </div: HTMLAttributes & ReservedPropsdiv> </template>
/** @jsxImportSource solid-js */
import { function createSignal<T>(): Signal<T | undefined> (+1 overload)
Creates a simple reactive state with a getter and setter ```typescript const [state: Accessor<T>, setState: Setter<T>] = createSignal<T>( value: T, options?: { name?: string, equals?: false | ((prev: T, next: T) => boolean) } ) ```
@paramvalue initial value of the state; if empty, the state's type will automatically extended with undefined; otherwise you need to extend the type manually if you want setting to undefined not be an error@paramoptions optional object with a name for debugging purposes and equals, a comparator function for the previous and next value to allow fine-grained control over the reactivity@returns```typescript [state: Accessor<T>, setState: Setter<T>] ``` * the Accessor is merely a function that returns the current value and registers each call to the reactive root * the Setter is a function that allows directly setting or mutating the value: ```typescript const [count, setCount] = createSignal(0); setCount(count => count + 1); ```@descriptionhttps://docs.solidjs.com/reference/basic-reactivity/create-signal
createSignal
} from "solid-js";
import {
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
} from "solid-js";
import { let state: BaseDragState<unknown>
The state of the drag and drop.
@type{BaseDragState<unknown>}
state
} from "@formkit/drag-and-drop";
import { function useDragAndDrop<E extends HTMLElement, T = unknown>(initValues: T[], options?: Partial<ParentConfig<T>>): [Setter<E | null>, Accessor<Store<T[]>>, ReturnType<typeof createStore>[1], (config?: Partial<ParentConfig<T>>) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paraminitValues - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
} from "@formkit/drag-and-drop/solid";
export function function App(): JSX.ElementApp() { const [const dragStatus: Accessor<string>dragStatus, const setDragStatus: Setter<string>setDragStatus] = createSignal<string>(value: string, options?: SignalOptions<string> | undefined): Signal<string> (+1 overload)
Creates a simple reactive state with a getter and setter ```typescript const [state: Accessor<T>, setState: Setter<T>] = createSignal<T>( value: T, options?: { name?: string, equals?: false | ((prev: T, next: T) => boolean) } ) ```
@paramvalue initial value of the state; if empty, the state's type will automatically extended with undefined; otherwise you need to extend the type manually if you want setting to undefined not be an error@paramoptions optional object with a name for debugging purposes and equals, a comparator function for the previous and next value to allow fine-grained control over the reactivity@returns```typescript [state: Accessor<T>, setState: Setter<T>] ``` * the Accessor is merely a function that returns the current value and registers each call to the reactive root * the Setter is a function that allows directly setting or mutating the value: ```typescript const [count, setCount] = createSignal(0); setCount(count => count + 1); ```@descriptionhttps://docs.solidjs.com/reference/basic-reactivity/create-signal
createSignal
("Not dragging");
const [const parent: Setter<HTMLUListElement | null>parent, const items: Accessor<string[]>items] = useDragAndDrop<HTMLUListElement, string>(initValues: string[], options?: Partial<ParentConfig<string>>): [Setter<HTMLUListElement | null>, Accessor<string[]>, SetStoreFunction<string[]>, (config?: Partial<ParentConfig<string>> | undefined) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paraminitValues - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
<HTMLUListElement, string>([
"🍦 vanilla", "🍫 chocolate", "🍓 strawberry", ]); const const onDragStarted: () => "Dragging"onDragStarted = () => const setDragStatus: <"Dragging">(value: "Dragging" | ((prev: string) => "Dragging")) => "Dragging" (+3 overloads)setDragStatus("Dragging"); const const onDragEnded: () => "Not dragging"onDragEnded = () => const setDragStatus: <"Not dragging">(value: "Not dragging" | ((prev: string) => "Not dragging")) => "Not dragging" (+3 overloads)setDragStatus("Not dragging"); let state: BaseDragState<unknown>
The state of the drag and drop.
@type{BaseDragState<unknown>}
state
.on: (event: string, callback: (data: unknown) => void) => voidon("dragStarted", const onDragStarted: () => "Dragging"onDragStarted);
let state: BaseDragState<unknown>
The state of the drag and drop.
@type{BaseDragState<unknown>}
state
.on: (event: string, callback: (data: unknown) => void) => voidon("dragEnded", const onDragEnded: () => "Not dragging"onDragEnded);
return ( <JSX.HTMLElementTags.div: JSX.HTMLAttributes<HTMLDivElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/div@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLDivElement
div
>
<JSX.HTMLElementTags.strong: JSX.HTMLAttributes<HTMLElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/strong@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLElement
strong
>Rank your favorite flavors</JSX.HTMLElementTags.strong: JSX.HTMLAttributes<HTMLElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/strong@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLElement
strong
>
<JSX.HTMLElementTags.br: JSX.HTMLAttributes<HTMLBRElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/br@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLBRElement
br
/>
<JSX.HTMLElementTags.span: JSX.HTMLAttributes<HTMLSpanElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/span@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLSpanElement
span
>{const dragStatus: () => stringdragStatus()}</JSX.HTMLElementTags.span: JSX.HTMLAttributes<HTMLSpanElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/span@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLSpanElement
span
>
<JSX.HTMLElementTags.br: JSX.HTMLAttributes<HTMLBRElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/br@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLBRElement
br
/>
<JSX.HTMLElementTags.ul: JSX.HTMLAttributes<HTMLUListElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLUListElement
ul
ref?: HTMLUListElement | ((el: HTMLUListElement) => void) | undefinedref={const parent: Setter<HTMLUListElement | null>parent}>
<
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
each: false | string[] | null | undefinedeach={const items: () => string[]items()}>{(item: stringitem) => <JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
>{item: stringitem}</JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
>}</
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
>
</JSX.HTMLElementTags.ul: JSX.HTMLAttributes<HTMLUListElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLUListElement
ul
>
</JSX.HTMLElementTags.div: JSX.HTMLAttributes<HTMLDivElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/div@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLDivElement
div
>
); }
import { function reactive<T>(effect: () => T): Computed<T> (+1 overload)
A reactive object is a proxy of the original object that allows for reactive dependency watching. It is created by calling `reactive()` and should be used to store reactive data in your app and components.
@paramdata - The data to make reactive, typically a plain object.@returnsA reactive proxy of the original data.
reactive
, function html(strings: TemplateStringsArray | string[], ...expSlots: ArrowExpression[]): ArrowTemplatehtml } from "@arrow-js/core";
import { function dragAndDrop<T>({ parent, getValues, setValues, config, }: DragAndDrop<T>): void
Initializes the drag and drop functionality for a given parent.
@paramdragAndDrop - The drag and drop configuration.@returnsvoid
dragAndDrop
, let state: BaseDragState<unknown>
The state of the drag and drop.
@type{BaseDragState<unknown>}
state
as let DNDState: BaseDragState<unknown>
The state of the drag and drop.
@type{BaseDragState<unknown>}
DNDState
} from "@formkit/drag-and-drop";
const
const state: Reactive<{
    items: string[];
    dragStatus: string;
}>
state
=
reactive<{
    items: string[];
    dragStatus: string;
}>(data: {
    items: string[];
    dragStatus: string;
}): Reactive<{
    items: string[];
    dragStatus: string;
}> (+1 overload)
A reactive object is a proxy of the original object that allows for reactive dependency watching. It is created by calling `reactive()` and should be used to store reactive data in your app and components.
@paramdata - The data to make reactive, typically a plain object.@returnsA reactive proxy of the original data.
reactive
({
items: string[]items: ["🍦 vanilla", "🍫 chocolate", "🍓 strawberry"], dragStatus: stringdragStatus: "Not dragging", }); function html(strings: TemplateStringsArray | string[], ...expSlots: ArrowExpression[]): ArrowTemplatehtml` <div> <strong>Rank your favorite flavors</strong> <span>${
const state: Reactive<{
    items: string[];
    dragStatus: string;
}>
state
.dragStatus: stringdragStatus}</span>
<ul id="list"> ${() =>
const state: Reactive<{
    items: string[];
    dragStatus: string;
}>
state
.items: string[] | Reactive<string[]>items.Array<T>.map<ArrowTemplate>(callbackfn: (value: string, index: number, array: string[]) => ArrowTemplate, thisArg?: any): ArrowTemplate[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
((item: stringitem) => function html(strings: TemplateStringsArray | string[], ...expSlots: ArrowExpression[]): ArrowTemplatehtml`<li>${item: stringitem}</li>`.ArrowTemplate.key: (key: ArrowTemplateKey) => ArrowTemplatekey(item: stringitem))}
</ul> </div> `(var document: Document
**`window.document`** returns a reference to the document contained in the window. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)
document
.Document.getElementById(elementId: string): HTMLElement | null
The **`getElementById()`** method of the Document interface returns an Element object representing the element whose id property matches the specified string. Since element IDs are required to be unique if specified, they're a useful way to get access to a specific element quickly.
getElementById
("app")!);
dragAndDrop<string>({ parent, getValues, setValues, config, }: DragAndDrop<string>): void
Initializes the drag and drop functionality for a given parent.
@paramdragAndDrop - The drag and drop configuration.@returnsvoid
dragAndDrop
<string>({
DragAndDrop<string>.parent: HTMLElement
The parent element that will contain the draggable nodes.
parent
: var document: Document
**`window.document`** returns a reference to the document contained in the window. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)
document
.Document.getElementById(elementId: string): HTMLElement | null
The **`getElementById()`** method of the Document interface returns an Element object representing the element whose id property matches the specified string. Since element IDs are required to be unique if specified, they're a useful way to get access to a specific element quickly.
getElementById
("list")!,
DragAndDrop<string>.getValues: (parent: HTMLElement) => string[]
A function that returns the values assigned to the parent.
getValues
: () =>
const state: Reactive<{
    items: string[];
    dragStatus: string;
}>
state
.items: string[] | Reactive<string[]>items,
DragAndDrop<string>.setValues: (values: string[], parent: HTMLElement) => void
A function that sets the values assigned to the parent.
setValues
: (newValues: string[]newValues) => {
const state: Reactive<{
    items: string[];
    dragStatus: string;
}>
state
.items: string[] | Reactive<string[]>items = reactive<string[]>(data: string[]): Reactive<string[]> (+1 overload)
A reactive object is a proxy of the original object that allows for reactive dependency watching. It is created by calling `reactive()` and should be used to store reactive data in your app and components.
@paramdata - The data to make reactive, typically a plain object.@returnsA reactive proxy of the original data.
reactive
(newValues: string[]newValues);
}, }); let DNDState: BaseDragState<unknown>
The state of the drag and drop.
@type{BaseDragState<unknown>}
DNDState
.on: (event: string, callback: (data: unknown) => void) => voidon("dragStarted", () => {
const state: Reactive<{
    items: string[];
    dragStatus: string;
}>
state
.dragStatus: stringdragStatus = "Dragging";
}); let DNDState: BaseDragState<unknown>
The state of the drag and drop.
@type{BaseDragState<unknown>}
DNDState
.on: (event: string, callback: (data: unknown) => void) => voidon("dragEnded", () => {
const state: Reactive<{
    items: string[];
    dragStatus: string;
}>
state
.dragStatus: stringdragStatus = "Not dragging";
});
client import { state } from "@formkit/drag-and-drop";

<let/flavors=["🍦 vanilla", "🍫 chocolate", "🍓 strawberry"]>
<let/dragStatus="Not dragging">

<lifecycle
  onMount() {
    state.on("dragStarted", () => { dragStatus = "Dragging"; });
    state.on("dragEnded", () => { dragStatus = "Not dragging"; });
  }
/>

<div class="border-4 p-4 border-indigo-300 dark:bg-slate-800 antialiased">
  <div class="font-oldschool mb-4 text-lg md:text-xl lg:text-2xl">
    <span class="antialiased">=== Rank your favorite flavors ===</span>
    <div>Drag status: ${dragStatus}</div>
  </div>
  <div/parent class="border-2 border-indigo-300 font-oldschool text-lg md:text-xl lg:text-2xl antialiased">
    <for|flavor| of=flavors by=(f => f)>
      <div class="border-2 border-indigo-300 p-2">${flavor}</div>
    </for>
  </div>
</div>

<dnd:=flavors parent=parent/>

Parent

Parents themselves have their own set of events that can be listened to. These events include: `onDragstart`, `onDragend`, `onSort`, `onTransfer`. To listen to parent events, assign a callback function to the event in the parent's configuration object.

  • React
  • Vue
  • Solid
  • Native
  • Marko
import React from "react";
import { function useState<S>(initialState: S | (() => S)): [S, React.Dispatch<React.SetStateAction<S>>] (+1 overload)
Returns a stateful value, and a function to update it.
@version16.8.0@see{@link https://react.dev/reference/react/useState}
useState
} from "react";
import { function useDragAndDrop<E extends HTMLElement, T = unknown>(list: T[], options?: Partial<ParentConfig<T>>): [React.RefObject<E | null>, T[], React.Dispatch<React.SetStateAction<T[]>>, (config: Partial<ParentConfig<T>>) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paramlist - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
} from "@formkit/drag-and-drop/react";
export function function App(): React.JSX.ElementApp() { const [const dragStatus: stringdragStatus, const setDragStatus: React.Dispatch<React.SetStateAction<string>>setDragStatus] = useState<string>(initialState: string | (() => string)): [string, React.Dispatch<React.SetStateAction<string>>] (+1 overload)
Returns a stateful value, and a function to update it.
@version16.8.0@see{@link https://react.dev/reference/react/useState}
useState
("Not dragging");
const [const valuesChanged: stringvaluesChanged, const setValuesChanged: React.Dispatch<React.SetStateAction<string>>setValuesChanged] = useState<string>(initialState: string | (() => string)): [string, React.Dispatch<React.SetStateAction<string>>] (+1 overload)
Returns a stateful value, and a function to update it.
@version16.8.0@see{@link https://react.dev/reference/react/useState}
useState
("Not sorting");
const [const parent: React.RefObject<HTMLUListElement | null>parent, const items: string[]items] = useDragAndDrop<HTMLUListElement, string>(list: string[], options?: Partial<ParentConfig<string>>): [React.RefObject<HTMLUListElement | null>, string[], React.Dispatch<React.SetStateAction<string[]>>, (config: Partial<ParentConfig<string>>) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paramlist - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
<HTMLUListElement, string>(
["🍦 vanilla", "🍫 chocolate", "🍓 strawberry"], { onDragstart?: DragstartEvent<string> | undefined
Fired when a drag is started, whether native drag or synthetic
onDragstart
: () => {
const setDragStatus: (value: React.SetStateAction<string>) => voidsetDragStatus("Dragging"); }, onDragend?: DragendEvent<string> | undefined
Fired when a drag is ended, whether native drag or synthetic
onDragend
: () => {
const setDragStatus: (value: React.SetStateAction<string>) => voidsetDragStatus("Not dragging"); const setValuesChanged: (value: React.SetStateAction<string>) => voidsetValuesChanged("Not sorting"); }, onSort?: SortEvent<string> | undefined
Callback function for when a sort operation is performed.
onSort
: (event: SortEventData<string>event) => {
const setValuesChanged: (value: React.SetStateAction<string>) => voidsetValuesChanged(`${event: SortEventData<string>event.SortEventData<string>.previousValues: string[]previousValues} -> ${event: SortEventData<string>event.SortEventData<string>.values: string[]values}`); }, } ); return ( <React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div> <React.JSX.IntrinsicElements.strong: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>strong>Rank your favorite flavors</React.JSX.IntrinsicElements.strong: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>strong> <React.JSX.IntrinsicElements.br: React.DetailedHTMLProps<React.HTMLAttributes<HTMLBRElement>, HTMLBRElement>br /> <React.JSX.IntrinsicElements.span: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>span>{const dragStatus: stringdragStatus}</React.JSX.IntrinsicElements.span: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>span> <React.JSX.IntrinsicElements.span: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>span>{const valuesChanged: stringvaluesChanged}</React.JSX.IntrinsicElements.span: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>span> <React.JSX.IntrinsicElements.br: React.DetailedHTMLProps<React.HTMLAttributes<HTMLBRElement>, HTMLBRElement>br /> <React.JSX.IntrinsicElements.ul: React.DetailedHTMLProps<React.HTMLAttributes<HTMLUListElement>, HTMLUListElement>ul React.RefAttributes<HTMLUListElement>.ref?: React.Ref<HTMLUListElement> | undefined
Allows getting a ref to the component instance. Once the component unmounts, React will set `ref.current` to `null` (or call the ref with `null` if you passed a callback ref).
@see{@link https://react.dev/learn/referencing-values-with-refs#refs-and-the-dom React Docs}
ref
={const parent: React.RefObject<HTMLUListElement | null>parent}>
{const items: string[]items.Array<string>.map<React.JSX.Element>(callbackfn: (value: string, index: number, array: string[]) => React.JSX.Element, thisArg?: any): React.JSX.Element[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
((item: stringitem) => {
return <React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li React.Attributes.key?: React.Key | null | undefinedkey={item: stringitem}>{item: stringitem}</React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li>; })} </React.JSX.IntrinsicElements.ul: React.DetailedHTMLProps<React.HTMLAttributes<HTMLUListElement>, HTMLUListElement>ul> </React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div> ); }
<script setup lang="ts">
import { function ref<T>(value: T): [T] extends [Ref] ? IfAny<T, Ref<T>, T> : Ref<UnwrapRef<T>, UnwrapRef<T> | T> (+1 overload)
Takes an inner value and returns a reactive and mutable ref object, which has a single property `.value` that points to the inner value.
@paramvalue - The object to wrap in the ref.@see{@link https://vuejs.org/api/reactivity-core.html#ref}
ref
} from "vue";
import { function useDragAndDrop<T>(initialValues: T[], options?: Partial<VueParentConfig<T>>): [Ref<HTMLElement | undefined>, Ref<T[]>, (config: Partial<VueParentConfig<T>>) => void]
Creates a new instance of drag and drop and returns the parent element and a ref of the values to use in your template.
@paraminitialValues - The initial values of the parent element.@returnsThe parent element and values for drag and drop.
useDragAndDrop
} from "@formkit/drag-and-drop/vue";
const const dragStatus: Ref<string, string>dragStatus = ref<string>(value: string): Ref<string, string> (+1 overload)
Takes an inner value and returns a reactive and mutable ref object, which has a single property `.value` that points to the inner value.
@paramvalue - The object to wrap in the ref.@see{@link https://vuejs.org/api/reactivity-core.html#ref}
ref
("Not dragging");
const const valuesChanged: Ref<string, string>valuesChanged = ref<string>(value: string): Ref<string, string> (+1 overload)
Takes an inner value and returns a reactive and mutable ref object, which has a single property `.value` that points to the inner value.
@paramvalue - The object to wrap in the ref.@see{@link https://vuejs.org/api/reactivity-core.html#ref}
ref
("Not sorting");
const [const parent: Ref<HTMLElement | undefined, HTMLElement | undefined>parent, const flavors: Ref<string[], string[]>flavors] = useDragAndDrop<string>(initialValues: string[], options?: Partial<Partial<ParentConfig<string>>>): [Ref<HTMLElement | undefined, HTMLElement | undefined>, Ref<string[], string[]>, (config: Partial<Partial<ParentConfig<string>>>) => void]
Creates a new instance of drag and drop and returns the parent element and a ref of the values to use in your template.
@paraminitialValues - The initial values of the parent element.@returnsThe parent element and values for drag and drop.
useDragAndDrop
(
["🍦 vanilla", "🍫 chocolate", "🍓 strawberry"], { onDragstart?: DragstartEvent<string> | undefined
Fired when a drag is started, whether native drag or synthetic
onDragstart
: () => {
const dragStatus: Ref<string, string>dragStatus.Ref<string, string>.value: stringvalue = "Dragging"; }, onDragend?: DragendEvent<string> | undefined
Fired when a drag is ended, whether native drag or synthetic
onDragend
: () => {
const dragStatus: Ref<string, string>dragStatus.Ref<string, string>.value: stringvalue = "Not dragging"; const valuesChanged: Ref<string, string>valuesChanged.Ref<string, string>.value: stringvalue = "Not sorting"; }, onSort?: SortEvent<string> | undefined
Callback function for when a sort operation is performed.
onSort
: (event: SortEventData<string>event) => {
const valuesChanged: Ref<string, string>valuesChanged.Ref<string, string>.value: stringvalue = `${event: SortEventData<string>event.SortEventData<string>.previousValues: string[]previousValues} -> ${event: SortEventData<string>event.SortEventData<string>.values: string[]values}`; }, } ); </script> <template> <div: HTMLAttributes & ReservedPropsdiv HTMLAttributes.class?: ClassValueclass="border-4 p-4 border-indigo-300 dark:bg-slate-800 antialiased"> <div: HTMLAttributes & ReservedPropsdiv HTMLAttributes.class?: ClassValueclass="font-oldschool mb-4 text-lg md:text-xl lg:text-2xl"> <span: HTMLAttributes & ReservedPropsspan HTMLAttributes.class?: ClassValueclass="antialiased">=== Rank your favorite flavors ===</span: HTMLAttributes & ReservedPropsspan> <div: HTMLAttributes & ReservedPropsdiv>Drag status: {{ const dragStatus: Ref<string, string>dragStatus }}</div: HTMLAttributes & ReservedPropsdiv> <div: HTMLAttributes & ReservedPropsdiv>Values changed: {{ const valuesChanged: Ref<string, string>valuesChanged }}</div: HTMLAttributes & ReservedPropsdiv> </div: HTMLAttributes & ReservedPropsdiv> <div: HTMLAttributes & ReservedPropsdiv ReservedProps.ref?: VNodeRef | undefinedref="parent: HTMLDivElementparent" HTMLAttributes.class?: ClassValueclass="border-2 border-indigo-300 font-oldschool text-lg md:text-xl lg:text-2xl antialiased" > <div: HTMLAttributes & ReservedPropsdiv v-for="const flavor: stringflavor in const flavors: Ref<string[], string[]>flavors" ReservedProps.key?: PropertyKey | undefined:key="const flavor: stringflavor" HTMLAttributes.class?: ClassValueclass="border-2 border-indigo-300 p-2" > {{ const flavor: stringflavor }} </div: HTMLAttributes & ReservedPropsdiv> </div: HTMLAttributes & ReservedPropsdiv> </div: HTMLAttributes & ReservedPropsdiv> </template>
/** @jsxImportSource solid-js */
// Start of Selection
import { function createSignal<T>(): Signal<T | undefined> (+1 overload)
Creates a simple reactive state with a getter and setter ```typescript const [state: Accessor<T>, setState: Setter<T>] = createSignal<T>( value: T, options?: { name?: string, equals?: false | ((prev: T, next: T) => boolean) } ) ```
@paramvalue initial value of the state; if empty, the state's type will automatically extended with undefined; otherwise you need to extend the type manually if you want setting to undefined not be an error@paramoptions optional object with a name for debugging purposes and equals, a comparator function for the previous and next value to allow fine-grained control over the reactivity@returns```typescript [state: Accessor<T>, setState: Setter<T>] ``` * the Accessor is merely a function that returns the current value and registers each call to the reactive root * the Setter is a function that allows directly setting or mutating the value: ```typescript const [count, setCount] = createSignal(0); setCount(count => count + 1); ```@descriptionhttps://docs.solidjs.com/reference/basic-reactivity/create-signal
createSignal
} from "solid-js";
import {
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
} from "solid-js";
import { function useDragAndDrop<E extends HTMLElement, T = unknown>(initValues: T[], options?: Partial<ParentConfig<T>>): [Setter<E | null>, Accessor<Store<T[]>>, ReturnType<typeof createStore>[1], (config?: Partial<ParentConfig<T>>) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paraminitValues - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
} from "@formkit/drag-and-drop/solid";
export function function App(): JSX.ElementApp() { const [const dragStatus: Accessor<string>dragStatus, const setDragStatus: Setter<string>setDragStatus] = createSignal<string>(value: string, options?: SignalOptions<string> | undefined): Signal<string> (+1 overload)
Creates a simple reactive state with a getter and setter ```typescript const [state: Accessor<T>, setState: Setter<T>] = createSignal<T>( value: T, options?: { name?: string, equals?: false | ((prev: T, next: T) => boolean) } ) ```
@paramvalue initial value of the state; if empty, the state's type will automatically extended with undefined; otherwise you need to extend the type manually if you want setting to undefined not be an error@paramoptions optional object with a name for debugging purposes and equals, a comparator function for the previous and next value to allow fine-grained control over the reactivity@returns```typescript [state: Accessor<T>, setState: Setter<T>] ``` * the Accessor is merely a function that returns the current value and registers each call to the reactive root * the Setter is a function that allows directly setting or mutating the value: ```typescript const [count, setCount] = createSignal(0); setCount(count => count + 1); ```@descriptionhttps://docs.solidjs.com/reference/basic-reactivity/create-signal
createSignal
("Not dragging");
const [const valuesChanged: Accessor<string>valuesChanged, const setValuesChanged: Setter<string>setValuesChanged] = createSignal<string>(value: string, options?: SignalOptions<string> | undefined): Signal<string> (+1 overload)
Creates a simple reactive state with a getter and setter ```typescript const [state: Accessor<T>, setState: Setter<T>] = createSignal<T>( value: T, options?: { name?: string, equals?: false | ((prev: T, next: T) => boolean) } ) ```
@paramvalue initial value of the state; if empty, the state's type will automatically extended with undefined; otherwise you need to extend the type manually if you want setting to undefined not be an error@paramoptions optional object with a name for debugging purposes and equals, a comparator function for the previous and next value to allow fine-grained control over the reactivity@returns```typescript [state: Accessor<T>, setState: Setter<T>] ``` * the Accessor is merely a function that returns the current value and registers each call to the reactive root * the Setter is a function that allows directly setting or mutating the value: ```typescript const [count, setCount] = createSignal(0); setCount(count => count + 1); ```@descriptionhttps://docs.solidjs.com/reference/basic-reactivity/create-signal
createSignal
("Not sorting");
const [const parent: Setter<HTMLUListElement | null>parent, const items: Accessor<string[]>items] = useDragAndDrop<HTMLUListElement, string>(initValues: string[], options?: Partial<ParentConfig<string>>): [Setter<HTMLUListElement | null>, Accessor<string[]>, SetStoreFunction<string[]>, (config?: Partial<ParentConfig<string>> | undefined) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paraminitValues - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
<HTMLUListElement, string>(
["🍦 vanilla", "🍫 chocolate", "🍓 strawberry"], { onDragstart?: DragstartEvent<string> | undefined
Fired when a drag is started, whether native drag or synthetic
onDragstart
: () => {
const setDragStatus: <"Dragging">(value: "Dragging" | ((prev: string) => "Dragging")) => "Dragging" (+3 overloads)setDragStatus("Dragging"); }, onDragend?: DragendEvent<string> | undefined
Fired when a drag is ended, whether native drag or synthetic
onDragend
: () => {
const setDragStatus: <"Not dragging">(value: "Not dragging" | ((prev: string) => "Not dragging")) => "Not dragging" (+3 overloads)setDragStatus("Not dragging"); const setValuesChanged: <"Not sorting">(value: "Not sorting" | ((prev: string) => "Not sorting")) => "Not sorting" (+3 overloads)setValuesChanged("Not sorting"); }, onSort?: SortEvent<string> | undefined
Callback function for when a sort operation is performed.
onSort
: (event: SortEventData<string>event) => {
const setValuesChanged: <`${string} -> ${string}`>(value: `${string} -> ${string}` | ((prev: string) => `${string} -> ${string}`)) => `${string} -> ${string}` (+3 overloads)setValuesChanged(`${event: SortEventData<string>event.SortEventData<string>.previousValues: string[]previousValues} -> ${event: SortEventData<string>event.SortEventData<string>.values: string[]values}`); }, } ); return ( <JSX.HTMLElementTags.div: JSX.HTMLAttributes<HTMLDivElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/div@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLDivElement
div
>
<JSX.HTMLElementTags.strong: JSX.HTMLAttributes<HTMLElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/strong@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLElement
strong
>Rank your favorite flavors</JSX.HTMLElementTags.strong: JSX.HTMLAttributes<HTMLElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/strong@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLElement
strong
>
<JSX.HTMLElementTags.br: JSX.HTMLAttributes<HTMLBRElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/br@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLBRElement
br
/>
<JSX.HTMLElementTags.span: JSX.HTMLAttributes<HTMLSpanElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/span@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLSpanElement
span
>{const dragStatus: () => stringdragStatus()}</JSX.HTMLElementTags.span: JSX.HTMLAttributes<HTMLSpanElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/span@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLSpanElement
span
>
<JSX.HTMLElementTags.span: JSX.HTMLAttributes<HTMLSpanElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/span@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLSpanElement
span
>{const valuesChanged: () => stringvaluesChanged()}</JSX.HTMLElementTags.span: JSX.HTMLAttributes<HTMLSpanElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/span@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLSpanElement
span
>
<JSX.HTMLElementTags.br: JSX.HTMLAttributes<HTMLBRElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/br@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLBRElement
br
/>
<JSX.HTMLElementTags.ul: JSX.HTMLAttributes<HTMLUListElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLUListElement
ul
ref?: HTMLUListElement | ((el: HTMLUListElement) => void) | undefinedref={const parent: Setter<HTMLUListElement | null>parent}>
<
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
each: false | string[] | null | undefinedeach={const items: () => string[]items()}>{(item: stringitem) => <JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
>{item: stringitem}</JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
>}</
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
>
</JSX.HTMLElementTags.ul: JSX.HTMLAttributes<HTMLUListElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLUListElement
ul
>
</JSX.HTMLElementTags.div: JSX.HTMLAttributes<HTMLDivElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/div@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLDivElement
div
>
); }
import { function reactive<T>(effect: () => T): Computed<T> (+1 overload)
A reactive object is a proxy of the original object that allows for reactive dependency watching. It is created by calling `reactive()` and should be used to store reactive data in your app and components.
@paramdata - The data to make reactive, typically a plain object.@returnsA reactive proxy of the original data.
reactive
, function html(strings: TemplateStringsArray | string[], ...expSlots: ArrowExpression[]): ArrowTemplatehtml } from "@arrow-js/core";
import { function dragAndDrop<T>({ parent, getValues, setValues, config, }: DragAndDrop<T>): void
Initializes the drag and drop functionality for a given parent.
@paramdragAndDrop - The drag and drop configuration.@returnsvoid
dragAndDrop
} from "@formkit/drag-and-drop";
const
const state: Reactive<{
    items: string[];
    dragStatus: string;
    valuesChanged: string;
}>
state
=
reactive<{
    items: string[];
    dragStatus: string;
    valuesChanged: string;
}>(data: {
    items: string[];
    dragStatus: string;
    valuesChanged: string;
}): Reactive<{
    items: string[];
    dragStatus: string;
    valuesChanged: string;
}> (+1 overload)
A reactive object is a proxy of the original object that allows for reactive dependency watching. It is created by calling `reactive()` and should be used to store reactive data in your app and components.
@paramdata - The data to make reactive, typically a plain object.@returnsA reactive proxy of the original data.
reactive
({
items: string[]items: ["🍦 vanilla", "🍫 chocolate", "🍓 strawberry"], dragStatus: stringdragStatus: "Not dragging", valuesChanged: stringvaluesChanged: "Not sorting", }); function html(strings: TemplateStringsArray | string[], ...expSlots: ArrowExpression[]): ArrowTemplatehtml` <div> <strong>Rank your favorite flavors</strong> <span>${
const state: Reactive<{
    items: string[];
    dragStatus: string;
    valuesChanged: string;
}>
state
.dragStatus: stringdragStatus}</span>
<ul id="list"> ${() =>
const state: Reactive<{
    items: string[];
    dragStatus: string;
    valuesChanged: string;
}>
state
.items: string[] | Reactive<string[]>items.Array<T>.map<ArrowTemplate>(callbackfn: (value: string, index: number, array: string[]) => ArrowTemplate, thisArg?: any): ArrowTemplate[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
((item: stringitem) => function html(strings: TemplateStringsArray | string[], ...expSlots: ArrowExpression[]): ArrowTemplatehtml`<li>${item: stringitem}</li>`.ArrowTemplate.key: (key: ArrowTemplateKey) => ArrowTemplatekey(item: stringitem))}
</ul> </div> `(var document: Document
**`window.document`** returns a reference to the document contained in the window. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)
document
.Document.getElementById(elementId: string): HTMLElement | null
The **`getElementById()`** method of the Document interface returns an Element object representing the element whose id property matches the specified string. Since element IDs are required to be unique if specified, they're a useful way to get access to a specific element quickly.
getElementById
("app")!);
dragAndDrop<string>({ parent, getValues, setValues, config, }: DragAndDrop<string>): void
Initializes the drag and drop functionality for a given parent.
@paramdragAndDrop - The drag and drop configuration.@returnsvoid
dragAndDrop
<string>({
DragAndDrop<string>.parent: HTMLElement
The parent element that will contain the draggable nodes.
parent
: var document: Document
**`window.document`** returns a reference to the document contained in the window. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)
document
.Document.getElementById(elementId: string): HTMLElement | null
The **`getElementById()`** method of the Document interface returns an Element object representing the element whose id property matches the specified string. Since element IDs are required to be unique if specified, they're a useful way to get access to a specific element quickly.
getElementById
("list")!,
DragAndDrop<string>.getValues: (parent: HTMLElement) => string[]
A function that returns the values assigned to the parent.
getValues
: () =>
const state: Reactive<{
    items: string[];
    dragStatus: string;
    valuesChanged: string;
}>
state
.items: string[] | Reactive<string[]>items,
DragAndDrop<string>.setValues: (values: string[], parent: HTMLElement) => void
A function that sets the values assigned to the parent.
setValues
: (newValues: string[]newValues) => {
const state: Reactive<{
    items: string[];
    dragStatus: string;
    valuesChanged: string;
}>
state
.items: string[] | Reactive<string[]>items = reactive<string[]>(data: string[]): Reactive<string[]> (+1 overload)
A reactive object is a proxy of the original object that allows for reactive dependency watching. It is created by calling `reactive()` and should be used to store reactive data in your app and components.
@paramdata - The data to make reactive, typically a plain object.@returnsA reactive proxy of the original data.
reactive
(newValues: string[]newValues);
}, DragAndDrop<string>.config?: Partial<ParentConfig<string>> | undefined
An optional configuration object.
config
: {
onDragstart?: DragstartEvent<string> | undefined
Fired when a drag is started, whether native drag or synthetic
onDragstart
: () => {
const state: Reactive<{
    items: string[];
    dragStatus: string;
    valuesChanged: string;
}>
state
.dragStatus: stringdragStatus = "Dragging";
}, onDragend?: DragendEvent<string> | undefined
Fired when a drag is ended, whether native drag or synthetic
onDragend
: () => {
const state: Reactive<{
    items: string[];
    dragStatus: string;
    valuesChanged: string;
}>
state
.dragStatus: stringdragStatus = "Not dragging";
const state: Reactive<{
    items: string[];
    dragStatus: string;
    valuesChanged: string;
}>
state
.valuesChanged: stringvaluesChanged = "Not sorting";
}, onSort?: SortEvent<string> | undefined
Callback function for when a sort operation is performed.
onSort
: (event: SortEventData<string>event) => {
const state: Reactive<{
    items: string[];
    dragStatus: string;
    valuesChanged: string;
}>
state
.valuesChanged: stringvaluesChanged = `${event: SortEventData<string>event.SortEventData<string>.previousValues: string[]previousValues} -> ${event: SortEventData<string>event.SortEventData<string>.values: string[]values}`;
}, }, });
<let/flavors=["🍦 vanilla", "🍫 chocolate", "🍓 strawberry"]>
<let/dragStatus="Not dragging">
<let/valuesChanged="Not sorting">
<let/config={
  onDragstart: () => { dragStatus = "Dragging"; },
  onDragend: () => { dragStatus = "Not dragging"; valuesChanged = "Not sorting"; },
  onSort: (event: any) => { valuesChanged = `${event.previousValues} -> ${event.values}`; },
}>

<div class="border-4 p-4 border-indigo-300 dark:bg-slate-800 antialiased">
  <div class="font-oldschool mb-4 text-lg md:text-xl lg:text-2xl">
    <span class="antialiased">=== Rank your favorite flavors ===</span>
    <div>Drag status: ${dragStatus}</div>
    <div>Values changed: ${valuesChanged}</div>
  </div>
  <div/parent class="border-2 border-indigo-300 font-oldschool text-lg md:text-xl lg:text-2xl antialiased">
    <for|flavor| of=flavors by=(f => f)>
      <div class="border-2 border-indigo-300 p-2">${flavor}</div>
    </for>
  </div>
</div>

<dnd:=flavors parent=parent config=config/>

Configuration

Each parent can be passed a configuration object. This object can be used to set options like group, drag handles, and or more dynamic options such as determining which direct descendants of a list are draggable. Invocation of useDragAndDrop or dragAndDrop can be used idempotently to update the configuration for a given list.

import type {
  interface ParentRecord<T>
The parent record, contains the el and the data in the `parents` weakmap.
ParentRecord
,
type DragState<T> = DragStateProps<T> & BaseDragState<T>DragState, interface NodeDragEventData<T>
The data passed to the node event listener when the event is a drag event.
NodeDragEventData
,
interface NodePointerEventData<T>
The data passed to the node event listener when the event is a pointer event (not a native drag event).
NodePointerEventData
,
interface NodeEventData<T>
The data passed to the node event listener.
NodeEventData
,
type DNDPlugin = (parent: HTMLElement) => DNDPluginData | undefinedDNDPlugin, interface PointeroverNodeEvent<T>
The payload of the custom event dispatched when a node is "touched" over a node.
PointeroverNodeEvent
,
type SetupNode = <T>(data: SetupNodeData<T>) => voidSetupNode, interface ParentEventData<T>
The data passed to the parent event listener.
@parame - The event that was triggered.@paramtargetData - The data of the target parent.
ParentEventData
,
type TearDownNode = <T>(data: TearDownNodeData<T>) => voidTearDownNode, interface PointeroverParentEvent<T>
The payload of the custom event dispatched when a node is "touched" over a parent.
PointeroverParentEvent
,
type SortEvent<T> = (data: SortEventData<T>) => voidSortEvent, type TransferEvent<T> = (data: TransferEventData<T>) => voidTransferEvent, type DragstartEvent<T> = (data: DragstartEventData<T>) => voidDragstartEvent, type DragendEvent<T> = (data: DragendEventData<T>) => voidDragendEvent, interface ParentDragEventData<T>ParentDragEventData,
type BaseDragState<T> = {
    activeState?: {
        node: NodeRecord<T>;
        parent: ParentRecord<T>;
    };
    affectedNodes: Array<NodeRecord<T>>;
    currentTargetValue: T | undefined;
    emit: (event: string, data: unknown) => void;
    on: (event: string, callback: (data: unknown) => void) => void;
    preventSynthDrag: boolean;
    longPress: boolean;
    longPressTimeout: ReturnType<typeof setTimeout> | undefined;
    pointerDown: {
        parent: ParentRecord<T>;
        node: NodeRecord<T>;
        validated: boolean;
    } | undefined;
    originalZIndex?: string;
    ... 17 more ...;
    frameIdY?: number;
}
BaseDragState
,
type NativeDragEffects = "link" | "none" | "copy" | "move"NativeDragEffects, interface NodeRecord<T>
The node record, contains the el and the data in the `nodes` weakmap.
NodeRecord
,
interface DropSwapConfig<T>DropSwapConfig, interface InsertConfig<T>InsertConfig, interface ParentData<T>
The data assigned to a given parent in the `parents` weakmap.
ParentData
,
interface ParentKeydownEventData<T>ParentKeydownEventData, type SynthDragState<T> = SynthDragStateProps & DragStateProps<T> & BaseDragState<T>
The state of the current drag. State is only created when a drag start event is triggered.
@paramactiveNode - The node that was most recently clicked (used optionally).@paramaffectedNodes - The nodes that will be updated by a drag action (sorted).@paramascendingDirection - Indicates whetehr the dragged node is moving to a node with a higher index or not.@paramclonedDraggedEls - The cloned elements of the dragged node. This is used primarily for TouchEvents or multi-drag purposes.@paramdraggedNode - The node that is being dragged.@paramdraggedNodes - The nodes that are being dragged.@paramincomingDirection - The direction that the dragged node is moving into a dragover node.@paraminitialParent - The parent that the dragged node was initially in.@paramcurrentParent - The parent that the dragged node was most recently in.@paramlastValue - The last value of the dragged node.@paramoriginalZIndex - The original z-index of the dragged node.@parampreventEnter - A flag to prevent a sort operation from firing until the mutation observer has had a chance to update the data of the remapped nodes.@paramswappedNodeValue - The value of the node that was swapped with the dragged node.@paramtargetIndex - The index of the node that the dragged node is moving into.
SynthDragState
,
} from "@formkit/drag-and-drop"; /** * The configuration object for a given parent. */ export interface interface ParentConfig<T>
The configuration object for a given parent.
ParentConfig
<function (type parameter) T in ParentConfig<T>T> {
/** * A function that returns whether a given parent accepts a given node. */ ParentConfig<T>.accepts?: ((targetParentData: ParentRecord<T>, initialParentData: ParentRecord<T>, currentParentData: ParentRecord<T>, state: BaseDragState<T>) => boolean) | undefined
A function that returns whether a given parent accepts a given node.
accepts
?: (
targetParentData: ParentRecord<T>targetParentData: interface ParentRecord<T>
The parent record, contains the el and the data in the `parents` weakmap.
ParentRecord
<function (type parameter) T in ParentConfig<T>T>,
initialParentData: ParentRecord<T>initialParentData: interface ParentRecord<T>
The parent record, contains the el and the data in the `parents` weakmap.
ParentRecord
<function (type parameter) T in ParentConfig<T>T>,
currentParentData: ParentRecord<T>currentParentData: interface ParentRecord<T>
The parent record, contains the el and the data in the `parents` weakmap.
ParentRecord
<function (type parameter) T in ParentConfig<T>T>,
state: BaseDragState<T>state:
type BaseDragState<T> = {
    activeState?: {
        node: NodeRecord<T>;
        parent: ParentRecord<T>;
    };
    affectedNodes: Array<NodeRecord<T>>;
    currentTargetValue: T | undefined;
    emit: (event: string, data: unknown) => void;
    on: (event: string, callback: (data: unknown) => void) => void;
    preventSynthDrag: boolean;
    longPress: boolean;
    longPressTimeout: ReturnType<typeof setTimeout> | undefined;
    pointerDown: {
        parent: ParentRecord<T>;
        node: NodeRecord<T>;
        validated: boolean;
    } | undefined;
    originalZIndex?: string;
    ... 17 more ...;
    frameIdY?: number;
}
BaseDragState
<function (type parameter) T in ParentConfig<T>T>
) => boolean; /** * The data transfer effect to use for the drag operation. */ ParentConfig<T>.dragEffectAllowed: NativeDragEffects
The data transfer effect to use for the drag operation.
dragEffectAllowed
: type NativeDragEffects = "link" | "none" | "copy" | "move"NativeDragEffects;
/** * The data transfer effect to use for the drag operation. */ ParentConfig<T>.dragDropEffect: NativeDragEffects
The data transfer effect to use for the drag operation.
dragDropEffect
: type NativeDragEffects = "link" | "none" | "copy" | "move"NativeDragEffects;
/** * A function that returns the image to use for the drag operation. This is * invoked for native operations. The clonedNode is what will be set as the drag * image, but this can be updated. */ ParentConfig<T>.dragImage?: ((data: NodeDragEventData<T>, draggedNodes: Array<NodeRecord<T>>) => HTMLElement) | undefined
A function that returns the image to use for the drag operation. This is invoked for native operations. The clonedNode is what will be set as the drag image, but this can be updated.
dragImage
?: (
data: NodeDragEventData<T>data: interface NodeDragEventData<T>
The data passed to the node event listener when the event is a drag event.
NodeDragEventData
<function (type parameter) T in ParentConfig<T>T>,
draggedNodes: NodeRecord<T>[]draggedNodes: interface Array<T>Array<interface NodeRecord<T>
The node record, contains the el and the data in the `nodes` weakmap.
NodeRecord
<function (type parameter) T in ParentConfig<T>T>>
) => HTMLElement; /** * A flag to disable dragability of all nodes in the parent. */ ParentConfig<T>.disabled?: boolean | undefined
A flag to disable dragability of all nodes in the parent.
disabled
?: boolean;
/** * A selector for the drag handle. Will search at any depth within the * draggable element. */ ParentConfig<T>.dragHandle?: string | undefined
A selector for the drag handle. Will search at any depth within the draggable element.
dragHandle
?: string;
/** * External drag handle */
ParentConfig<T>.externalDragHandle?: {
    el: HTMLElement;
    callback: () => HTMLElement;
} | undefined
External drag handle
externalDragHandle
?: {
el: HTMLElementel: HTMLElement; callback: () => HTMLElementcallback: () => HTMLElement; }; /** * A function that returns whether a given node is draggable. */ ParentConfig<T>.draggable?: ((child: HTMLElement) => boolean) | undefined
A function that returns whether a given node is draggable.
draggable
?: (child: HTMLElementchild: HTMLElement) => boolean;
/** * A function that returns whether a given value is draggable */ ParentConfig<T>.draggableValue?: ((values: T) => boolean) | undefined
A function that returns whether a given value is draggable
draggableValue
?: (values: Tvalues: function (type parameter) T in ParentConfig<T>T) => boolean;
ParentConfig<T>.draggedNodes: (pointerDown: {
    parent: ParentRecord<T>;
    node: NodeRecord<T>;
}) => Array<NodeRecord<T>>
draggedNodes
: (
pointerDown: {
    parent: ParentRecord<T>;
    node: NodeRecord<T>;
}
pointerDown
: {
parent: ParentRecord<T>parent: interface ParentRecord<T>
The parent record, contains the el and the data in the `parents` weakmap.
ParentRecord
<function (type parameter) T in ParentConfig<T>T>;
node: NodeRecord<T>node: interface NodeRecord<T>
The node record, contains the el and the data in the `nodes` weakmap.
NodeRecord
<function (type parameter) T in ParentConfig<T>T>;
}) => interface Array<T>Array<interface NodeRecord<T>
The node record, contains the el and the data in the `nodes` weakmap.
NodeRecord
<function (type parameter) T in ParentConfig<T>T>>;
/** * The class to add to a node when it is being dragged. */ ParentConfig<T>.draggingClass?: string | undefined
The class to add to a node when it is being dragged.
draggingClass
?: string;
/** * Accepts array of "dragged nodes" and applies dragstart classes to them. */ ParentConfig<T>.dragstartClasses: (node: NodeRecord<T>, nodes: Array<NodeRecord<T>>, config: ParentConfig<T>, isSynthDrag?: boolean) => void
Accepts array of "dragged nodes" and applies dragstart classes to them.
dragstartClasses
: (
node: NodeRecord<T>node: interface NodeRecord<T>
The node record, contains the el and the data in the `nodes` weakmap.
NodeRecord
<function (type parameter) T in ParentConfig<T>T>,
nodes: NodeRecord<T>[]nodes: interface Array<T>Array<interface NodeRecord<T>
The node record, contains the el and the data in the `nodes` weakmap.
NodeRecord
<function (type parameter) T in ParentConfig<T>T>>,
config: ParentConfig<T>config: interface ParentConfig<T>
The configuration object for a given parent.
ParentConfig
<function (type parameter) T in ParentConfig<T>T>,
isSynthDrag: boolean | undefinedisSynthDrag?: boolean ) => void; // When drag starts, this will be applied to the dragged node(s) (not their // representations being dragged) on dragstart. This will remain on the nodes // until the drag ends. ParentConfig<T>.dragPlaceholderClass?: string | undefineddragPlaceholderClass?: string; /** * The configuration object for the drop and swap plugin. */ ParentConfig<T>.dropSwapConfig?: DropSwapConfig<T> | undefined
The configuration object for the drop and swap plugin.
dropSwapConfig
?: interface DropSwapConfig<T>DropSwapConfig<function (type parameter) T in ParentConfig<T>T>;
/** * The class to add to a node when the node is dragged over it. */ ParentConfig<T>.dropZoneClass?: string | undefined
The class to add to a node when the node is dragged over it.
dropZoneClass
?: string;
/** * The class to add to a parent when it is dragged over. */ ParentConfig<T>.dropZoneParentClass?: string | undefined
The class to add to a parent when it is dragged over.
dropZoneParentClass
?: string;
/** * A flag to indicate whether the parent itself is a dropZone. */ ParentConfig<T>.dropZone?: boolean | undefined
A flag to indicate whether the parent itself is a dropZone.
dropZone
?: boolean;
/** * The group that the parent belongs to. This is used for allowing multiple * parents to transfer nodes between each other. */ ParentConfig<T>.group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
?: string;
ParentConfig<T>.handleParentFocus: (data: ParentEventData<T>, state: BaseDragState<T>) => voidhandleParentFocus: ( data: ParentEventData<T>data: interface ParentEventData<T>
The data passed to the parent event listener.
@parame - The event that was triggered.@paramtargetData - The data of the target parent.
ParentEventData
<function (type parameter) T in ParentConfig<T>T>,
state: BaseDragState<T>state:
type BaseDragState<T> = {
    activeState?: {
        node: NodeRecord<T>;
        parent: ParentRecord<T>;
    };
    affectedNodes: Array<NodeRecord<T>>;
    currentTargetValue: T | undefined;
    emit: (event: string, data: unknown) => void;
    on: (event: string, callback: (data: unknown) => void) => void;
    preventSynthDrag: boolean;
    longPress: boolean;
    longPressTimeout: ReturnType<typeof setTimeout> | undefined;
    pointerDown: {
        parent: ParentRecord<T>;
        node: NodeRecord<T>;
        validated: boolean;
    } | undefined;
    originalZIndex?: string;
    ... 17 more ...;
    frameIdY?: number;
}
BaseDragState
<function (type parameter) T in ParentConfig<T>T>
) => void; ParentConfig<T>.handleNodeKeydown: (data: NodeEventData<T>, state: DragState<T>) => voidhandleNodeKeydown: (data: NodeEventData<T>data: interface NodeEventData<T>
The data passed to the node event listener.
NodeEventData
<function (type parameter) T in ParentConfig<T>T>, state: DragState<T>state: type DragState<T> = DragStateProps<T> & BaseDragState<T>DragState<function (type parameter) T in ParentConfig<T>T>) => void;
/** * Function that is called when dragend or touchend event occurs. */ ParentConfig<T>.handleDragend: (data: NodeDragEventData<T>, state: DragState<T>) => void
Function that is called when dragend or touchend event occurs.
handleDragend
: (data: NodeDragEventData<T>data: interface NodeDragEventData<T>
The data passed to the node event listener when the event is a drag event.
NodeDragEventData
<function (type parameter) T in ParentConfig<T>T>, state: DragState<T>state: type DragState<T> = DragStateProps<T> & BaseDragState<T>DragState<function (type parameter) T in ParentConfig<T>T>) => void;
/** * Function that is called when dragstart event occurs. */ ParentConfig<T>.handleDragstart: (data: NodeDragEventData<T>, state: DragState<T>) => void
Function that is called when dragstart event occurs.
handleDragstart
: (data: NodeDragEventData<T>data: interface NodeDragEventData<T>
The data passed to the node event listener when the event is a drag event.
NodeDragEventData
<function (type parameter) T in ParentConfig<T>T>, state: DragState<T>state: type DragState<T> = DragStateProps<T> & BaseDragState<T>DragState<function (type parameter) T in ParentConfig<T>T>) => void;
ParentConfig<T>.handleEnd: (state: DragState<T> | SynthDragState<T>) => voidhandleEnd: (state: DragState<T> | SynthDragState<T>state: type DragState<T> = DragStateProps<T> & BaseDragState<T>DragState<function (type parameter) T in ParentConfig<T>T> | type SynthDragState<T> = SynthDragStateProps & DragStateProps<T> & BaseDragState<T>
The state of the current drag. State is only created when a drag start event is triggered.
@paramactiveNode - The node that was most recently clicked (used optionally).@paramaffectedNodes - The nodes that will be updated by a drag action (sorted).@paramascendingDirection - Indicates whetehr the dragged node is moving to a node with a higher index or not.@paramclonedDraggedEls - The cloned elements of the dragged node. This is used primarily for TouchEvents or multi-drag purposes.@paramdraggedNode - The node that is being dragged.@paramdraggedNodes - The nodes that are being dragged.@paramincomingDirection - The direction that the dragged node is moving into a dragover node.@paraminitialParent - The parent that the dragged node was initially in.@paramcurrentParent - The parent that the dragged node was most recently in.@paramlastValue - The last value of the dragged node.@paramoriginalZIndex - The original z-index of the dragged node.@parampreventEnter - A flag to prevent a sort operation from firing until the mutation observer has had a chance to update the data of the remapped nodes.@paramswappedNodeValue - The value of the node that was swapped with the dragged node.@paramtargetIndex - The index of the node that the dragged node is moving into.
SynthDragState
<function (type parameter) T in ParentConfig<T>T>) => void;
ParentConfig<T>.handleNodeDrop: (data: NodeDragEventData<T>, state: DragState<T>) => voidhandleNodeDrop: (data: NodeDragEventData<T>data: interface NodeDragEventData<T>
The data passed to the node event listener when the event is a drag event.
NodeDragEventData
<function (type parameter) T in ParentConfig<T>T>, state: DragState<T>state: type DragState<T> = DragStateProps<T> & BaseDragState<T>DragState<function (type parameter) T in ParentConfig<T>T>) => void;
ParentConfig<T>.handleNodePointerup: (data: NodePointerEventData<T>, state: DragState<T>) => voidhandleNodePointerup: ( data: NodePointerEventData<T>data: interface NodePointerEventData<T>
The data passed to the node event listener when the event is a pointer event (not a native drag event).
NodePointerEventData
<function (type parameter) T in ParentConfig<T>T>,
state: DragState<T>state: type DragState<T> = DragStateProps<T> & BaseDragState<T>DragState<function (type parameter) T in ParentConfig<T>T> ) => void; ParentConfig<T>.handleParentScroll: (data: ParentEventData<T>, state: DragState<T> | BaseDragState<T> | SynthDragState<T>) => voidhandleParentScroll: ( data: ParentEventData<T>data: interface ParentEventData<T>
The data passed to the parent event listener.
@parame - The event that was triggered.@paramtargetData - The data of the target parent.
ParentEventData
<function (type parameter) T in ParentConfig<T>T>,
state: BaseDragState<T> | DragState<T> | SynthDragState<T>state: type DragState<T> = DragStateProps<T> & BaseDragState<T>DragState<function (type parameter) T in ParentConfig<T>T> |
type BaseDragState<T> = {
    activeState?: {
        node: NodeRecord<T>;
        parent: ParentRecord<T>;
    };
    affectedNodes: Array<NodeRecord<T>>;
    currentTargetValue: T | undefined;
    emit: (event: string, data: unknown) => void;
    on: (event: string, callback: (data: unknown) => void) => void;
    preventSynthDrag: boolean;
    longPress: boolean;
    longPressTimeout: ReturnType<typeof setTimeout> | undefined;
    pointerDown: {
        parent: ParentRecord<T>;
        node: NodeRecord<T>;
        validated: boolean;
    } | undefined;
    originalZIndex?: string;
    ... 17 more ...;
    frameIdY?: number;
}
BaseDragState
<function (type parameter) T in ParentConfig<T>T> | type SynthDragState<T> = SynthDragStateProps & DragStateProps<T> & BaseDragState<T>
The state of the current drag. State is only created when a drag start event is triggered.
@paramactiveNode - The node that was most recently clicked (used optionally).@paramaffectedNodes - The nodes that will be updated by a drag action (sorted).@paramascendingDirection - Indicates whetehr the dragged node is moving to a node with a higher index or not.@paramclonedDraggedEls - The cloned elements of the dragged node. This is used primarily for TouchEvents or multi-drag purposes.@paramdraggedNode - The node that is being dragged.@paramdraggedNodes - The nodes that are being dragged.@paramincomingDirection - The direction that the dragged node is moving into a dragover node.@paraminitialParent - The parent that the dragged node was initially in.@paramcurrentParent - The parent that the dragged node was most recently in.@paramlastValue - The last value of the dragged node.@paramoriginalZIndex - The original z-index of the dragged node.@parampreventEnter - A flag to prevent a sort operation from firing until the mutation observer has had a chance to update the data of the remapped nodes.@paramswappedNodeValue - The value of the node that was swapped with the dragged node.@paramtargetIndex - The index of the node that the dragged node is moving into.
SynthDragState
<function (type parameter) T in ParentConfig<T>T>
) => void; /** * Function that is called when a dragenter event is triggered on the node. */ ParentConfig<T>.handleNodeDragenter: (data: NodeDragEventData<T>, state: DragState<T>) => void
Function that is called when a dragenter event is triggered on the node.
handleNodeDragenter
: (
data: NodeDragEventData<T>data: interface NodeDragEventData<T>
The data passed to the node event listener when the event is a drag event.
NodeDragEventData
<function (type parameter) T in ParentConfig<T>T>,
state: DragState<T>state: type DragState<T> = DragStateProps<T> & BaseDragState<T>DragState<function (type parameter) T in ParentConfig<T>T> ) => void; ParentConfig<T>.handleNodeBlur: (data: NodeEventData<T>, state: DragState<T>) => voidhandleNodeBlur: (data: NodeEventData<T>data: interface NodeEventData<T>
The data passed to the node event listener.
NodeEventData
<function (type parameter) T in ParentConfig<T>T>, state: DragState<T>state: type DragState<T> = DragStateProps<T> & BaseDragState<T>DragState<function (type parameter) T in ParentConfig<T>T>) => void;
ParentConfig<T>.handleNodeFocus: (data: NodeEventData<T>, state: DragState<T>) => voidhandleNodeFocus: (data: NodeEventData<T>data: interface NodeEventData<T>
The data passed to the node event listener.
NodeEventData
<function (type parameter) T in ParentConfig<T>T>, state: DragState<T>state: type DragState<T> = DragStateProps<T> & BaseDragState<T>DragState<function (type parameter) T in ParentConfig<T>T>) => void;
/** * Dragleave event on node */ ParentConfig<T>.handleNodeDragleave: (data: NodeDragEventData<T>, state: DragState<T>) => void
Dragleave event on node
handleNodeDragleave
: (
data: NodeDragEventData<T>data: interface NodeDragEventData<T>
The data passed to the node event listener when the event is a drag event.
NodeDragEventData
<function (type parameter) T in ParentConfig<T>T>,
state: DragState<T>state: type DragState<T> = DragStateProps<T> & BaseDragState<T>DragState<function (type parameter) T in ParentConfig<T>T> ) => void; /** * Function that is called when a dragover event is triggered on the parent. */ ParentConfig<T>.handleParentDragover: (data: ParentDragEventData<T>, state: DragState<T>) => void
Function that is called when a dragover event is triggered on the parent.
handleParentDragover
: (
data: ParentDragEventData<T>data: interface ParentDragEventData<T>ParentDragEventData<function (type parameter) T in ParentConfig<T>T>, state: DragState<T>state: type DragState<T> = DragStateProps<T> & BaseDragState<T>DragState<function (type parameter) T in ParentConfig<T>T> ) => void; /** * Drop event on parent */ ParentConfig<T>.handleParentDrop: (data: ParentDragEventData<T>, state: DragState<T>) => void
Drop event on parent
handleParentDrop
: (data: ParentDragEventData<T>data: interface ParentDragEventData<T>ParentDragEventData<function (type parameter) T in ParentConfig<T>T>, state: DragState<T>state: type DragState<T> = DragStateProps<T> & BaseDragState<T>DragState<function (type parameter) T in ParentConfig<T>T>) => void;
/** * Function that is called when a dragover event is triggered on a node. */ ParentConfig<T>.handleNodeDragover: (data: NodeDragEventData<T>, state: DragState<T>) => void
Function that is called when a dragover event is triggered on a node.
handleNodeDragover
: (data: NodeDragEventData<T>data: interface NodeDragEventData<T>
The data passed to the node event listener when the event is a drag event.
NodeDragEventData
<function (type parameter) T in ParentConfig<T>T>, state: DragState<T>state: type DragState<T> = DragStateProps<T> & BaseDragState<T>DragState<function (type parameter) T in ParentConfig<T>T>) => void;
ParentConfig<T>.handlePointercancel: (data: NodeDragEventData<T> | NodePointerEventData<T>, state: DragState<T> | SynthDragState<T> | BaseDragState<T>) => voidhandlePointercancel: ( data: NodeDragEventData<T> | NodePointerEventData<T>data: interface NodeDragEventData<T>
The data passed to the node event listener when the event is a drag event.
NodeDragEventData
<function (type parameter) T in ParentConfig<T>T> | interface NodePointerEventData<T>
The data passed to the node event listener when the event is a pointer event (not a native drag event).
NodePointerEventData
<function (type parameter) T in ParentConfig<T>T>,
state: BaseDragState<T> | DragState<T> | SynthDragState<T>state: type DragState<T> = DragStateProps<T> & BaseDragState<T>DragState<function (type parameter) T in ParentConfig<T>T> | type SynthDragState<T> = SynthDragStateProps & DragStateProps<T> & BaseDragState<T>
The state of the current drag. State is only created when a drag start event is triggered.
@paramactiveNode - The node that was most recently clicked (used optionally).@paramaffectedNodes - The nodes that will be updated by a drag action (sorted).@paramascendingDirection - Indicates whetehr the dragged node is moving to a node with a higher index or not.@paramclonedDraggedEls - The cloned elements of the dragged node. This is used primarily for TouchEvents or multi-drag purposes.@paramdraggedNode - The node that is being dragged.@paramdraggedNodes - The nodes that are being dragged.@paramincomingDirection - The direction that the dragged node is moving into a dragover node.@paraminitialParent - The parent that the dragged node was initially in.@paramcurrentParent - The parent that the dragged node was most recently in.@paramlastValue - The last value of the dragged node.@paramoriginalZIndex - The original z-index of the dragged node.@parampreventEnter - A flag to prevent a sort operation from firing until the mutation observer has had a chance to update the data of the remapped nodes.@paramswappedNodeValue - The value of the node that was swapped with the dragged node.@paramtargetIndex - The index of the node that the dragged node is moving into.
SynthDragState
<function (type parameter) T in ParentConfig<T>T> |
type BaseDragState<T> = {
    activeState?: {
        node: NodeRecord<T>;
        parent: ParentRecord<T>;
    };
    affectedNodes: Array<NodeRecord<T>>;
    currentTargetValue: T | undefined;
    emit: (event: string, data: unknown) => void;
    on: (event: string, callback: (data: unknown) => void) => void;
    preventSynthDrag: boolean;
    longPress: boolean;
    longPressTimeout: ReturnType<typeof setTimeout> | undefined;
    pointerDown: {
        parent: ParentRecord<T>;
        node: NodeRecord<T>;
        validated: boolean;
    } | undefined;
    originalZIndex?: string;
    ... 17 more ...;
    frameIdY?: number;
}
BaseDragState
<function (type parameter) T in ParentConfig<T>T>
) => void; /* * Function that is called when a pointerdown is triggered on node. */ ParentConfig<T>.handleNodePointerdown: (data: NodePointerEventData<T>, state: DragState<T>) => voidhandleNodePointerdown: ( data: NodePointerEventData<T>data: interface NodePointerEventData<T>
The data passed to the node event listener when the event is a pointer event (not a native drag event).
NodePointerEventData
<function (type parameter) T in ParentConfig<T>T>,
state: DragState<T>state: type DragState<T> = DragStateProps<T> & BaseDragState<T>DragState<function (type parameter) T in ParentConfig<T>T> ) => void; /** * Function that is called when a node that is being moved by touchmove event * is over a given node (similar to dragover). */ ParentConfig<T>.handleNodePointerover: (data: PointeroverNodeEvent<T>, state: SynthDragState<T>) => void
Function that is called when a node that is being moved by touchmove event is over a given node (similar to dragover).
handleNodePointerover
: (
data: PointeroverNodeEvent<T>data: interface PointeroverNodeEvent<T>
The payload of the custom event dispatched when a node is "touched" over a node.
PointeroverNodeEvent
<function (type parameter) T in ParentConfig<T>T>,
state: SynthDragState<T>state: type SynthDragState<T> = SynthDragStateProps & DragStateProps<T> & BaseDragState<T>
The state of the current drag. State is only created when a drag start event is triggered.
@paramactiveNode - The node that was most recently clicked (used optionally).@paramaffectedNodes - The nodes that will be updated by a drag action (sorted).@paramascendingDirection - Indicates whetehr the dragged node is moving to a node with a higher index or not.@paramclonedDraggedEls - The cloned elements of the dragged node. This is used primarily for TouchEvents or multi-drag purposes.@paramdraggedNode - The node that is being dragged.@paramdraggedNodes - The nodes that are being dragged.@paramincomingDirection - The direction that the dragged node is moving into a dragover node.@paraminitialParent - The parent that the dragged node was initially in.@paramcurrentParent - The parent that the dragged node was most recently in.@paramlastValue - The last value of the dragged node.@paramoriginalZIndex - The original z-index of the dragged node.@parampreventEnter - A flag to prevent a sort operation from firing until the mutation observer has had a chance to update the data of the remapped nodes.@paramswappedNodeValue - The value of the node that was swapped with the dragged node.@paramtargetIndex - The index of the node that the dragged node is moving into.
SynthDragState
<function (type parameter) T in ParentConfig<T>T>
) => void; /** * Function that is called when a node that is being moved by touchmove event * is over the parent (similar to dragover). */ ParentConfig<T>.handleParentPointerover: (e: PointeroverParentEvent<T>, state: SynthDragState<T>) => void
Function that is called when a node that is being moved by touchmove event is over the parent (similar to dragover).
handleParentPointerover
: (
e: PointeroverParentEvent<T>e: interface PointeroverParentEvent<T>
The payload of the custom event dispatched when a node is "touched" over a parent.
PointeroverParentEvent
<function (type parameter) T in ParentConfig<T>T>,
state: SynthDragState<T>state: type SynthDragState<T> = SynthDragStateProps & DragStateProps<T> & BaseDragState<T>
The state of the current drag. State is only created when a drag start event is triggered.
@paramactiveNode - The node that was most recently clicked (used optionally).@paramaffectedNodes - The nodes that will be updated by a drag action (sorted).@paramascendingDirection - Indicates whetehr the dragged node is moving to a node with a higher index or not.@paramclonedDraggedEls - The cloned elements of the dragged node. This is used primarily for TouchEvents or multi-drag purposes.@paramdraggedNode - The node that is being dragged.@paramdraggedNodes - The nodes that are being dragged.@paramincomingDirection - The direction that the dragged node is moving into a dragover node.@paraminitialParent - The parent that the dragged node was initially in.@paramcurrentParent - The parent that the dragged node was most recently in.@paramlastValue - The last value of the dragged node.@paramoriginalZIndex - The original z-index of the dragged node.@parampreventEnter - A flag to prevent a sort operation from firing until the mutation observer has had a chance to update the data of the remapped nodes.@paramswappedNodeValue - The value of the node that was swapped with the dragged node.@paramtargetIndex - The index of the node that the dragged node is moving into.
SynthDragState
<function (type parameter) T in ParentConfig<T>T>
) => void; /** * Config option for insert plugin. */ ParentConfig<T>.insertConfig?: InsertConfig<T> | undefined
Config option for insert plugin.
insertConfig
?: interface InsertConfig<T>InsertConfig<function (type parameter) T in ParentConfig<T>T>;
/** * A flag to indicate whether long touch is enabled. */ ParentConfig<T>.longPress?: boolean | undefined
A flag to indicate whether long touch is enabled.
longPress
?: boolean;
/** * The class to add to a node when a long touch action is performed. */ ParentConfig<T>.longPressClass?: string | undefined
The class to add to a node when a long touch action is performed.
longPressClass
?: string;
/** * The time in milliseconds to wait before a long touch is performed. */ ParentConfig<T>.longPressDuration?: number | undefined
The time in milliseconds to wait before a long touch is performed.
longPressDuration
?: number;
/** * The name of the parent (used for accepts function for increased specificity). */ ParentConfig<T>.name?: string | undefined
The name of the parent (used for accepts function for increased specificity).
name
?: string;
ParentConfig<T>.multiDrag?: boolean | undefinedmultiDrag?: boolean; /** * If set to false, the library will not use the native drag and drop API. */ ParentConfig<T>.nativeDrag?: boolean | undefined
If set to false, the library will not use the native drag and drop API.
nativeDrag
?: boolean;
/** * Function that is called when a sort operation is to be performed. */
ParentConfig<T>.performSort: ({ parent, draggedNodes, targetNodes, }: {
    parent: ParentRecord<T>;
    draggedNodes: Array<NodeRecord<T>>;
    targetNodes: Array<NodeRecord<T>>;
}) => void
Function that is called when a sort operation is to be performed.
performSort
: ({
parent: ParentRecord<T>parent, draggedNodes: NodeRecord<T>[]draggedNodes, targetNodes: NodeRecord<T>[]targetNodes, }: { parent: ParentRecord<T>parent: interface ParentRecord<T>
The parent record, contains the el and the data in the `parents` weakmap.
ParentRecord
<function (type parameter) T in ParentConfig<T>T>;
draggedNodes: NodeRecord<T>[]draggedNodes: interface Array<T>Array<interface NodeRecord<T>
The node record, contains the el and the data in the `nodes` weakmap.
NodeRecord
<function (type parameter) T in ParentConfig<T>T>>;
targetNodes: NodeRecord<T>[]targetNodes: interface Array<T>Array<interface NodeRecord<T>
The node record, contains the el and the data in the `nodes` weakmap.
NodeRecord
<function (type parameter) T in ParentConfig<T>T>>;
}) => void; /** * Function that is called when a transfer operation is to be performed. */
ParentConfig<T>.performTransfer: ({ currentParent, targetParent, initialParent, draggedNodes, initialIndex, state, targetNodes, }: {
    currentParent: ParentRecord<T>;
    targetParent: ParentRecord<T>;
    initialParent: ParentRecord<T>;
    draggedNodes: Array<NodeRecord<T>>;
    initialIndex: number;
    state: BaseDragState<T> | DragState<T> | SynthDragState<T>;
    targetNodes: Array<NodeRecord<T>>;
}) => void
Function that is called when a transfer operation is to be performed.
performTransfer
: ({
currentParent: ParentRecord<T>currentParent, targetParent: ParentRecord<T>targetParent, initialParent: ParentRecord<T>initialParent, draggedNodes: NodeRecord<T>[]draggedNodes, initialIndex: numberinitialIndex, state: BaseDragState<T> | DragState<T> | SynthDragState<T>state, targetNodes: NodeRecord<T>[]targetNodes, }: { currentParent: ParentRecord<T>currentParent: interface ParentRecord<T>
The parent record, contains the el and the data in the `parents` weakmap.
ParentRecord
<function (type parameter) T in ParentConfig<T>T>;
targetParent: ParentRecord<T>targetParent: interface ParentRecord<T>
The parent record, contains the el and the data in the `parents` weakmap.
ParentRecord
<function (type parameter) T in ParentConfig<T>T>;
initialParent: ParentRecord<T>initialParent: interface ParentRecord<T>
The parent record, contains the el and the data in the `parents` weakmap.
ParentRecord
<function (type parameter) T in ParentConfig<T>T>;
draggedNodes: NodeRecord<T>[]draggedNodes: interface Array<T>Array<interface NodeRecord<T>
The node record, contains the el and the data in the `nodes` weakmap.
NodeRecord
<function (type parameter) T in ParentConfig<T>T>>;
initialIndex: numberinitialIndex: number; state: BaseDragState<T> | DragState<T> | SynthDragState<T>state:
type BaseDragState<T> = {
    activeState?: {
        node: NodeRecord<T>;
        parent: ParentRecord<T>;
    };
    affectedNodes: Array<NodeRecord<T>>;
    currentTargetValue: T | undefined;
    emit: (event: string, data: unknown) => void;
    on: (event: string, callback: (data: unknown) => void) => void;
    preventSynthDrag: boolean;
    longPress: boolean;
    longPressTimeout: ReturnType<typeof setTimeout> | undefined;
    pointerDown: {
        parent: ParentRecord<T>;
        node: NodeRecord<T>;
        validated: boolean;
    } | undefined;
    originalZIndex?: string;
    ... 17 more ...;
    frameIdY?: number;
}
BaseDragState
<function (type parameter) T in ParentConfig<T>T> | type DragState<T> = DragStateProps<T> & BaseDragState<T>DragState<function (type parameter) T in ParentConfig<T>T> | type SynthDragState<T> = SynthDragStateProps & DragStateProps<T> & BaseDragState<T>
The state of the current drag. State is only created when a drag start event is triggered.
@paramactiveNode - The node that was most recently clicked (used optionally).@paramaffectedNodes - The nodes that will be updated by a drag action (sorted).@paramascendingDirection - Indicates whetehr the dragged node is moving to a node with a higher index or not.@paramclonedDraggedEls - The cloned elements of the dragged node. This is used primarily for TouchEvents or multi-drag purposes.@paramdraggedNode - The node that is being dragged.@paramdraggedNodes - The nodes that are being dragged.@paramincomingDirection - The direction that the dragged node is moving into a dragover node.@paraminitialParent - The parent that the dragged node was initially in.@paramcurrentParent - The parent that the dragged node was most recently in.@paramlastValue - The last value of the dragged node.@paramoriginalZIndex - The original z-index of the dragged node.@parampreventEnter - A flag to prevent a sort operation from firing until the mutation observer has had a chance to update the data of the remapped nodes.@paramswappedNodeValue - The value of the node that was swapped with the dragged node.@paramtargetIndex - The index of the node that the dragged node is moving into.
SynthDragState
<function (type parameter) T in ParentConfig<T>T>;
targetNodes: NodeRecord<T>[]targetNodes: interface Array<T>Array<interface NodeRecord<T>
The node record, contains the el and the data in the `nodes` weakmap.
NodeRecord
<function (type parameter) T in ParentConfig<T>T>>;
}) => void; /** * An array of functions to use for a given parent. */ ParentConfig<T>.plugins?: DNDPlugin[] | undefined
An array of functions to use for a given parent.
plugins
?: interface Array<T>Array<type DNDPlugin = (parent: HTMLElement) => DNDPluginData | undefinedDNDPlugin>;
/** * Takes a given node and reapplies the drag classes. */ ParentConfig<T>.reapplyDragClasses: (node: Node, parentData: ParentData<T>) => void
Takes a given node and reapplies the drag classes.
reapplyDragClasses
: (node: Nodenode: Node, parentData: ParentData<T>parentData: interface ParentData<T>
The data assigned to a given parent in the `parents` weakmap.
ParentData
<function (type parameter) T in ParentConfig<T>T>) => void;
/** * Invoked when the remapping of a given parent's nodes is finished. */ ParentConfig<T>.remapFinished: (data: ParentData<T>) => void
Invoked when the remapping of a given parent's nodes is finished.
remapFinished
: (data: ParentData<T>data: interface ParentData<T>
The data assigned to a given parent in the `parents` weakmap.
ParentData
<function (type parameter) T in ParentConfig<T>T>) => void;
/** * The root element to use for the parent. */ ParentConfig<T>.root: Document | ShadowRoot
The root element to use for the parent.
root
: Document | ShadowRoot;
/** * The class to add to a node when it is selected (clicked or pressed). */ ParentConfig<T>.selectedClass?: string | undefined
The class to add to a node when it is selected (clicked or pressed).
selectedClass
?: string;
/** * Function that is called when a node is set up. */ ParentConfig<T>.setupNode: SetupNode
Function that is called when a node is set up.
setupNode
: type SetupNode = <T>(data: SetupNodeData<T>) => voidSetupNode;
/** * Called when the value of the parent is changed and the nodes are remapped. */ ParentConfig<T>.setupNodeRemap: SetupNode
Called when the value of the parent is changed and the nodes are remapped.
setupNodeRemap
: type SetupNode = <T>(data: SetupNodeData<T>) => voidSetupNode;
/** * Flag for whether or not to allow sorting within a given parent. */ ParentConfig<T>.sortable?: boolean | undefined
Flag for whether or not to allow sorting within a given parent.
sortable
?: boolean;
/** * The class to add to a parent when it is dragged over. */ ParentConfig<T>.synthDropZoneParentClass?: string | undefined
The class to add to a parent when it is dragged over.
synthDropZoneParentClass
?: string;
/** * A function that returns the image to use for the drag operation. This is * invoked for synth drag operations operations. The clonedNode is what will * be set as the drag image, but this can be updated. */
ParentConfig<T>.synthDragImage?: ((node: NodeRecord<T>, parent: ParentRecord<T>, e: PointerEvent, draggedNodes: Array<NodeRecord<T>>) => {
    dragImage: HTMLElement;
    offsetX?: number;
    offsetY?: number;
}) | undefined
A function that returns the image to use for the drag operation. This is invoked for synth drag operations operations. The clonedNode is what will be set as the drag image, but this can be updated.
synthDragImage
?: (
node: NodeRecord<T>node: interface NodeRecord<T>
The node record, contains the el and the data in the `nodes` weakmap.
NodeRecord
<function (type parameter) T in ParentConfig<T>T>,
parent: ParentRecord<T>parent: interface ParentRecord<T>
The parent record, contains the el and the data in the `parents` weakmap.
ParentRecord
<function (type parameter) T in ParentConfig<T>T>,
e: PointerEvente: PointerEvent, draggedNodes: NodeRecord<T>[]draggedNodes: interface Array<T>Array<interface NodeRecord<T>
The node record, contains the el and the data in the `nodes` weakmap.
NodeRecord
<function (type parameter) T in ParentConfig<T>T>>
) => { dragImage: HTMLElementdragImage: HTMLElement; offsetX?: number | undefinedoffsetX?: number; offsetY?: number | undefinedoffsetY?: number; }; /** * Function that is called when a node is torn down. */ ParentConfig<T>.tearDownNode: TearDownNode
Function that is called when a node is torn down.
tearDownNode
: type TearDownNode = <T>(data: TearDownNodeData<T>) => voidTearDownNode;
/** * Called when the value of the parent is changed and the nodes are remapped. */ ParentConfig<T>.tearDownNodeRemap: TearDownNode
Called when the value of the parent is changed and the nodes are remapped.
tearDownNodeRemap
: type TearDownNode = <T>(data: TearDownNodeData<T>) => voidTearDownNode;
/** * Property to identify which group of tree descendants the current parent belongs to. */ /** * The threshold for a drag to be considered a valid sort * operation. */
ParentConfig<T>.threshold: {
    horizontal: number;
    vertical: number;
}
The threshold for a drag to be considered a valid sort operation.
threshold
: {
horizontal: numberhorizontal: number; vertical: numbervertical: number; }; /** * The class to add to a node when it is being synthetically dragged. */ ParentConfig<T>.synthDraggingClass?: string | undefined
The class to add to a node when it is being synthetically dragged.
synthDraggingClass
?: string;
/** * On synth drag start, this is applied to the dragged node(s) (not their * representations being dragged). */ ParentConfig<T>.synthDragPlaceholderClass?: string | undefined
On synth drag start, this is applied to the dragged node(s) (not their representations being dragged).
synthDragPlaceholderClass
?: string;
/** * When hovering over a node, this class is applied to the node. */ ParentConfig<T>.synthDropZoneClass?: string | undefined
When hovering over a node, this class is applied to the node.
synthDropZoneClass
?: string;
/** * Callback function for when a sort operation is performed. */ ParentConfig<T>.onSort?: SortEvent<T> | undefined
Callback function for when a sort operation is performed.
onSort
?: type SortEvent<T> = (data: SortEventData<T>) => voidSortEvent<function (type parameter) T in ParentConfig<T>T>;
/** * Callback function for when a transfer operation is performed. */ ParentConfig<T>.onTransfer?: TransferEvent<T> | undefined
Callback function for when a transfer operation is performed.
onTransfer
?: type TransferEvent<T> = (data: TransferEventData<T>) => voidTransferEvent<function (type parameter) T in ParentConfig<T>T>;
/** * Fired when a drag is started, whether native drag or synthetic */ ParentConfig<T>.onDragstart?: DragstartEvent<T> | undefined
Fired when a drag is started, whether native drag or synthetic
onDragstart
?: type DragstartEvent<T> = (data: DragstartEventData<T>) => voidDragstartEvent<function (type parameter) T in ParentConfig<T>T>;
/** * Fired when a drag is ended, whether native drag or synthetic */ ParentConfig<T>.onDragend?: DragendEvent<T> | undefined
Fired when a drag is ended, whether native drag or synthetic
onDragend
?: type DragendEvent<T> = (data: DragendEventData<T>) => voidDragendEvent<function (type parameter) T in ParentConfig<T>T>;
}

Accessibility

Below is an example of how to implement drag and drop lists with accessibility in mind.

  • React
  • Vue
  • Solid
  • Native
  • Marko
import React, { function useState<S>(initialState: S | (() => S)): [S, React.Dispatch<React.SetStateAction<S>>] (+1 overload)
Returns a stateful value, and a function to update it.
@version16.8.0@see{@link https://react.dev/reference/react/useState}
useState
, function useRef<T>(initialValue: T): React.RefObject<T> (+2 overloads)
`useRef` returns a mutable ref object whose `.current` property is initialized to the passed argument (`initialValue`). The returned object will persist for the full lifetime of the component. Note that `useRef()` is useful for more than the `ref` attribute. It’s handy for keeping any mutable value around similar to how you’d use instance fields in classes.
@version16.8.0@see{@link https://react.dev/reference/react/useRef}
useRef
, function useCallback<T extends Function>(callback: T, deps: React.DependencyList): T
`useCallback` will return a memoized version of the callback that only changes if one of the `inputs` has changed.
@version16.8.0@see{@link https://react.dev/reference/react/useCallback}
useCallback
, function useMemo<T>(factory: () => T, deps: React.DependencyList): T
`useMemo` will only recompute the memoized value when one of the `deps` has changed.
@version16.8.0@see{@link https://react.dev/reference/react/useMemo}
useMemo
} from "react";
import { function useDragAndDrop<E extends HTMLElement, T = unknown>(list: T[], options?: Partial<ParentConfig<T>>): [React.RefObject<E | null>, T[], React.Dispatch<React.SetStateAction<T[]>>, (config: Partial<ParentConfig<T>>) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paramlist - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
} from "@formkit/drag-and-drop/react";
// Initial data for the lists const const initialItems1: string[]initialItems1 = ["Apples", "Bananas", "Oranges", "Grapes"]; const const initialItems2: string[]initialItems2 = ["Milk", "Cheese", "Yogurt"]; interface SelectedItem { SelectedItem.listIndex: 0 | 1listIndex: 0 | 1; SelectedItem.itemIndex: numberitemIndex: number; SelectedItem.value: stringvalue: string; } export default function function AccessibilityDemoReact(): React.JSX.ElementAccessibilityDemoReact() { // Refs for ARIA Live region const [const liveMessage: stringliveMessage, const setLiveMessage: React.Dispatch<React.SetStateAction<string>>setLiveMessage] = useState<string>(initialState: string | (() => string)): [string, React.Dispatch<React.SetStateAction<string>>] (+1 overload)
Returns a stateful value, and a function to update it.
@version16.8.0@see{@link https://react.dev/reference/react/useState}
useState
("");
const const liveRegionRef: React.RefObject<HTMLDivElement | null>liveRegionRef = useRef<HTMLDivElement>(initialValue: HTMLDivElement | null): React.RefObject<HTMLDivElement | null> (+2 overloads)
`useRef` returns a mutable ref object whose `.current` property is initialized to the passed argument (`initialValue`). The returned object will persist for the full lifetime of the component. Note that `useRef()` is useful for more than the `ref` attribute. It’s handy for keeping any mutable value around similar to how you’d use instance fields in classes.
@version16.8.0@see{@link https://react.dev/reference/react/useRef}
useRef
<HTMLDivElement>(null);
// Function to update the live region const const announce: (message: string) => voidannounce = useCallback<(message: string) => void>(callback: (message: string) => void, deps: React.DependencyList): (message: string) => void
`useCallback` will return a memoized version of the callback that only changes if one of the `inputs` has changed.
@version16.8.0@see{@link https://react.dev/reference/react/useCallback}
useCallback
((message: stringmessage: string) => {
const setLiveMessage: (value: React.SetStateAction<string>) => voidsetLiveMessage(message: stringmessage); // Optional: Clear the message after a delay // const timer = setTimeout(() => setLiveMessage(''), 5000); // return () => clearTimeout(timer); }, []); // Setup drag and drop for List 1 const [const list1Ref: React.RefObject<HTMLUListElement | null>list1Ref, const items1: string[]items1, const setItems1: React.Dispatch<React.SetStateAction<string[]>>setItems1] = useDragAndDrop<HTMLUListElement, string>(list: string[], options?: Partial<ParentConfig<string>>): [React.RefObject<HTMLUListElement | null>, string[], React.Dispatch<React.SetStateAction<string[]>>, (config: Partial<ParentConfig<string>>) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paramlist - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
<
HTMLUListElement, string >(const initialItems1: string[]initialItems1, { group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "accessibleList",
// Let types be inferred onDragstart?: DragstartEvent<string> | undefined
Fired when a drag is started, whether native drag or synthetic
onDragstart
: (state: DragstartEventData<string>state) =>
const announce: (message: string) => voidannounce(`Drag started for ${state: DragstartEventData<string>state.DragstartEventData<string>.draggedNode: NodeRecord<string>draggedNode.NodeRecord<string>.data: NodeData<string>data.NodeData<string>.value: string
The value of the node.
value
}.`),
onSort?: SortEvent<string> | undefined
Callback function for when a sort operation is performed.
onSort
: (event: SortEventData<string>event) =>
const announce: (message: string) => voidannounce( `Sorted ${event: SortEventData<string>event.SortEventData<string>.draggedNodes: NodeRecord<string>[]draggedNodes[0].NodeRecord<string>.data: NodeData<string>data.NodeData<string>.value: string
The value of the node.
value
} in List 1 to position ${
event: SortEventData<string>event.SortEventData<string>.position: numberposition + 1 }.` ), onTransfer?: TransferEvent<string> | undefined
Callback function for when a transfer operation is performed.
onTransfer
: (event: TransferEventData<string>event) => {
const announce: (message: string) => voidannounce( `Transferred ${event: TransferEventData<string>event.TransferEventData<string>.draggedNodes: NodeRecord<string>[]draggedNodes[0].NodeRecord<string>.data: NodeData<string>data.NodeData<string>.value: string
The value of the node.
value
} from List ${
event: TransferEventData<string>event.TransferEventData<string>.sourceParent: ParentRecord<string>sourceParent.ParentRecord<string>.el: HTMLElementel === const list1Ref: React.RefObject<HTMLUListElement | null>list1Ref.React.RefObject<HTMLUListElement | null>.current: HTMLUListElement | null
The current value of the ref.
current
? 1 : 2
} to List 1 at position ${event: TransferEventData<string>event.TransferEventData<string>.targetIndex: numbertargetIndex + 1}.` ); }, onDragend?: DragendEvent<string> | undefined
Fired when a drag is ended, whether native drag or synthetic
onDragend
: (state: DragendEventData<string>state) =>
const announce: (message: string) => voidannounce(`Drag ended for ${state: DragendEventData<string>state.DragendEventData<string>.draggedNode: NodeRecord<string>draggedNode.NodeRecord<string>.data: NodeData<string>data.NodeData<string>.value: string
The value of the node.
value
}.`),
}); // Setup drag and drop for List 2 const [const list2Ref: React.RefObject<HTMLUListElement | null>list2Ref, const items2: string[]items2, const setItems2: React.Dispatch<React.SetStateAction<string[]>>setItems2] = useDragAndDrop<HTMLUListElement, string>(list: string[], options?: Partial<ParentConfig<string>>): [React.RefObject<HTMLUListElement | null>, string[], React.Dispatch<React.SetStateAction<string[]>>, (config: Partial<ParentConfig<string>>) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paramlist - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
<
HTMLUListElement, string >(const initialItems2: string[]initialItems2, { group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "accessibleList",
onDragstart?: DragstartEvent<string> | undefined
Fired when a drag is started, whether native drag or synthetic
onDragstart
: (state: DragstartEventData<string>state) =>
const announce: (message: string) => voidannounce(`Drag started for ${state: DragstartEventData<string>state.DragstartEventData<string>.draggedNode: NodeRecord<string>draggedNode.NodeRecord<string>.data: NodeData<string>data.NodeData<string>.value: string
The value of the node.
value
}.`),
onSort?: SortEvent<string> | undefined
Callback function for when a sort operation is performed.
onSort
: (event: SortEventData<string>event) =>
const announce: (message: string) => voidannounce( `Sorted ${event: SortEventData<string>event.SortEventData<string>.draggedNodes: NodeRecord<string>[]draggedNodes[0].NodeRecord<string>.data: NodeData<string>data.NodeData<string>.value: string
The value of the node.
value
} in List 2 to position ${
event: SortEventData<string>event.SortEventData<string>.position: numberposition + 1 }.` ), onTransfer?: TransferEvent<string> | undefined
Callback function for when a transfer operation is performed.
onTransfer
: (event: TransferEventData<string>event) => {
// Compare against element refs const announce: (message: string) => voidannounce( `Transferred ${event: TransferEventData<string>event.TransferEventData<string>.draggedNodes: NodeRecord<string>[]draggedNodes[0].NodeRecord<string>.data: NodeData<string>data.NodeData<string>.value: string
The value of the node.
value
} from List ${
event: TransferEventData<string>event.TransferEventData<string>.sourceParent: ParentRecord<string>sourceParent.ParentRecord<string>.el: HTMLElementel === const list1Ref: React.RefObject<HTMLUListElement | null>list1Ref.React.RefObject<HTMLUListElement | null>.current: HTMLUListElement | null
The current value of the ref.
current
? 1 : 2
} to List 2 at position ${event: TransferEventData<string>event.TransferEventData<string>.targetIndex: numbertargetIndex + 1}.` ); }, onDragend?: DragendEvent<string> | undefined
Fired when a drag is ended, whether native drag or synthetic
onDragend
: (state: DragendEventData<string>state) =>
const announce: (message: string) => voidannounce(`Drag ended for ${state: DragendEventData<string>state.DragendEventData<string>.draggedNode: NodeRecord<string>draggedNode.NodeRecord<string>.data: NodeData<string>data.NodeData<string>.value: string
The value of the node.
value
}.`),
}); // State for keyboard navigation const [const focusedListIndex: 0 | 1 | nullfocusedListIndex, const setFocusedListIndex: React.Dispatch<React.SetStateAction<0 | 1 | null>>setFocusedListIndex] = useState<0 | 1 | null>(initialState: 0 | 1 | (() => 0 | 1 | null) | null): [0 | 1 | null, React.Dispatch<React.SetStateAction<0 | 1 | null>>] (+1 overload)
Returns a stateful value, and a function to update it.
@version16.8.0@see{@link https://react.dev/reference/react/useState}
useState
<0 | 1 | null>(null);
const [const focusedItemIndex: number | nullfocusedItemIndex, const setFocusedItemIndex: React.Dispatch<React.SetStateAction<number | null>>setFocusedItemIndex] = useState<number | null>(initialState: number | (() => number | null) | null): [number | null, React.Dispatch<React.SetStateAction<number | null>>] (+1 overload)
Returns a stateful value, and a function to update it.
@version16.8.0@see{@link https://react.dev/reference/react/useState}
useState
<number | null>(null);
const [const selectedItem: SelectedItem | nullselectedItem, const setSelectedItem: React.Dispatch<React.SetStateAction<SelectedItem | null>>setSelectedItem] = useState<SelectedItem | null>(initialState: SelectedItem | (() => SelectedItem | null) | null): [SelectedItem | null, React.Dispatch<React.SetStateAction<SelectedItem | null>>] (+1 overload)
Returns a stateful value, and a function to update it.
@version16.8.0@see{@link https://react.dev/reference/react/useState}
useState
<SelectedItem | null>(null);
// Calculate focusedItemId directly const const focusedItemId: string | undefinedfocusedItemId = useMemo<string | undefined>(factory: () => string | undefined, deps: React.DependencyList): string | undefined
`useMemo` will only recompute the memoized value when one of the `deps` has changed.
@version16.8.0@see{@link https://react.dev/reference/react/useMemo}
useMemo
(() => {
if ( const focusedListIndex: 0 | 1 | nullfocusedListIndex === 0 && const focusedItemIndex: number | nullfocusedItemIndex !== null && const focusedItemIndex: numberfocusedItemIndex < const items1: string[]items1.Array<string>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
) { return `list1-item-${const items1: string[]items1[const focusedItemIndex: numberfocusedItemIndex]}`; } if ( const focusedListIndex: 0 | 1 | nullfocusedListIndex === 1 && const focusedItemIndex: number | nullfocusedItemIndex !== null && const focusedItemIndex: numberfocusedItemIndex < const items2: string[]items2.Array<string>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
) { return `list2-item-${const items2: string[]items2[const focusedItemIndex: numberfocusedItemIndex]}`; } return var undefinedundefined; }, [const focusedListIndex: 0 | 1 | nullfocusedListIndex, const focusedItemIndex: number | nullfocusedItemIndex, const items1: string[]items1, const items2: string[]items2]); const const handleListFocus: (listIndex: 0 | 1) => voidhandleListFocus = useCallback<(listIndex: 0 | 1) => void>(callback: (listIndex: 0 | 1) => void, deps: React.DependencyList): (listIndex: 0 | 1) => void
`useCallback` will return a memoized version of the callback that only changes if one of the `inputs` has changed.
@version16.8.0@see{@link https://react.dev/reference/react/useCallback}
useCallback
(
(listIndex: 0 | 1listIndex: 0 | 1) => { const setFocusedListIndex: (value: React.SetStateAction<0 | 1 | null>) => voidsetFocusedListIndex(listIndex: 0 | 1listIndex); const const currentItems: string[]currentItems = listIndex: 0 | 1listIndex === 0 ? const items1: string[]items1 : const items2: string[]items2; if (const focusedItemIndex: number | nullfocusedItemIndex === null && const currentItems: string[]currentItems.Array<string>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
> 0) {
const setFocusedItemIndex: (value: React.SetStateAction<number | null>) => voidsetFocusedItemIndex(0); } const announce: (message: string) => voidannounce( `List ${ listIndex: 0 | 1listIndex + 1 } focused. Use up and down arrows to navigate items.` ); }, [const items1: string[]items1, const items2: string[]items2, const announce: (message: string) => voidannounce, const focusedItemIndex: number | nullfocusedItemIndex] ); const const handleListBlur: () => voidhandleListBlur = useCallback<() => void>(callback: () => void, deps: React.DependencyList): () => void
`useCallback` will return a memoized version of the callback that only changes if one of the `inputs` has changed.
@version16.8.0@see{@link https://react.dev/reference/react/useCallback}
useCallback
(() => {
// Minimal blur handler - prevents immediate focus loss when clicking between elements // More complex logic might be needed for specific focus management scenarios }, []); const const handleListKeydown: (event: React.KeyboardEvent<HTMLUListElement>, listIndex: 0 | 1) => voidhandleListKeydown = useCallback<(event: React.KeyboardEvent<HTMLUListElement>, listIndex: 0 | 1) => void>(callback: (event: React.KeyboardEvent<HTMLUListElement>, listIndex: 0 | 1) => void, deps: React.DependencyList): (event: React.KeyboardEvent<HTMLUListElement>, listIndex: 0 | 1) => void
`useCallback` will return a memoized version of the callback that only changes if one of the `inputs` has changed.
@version16.8.0@see{@link https://react.dev/reference/react/useCallback}
useCallback
(
(event: React.KeyboardEvent<HTMLUListElement>event: React.interface React.KeyboardEvent<T = Element>KeyboardEvent<HTMLUListElement>, listIndex: 0 | 1listIndex: 0 | 1) => { if (const focusedListIndex: 0 | 1 | nullfocusedListIndex !== listIndex: 0 | 1listIndex) return; const const currentItems: string[]currentItems = listIndex: 0 | 1listIndex === 0 ? const items1: string[]items1 : const items2: string[]items2; const const setItems: React.Dispatch<React.SetStateAction<string[]>>setItems = listIndex: 0 | 1listIndex === 0 ? const setItems1: React.Dispatch<React.SetStateAction<string[]>>setItems1 : const setItems2: React.Dispatch<React.SetStateAction<string[]>>setItems2; const const currentItemIndex: number | nullcurrentItemIndex = const focusedItemIndex: number | nullfocusedItemIndex; switch (event: React.KeyboardEvent<HTMLUListElement>event.React.KeyboardEvent<HTMLUListElement>.key: string
See the [DOM Level 3 Events spec](https://www.w3.org/TR/uievents-key/#named-key-attribute-values). for possible values
key
) {
case "ArrowDown": event: React.KeyboardEvent<HTMLUListElement>event.React.BaseSyntheticEvent<KeyboardEvent, EventTarget & HTMLUListElement, EventTarget>.preventDefault(): voidpreventDefault(); if (const currentItems: string[]currentItems.Array<string>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
> 0) {
const const nextIndex: numbernextIndex = const currentItemIndex: number | nullcurrentItemIndex === null ? 0 : (const currentItemIndex: numbercurrentItemIndex + 1) % const currentItems: string[]currentItems.Array<string>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
;
const setFocusedItemIndex: (value: React.SetStateAction<number | null>) => voidsetFocusedItemIndex(const nextIndex: numbernextIndex); const announce: (message: string) => voidannounce(const currentItems: string[]currentItems[const nextIndex: numbernextIndex]); } break; case "ArrowUp": event: React.KeyboardEvent<HTMLUListElement>event.React.BaseSyntheticEvent<KeyboardEvent, EventTarget & HTMLUListElement, EventTarget>.preventDefault(): voidpreventDefault(); if (const currentItems: string[]currentItems.Array<string>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
> 0) {
const const prevIndex: numberprevIndex = const currentItemIndex: number | nullcurrentItemIndex === null ? const currentItems: string[]currentItems.Array<string>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
- 1
: (const currentItemIndex: numbercurrentItemIndex - 1 + const currentItems: string[]currentItems.Array<string>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
) %
const currentItems: string[]currentItems.Array<string>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
;
const setFocusedItemIndex: (value: React.SetStateAction<number | null>) => voidsetFocusedItemIndex(const prevIndex: numberprevIndex); const announce: (message: string) => voidannounce(const currentItems: string[]currentItems[const prevIndex: numberprevIndex]); } break; case " ": // Spacebar event: React.KeyboardEvent<HTMLUListElement>event.React.BaseSyntheticEvent<KeyboardEvent, EventTarget & HTMLUListElement, EventTarget>.preventDefault(): voidpreventDefault(); if ( const currentItemIndex: number | nullcurrentItemIndex !== null && const currentItemIndex: numbercurrentItemIndex >= 0 && const currentItemIndex: numbercurrentItemIndex < const currentItems: string[]currentItems.Array<string>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
) { const const currentItemValue: stringcurrentItemValue = const currentItems: string[]currentItems[const currentItemIndex: numbercurrentItemIndex]; if ( const selectedItem: SelectedItem | nullselectedItem?.SelectedItem.listIndex: 0 | 1 | undefinedlistIndex === listIndex: 0 | 1listIndex && const selectedItem: SelectedItemselectedItem?.SelectedItem.itemIndex: numberitemIndex === const currentItemIndex: numbercurrentItemIndex ) { const setSelectedItem: (value: React.SetStateAction<SelectedItem | null>) => voidsetSelectedItem(null); const announce: (message: string) => voidannounce(`${const currentItemValue: stringcurrentItemValue} deselected.`); } else { const setSelectedItem: (value: React.SetStateAction<SelectedItem | null>) => voidsetSelectedItem({ SelectedItem.listIndex: 0 | 1listIndex, SelectedItem.itemIndex: numberitemIndex: const currentItemIndex: numbercurrentItemIndex, SelectedItem.value: stringvalue: const currentItemValue: stringcurrentItemValue, }); const announce: (message: string) => voidannounce( `${const currentItemValue: stringcurrentItemValue} selected. Use arrow keys to choose drop position, then press Enter.` ); } } break; case "Enter": event: React.KeyboardEvent<HTMLUListElement>event.React.BaseSyntheticEvent<KeyboardEvent, EventTarget & HTMLUListElement, EventTarget>.preventDefault(): voidpreventDefault(); if ( const selectedItem: SelectedItem | nullselectedItem && const currentItemIndex: number | nullcurrentItemIndex !== null && const currentItemIndex: numbercurrentItemIndex >= 0 && const currentItemIndex: numbercurrentItemIndex < const currentItems: string[]currentItems.Array<string>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
) { const { SelectedItem.listIndex: 0 | 1listIndex: const sourceListIndex: 0 | 1sourceListIndex, SelectedItem.itemIndex: numberitemIndex: const sourceItemIndex: numbersourceItemIndex, SelectedItem.value: stringvalue: const itemValue: stringitemValue, } = const selectedItem: SelectedItemselectedItem; const const targetListIndex: 0 | 1targetListIndex = listIndex: 0 | 1listIndex; const const targetItemIndex: numbertargetItemIndex = const currentItemIndex: numbercurrentItemIndex; if ( const sourceListIndex: 0 | 1sourceListIndex === const targetListIndex: 0 | 1targetListIndex && const sourceItemIndex: numbersourceItemIndex === const targetItemIndex: numbertargetItemIndex ) { const announce: (message: string) => voidannounce(`Keyboard: Cannot drop ${const itemValue: stringitemValue} onto itself.`); const setSelectedItem: (value: React.SetStateAction<SelectedItem | null>) => voidsetSelectedItem(null); break; } const const sourceItemsArray: string[]sourceItemsArray = const sourceListIndex: 0 | 1sourceListIndex === 0 ? const items1: string[]items1 : const items2: string[]items2; const const setSourceItems: React.Dispatch<React.SetStateAction<string[]>>setSourceItems = const sourceListIndex: 0 | 1sourceListIndex === 0 ? const setItems1: React.Dispatch<React.SetStateAction<string[]>>setItems1 : const setItems2: React.Dispatch<React.SetStateAction<string[]>>setItems2; const const targetItemsArray: string[]targetItemsArray = const targetListIndex: 0 | 1targetListIndex === 0 ? const items1: string[]items1 : const items2: string[]items2; const const setTargetItems: React.Dispatch<React.SetStateAction<string[]>>setTargetItems = const targetListIndex: 0 | 1targetListIndex === 0 ? const setItems1: React.Dispatch<React.SetStateAction<string[]>>setItems1 : const setItems2: React.Dispatch<React.SetStateAction<string[]>>setItems2; const const newSourceItems: string[]newSourceItems = [...const sourceItemsArray: string[]sourceItemsArray]; const newSourceItems: string[]newSourceItems.Array<string>.splice(start: number, deleteCount?: number): string[] (+1 overload)
Removes elements from an array and, if necessary, inserts new elements in their place, returning the deleted elements.
@paramstart The zero-based location in the array from which to start removing elements.@paramdeleteCount The number of elements to remove. Omitting this argument will remove all elements from the start paramater location to end of the array. If value of this argument is either a negative number, zero, undefined, or a type that cannot be converted to an integer, the function will evaluate the argument as zero and not remove any elements.@returnsAn array containing the elements that were deleted.
splice
(const sourceItemIndex: numbersourceItemIndex, 1);
const const newTargetItems: string[]newTargetItems = const sourceListIndex: 0 | 1sourceListIndex === const targetListIndex: 0 | 1targetListIndex ? const newSourceItems: string[]newSourceItems : [...const targetItemsArray: string[]targetItemsArray]; let let effectiveTargetIndex: numbereffectiveTargetIndex = const targetItemIndex: numbertargetItemIndex; if (const sourceListIndex: 0 | 1sourceListIndex === const targetListIndex: 0 | 1targetListIndex) { if (const sourceItemIndex: numbersourceItemIndex < const targetItemIndex: numbertargetItemIndex) { let effectiveTargetIndex: numbereffectiveTargetIndex = const targetItemIndex: numbertargetItemIndex - 1; } else { let effectiveTargetIndex: numbereffectiveTargetIndex = const targetItemIndex: numbertargetItemIndex; } } else { let effectiveTargetIndex: numbereffectiveTargetIndex = const targetItemIndex: numbertargetItemIndex; } let effectiveTargetIndex: numbereffectiveTargetIndex = var Math: Math
An intrinsic object that provides basic mathematics functionality and constants.
Math
.Math.max(...values: number[]): number
Returns the larger of a set of supplied numeric expressions.
@paramvalues Numeric expressions to be evaluated.
max
(
0, var Math: Math
An intrinsic object that provides basic mathematics functionality and constants.
Math
.Math.min(...values: number[]): number
Returns the smaller of a set of supplied numeric expressions.
@paramvalues Numeric expressions to be evaluated.
min
(let effectiveTargetIndex: numbereffectiveTargetIndex, const newTargetItems: string[]newTargetItems.Array<string>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
)
); const newTargetItems: string[]newTargetItems.Array<string>.splice(start: number, deleteCount: number, ...items: string[]): string[] (+1 overload)
Removes elements from an array and, if necessary, inserts new elements in their place, returning the deleted elements.
@paramstart The zero-based location in the array from which to start removing elements.@paramdeleteCount The number of elements to remove. If value of this argument is either a negative number, zero, undefined, or a type that cannot be converted to an integer, the function will evaluate the argument as zero and not remove any elements.@paramitems Elements to insert into the array in place of the deleted elements.@returnsAn array containing the elements that were deleted.
splice
(let effectiveTargetIndex: numbereffectiveTargetIndex, 0, const itemValue: stringitemValue);
// Update state using the hook's setters const setSourceItems: (value: React.SetStateAction<string[]>) => voidsetSourceItems(const newSourceItems: string[]newSourceItems); if (const sourceListIndex: 0 | 1sourceListIndex !== const targetListIndex: 0 | 1targetListIndex) { const setTargetItems: (value: React.SetStateAction<string[]>) => voidsetTargetItems(const newTargetItems: string[]newTargetItems); } // If same list, setSourceItems has updated the array const announce: (message: string) => voidannounce( `Keyboard: Moved ${const itemValue: stringitemValue} to position ${ let effectiveTargetIndex: numbereffectiveTargetIndex + 1 } in List ${const targetListIndex: 0 | 1targetListIndex + 1}.` ); const setSelectedItem: (value: React.SetStateAction<SelectedItem | null>) => voidsetSelectedItem(null); const setFocusedItemIndex: (value: React.SetStateAction<number | null>) => voidsetFocusedItemIndex(let effectiveTargetIndex: numbereffectiveTargetIndex); const setFocusedListIndex: (value: React.SetStateAction<0 | 1 | null>) => voidsetFocusedListIndex(const targetListIndex: 0 | 1targetListIndex); } break; case "Escape": event: React.KeyboardEvent<HTMLUListElement>event.React.BaseSyntheticEvent<KeyboardEvent, EventTarget & HTMLUListElement, EventTarget>.preventDefault(): voidpreventDefault(); if (const selectedItem: SelectedItem | nullselectedItem) { const announce: (message: string) => voidannounce(`Selection cancelled for ${const selectedItem: SelectedItemselectedItem.SelectedItem.value: stringvalue}.`); const setSelectedItem: (value: React.SetStateAction<SelectedItem | null>) => voidsetSelectedItem(null); } else { const announce: (message: string) => voidannounce("Escape pressed. No item selected."); (event: React.KeyboardEvent<HTMLUListElement>event.React.BaseSyntheticEvent<KeyboardEvent, EventTarget & HTMLUListElement, EventTarget>.target: EventTargettarget as HTMLElement).HTMLOrSVGElement.blur(): void
[MDN Reference](https://developer.mozilla.org/docs/Web/API/HTMLElement/blur)
blur
();
const setFocusedListIndex: (value: React.SetStateAction<0 | 1 | null>) => voidsetFocusedListIndex(null); const setFocusedItemIndex: (value: React.SetStateAction<number | null>) => voidsetFocusedItemIndex(null); } break; default: return; } }, [ const focusedListIndex: 0 | 1 | nullfocusedListIndex, const focusedItemIndex: number | nullfocusedItemIndex, const selectedItem: SelectedItem | nullselectedItem, const items1: string[]items1, const items2: string[]items2, const setItems1: React.Dispatch<React.SetStateAction<string[]>>setItems1, const setItems2: React.Dispatch<React.SetStateAction<string[]>>setItems2, const announce: (message: string) => voidannounce, ] ); return ( // Using a standard div wrapper instead of DemoContainer <React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div React.HTMLAttributes<HTMLDivElement>.className?: string | undefinedclassName="container p-4 border-4 border-blue-300"> <React.JSX.IntrinsicElements.h1: React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>h1 React.HTMLAttributes<T>.className?: string | undefinedclassName="text-xl font-bold mb-4">React Accessibility Demo</React.JSX.IntrinsicElements.h1: React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>h1> <React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div React.HTMLAttributes<HTMLDivElement>.className?: string | undefinedclassName="accessibility-demo"> <React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div React.RefAttributes<HTMLDivElement>.ref?: React.Ref<HTMLDivElement> | undefined
Allows getting a ref to the component instance. Once the component unmounts, React will set `ref.current` to `null` (or call the ref with `null` if you passed a callback ref).
@see{@link https://react.dev/learn/referencing-values-with-refs#refs-and-the-dom React Docs}
ref
={const liveRegionRef: React.RefObject<HTMLDivElement | null>liveRegionRef} React.AriaAttributes["aria-live"]?: "polite" | "off" | "assertive" | undefined
Indicates that an element will be updated, and describes the types of updates the user agents, assistive technologies, and user can expect from the live region.
aria-live
="polite" React.HTMLAttributes<HTMLDivElement>.className?: string | undefinedclassName="sr-only">
{const liveMessage: stringliveMessage} </React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div> <React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div React.HTMLAttributes<HTMLDivElement>.className?: string | undefinedclassName="lists-container"> {/* List 1 */} <React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div React.HTMLAttributes<HTMLDivElement>.className?: string | undefinedclassName="list-wrapper"> <React.JSX.IntrinsicElements.h2: React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>h2 React.HTMLAttributes<HTMLHeadingElement>.id?: string | undefinedid="list1-item-heading">List 1</React.JSX.IntrinsicElements.h2: React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>h2> <React.JSX.IntrinsicElements.ul: React.DetailedHTMLProps<React.HTMLAttributes<HTMLUListElement>, HTMLUListElement>ul React.RefAttributes<HTMLUListElement>.ref?: React.Ref<HTMLUListElement> | undefined
Allows getting a ref to the component instance. Once the component unmounts, React will set `ref.current` to `null` (or call the ref with `null` if you passed a callback ref).
@see{@link https://react.dev/learn/referencing-values-with-refs#refs-and-the-dom React Docs}
ref
={const list1Ref: React.RefObject<HTMLUListElement | null>list1Ref} // Assign ref from hook
React.HTMLAttributes<T>.className?: string | undefinedclassName="list" React.HTMLAttributes<HTMLUListElement>.tabIndex?: number | undefinedtabIndex={0} React.HTMLAttributes<HTMLUListElement>.role?: React.AriaRole | undefinedrole="listbox" React.AriaAttributes["aria-labelledby"]?: string | undefined
Identifies the element (or elements) that labels the current element.
@seearia-describedby.
aria-labelledby
="list1-item-heading"
React.AriaAttributes["aria-activedescendant"]?: string | undefined
Identifies the currently active element when DOM focus is on a composite widget, textbox, group, or application.
aria-activedescendant
={
const focusedListIndex: 0 | 1 | nullfocusedListIndex === 0 ? const focusedItemId: string | undefinedfocusedItemId : var undefinedundefined } React.DOMAttributes<HTMLUListElement>.onFocus?: React.FocusEventHandler<HTMLUListElement> | undefinedonFocus={() => const handleListFocus: (listIndex: 0 | 1) => voidhandleListFocus(0)} React.DOMAttributes<HTMLUListElement>.onBlur?: React.FocusEventHandler<HTMLUListElement> | undefinedonBlur={const handleListBlur: () => voidhandleListBlur} React.DOMAttributes<HTMLUListElement>.onKeyDown?: React.KeyboardEventHandler<HTMLUListElement> | undefinedonKeyDown={(e: React.KeyboardEvent<HTMLUListElement>e) => const handleListKeydown: (event: React.KeyboardEvent<HTMLUListElement>, listIndex: 0 | 1) => voidhandleListKeydown(e: React.KeyboardEvent<HTMLUListElement>e, 0)} > {const items1: string[]items1.Array<string>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
> 0 ? (
const items1: string[]items1.Array<string>.map<React.JSX.Element>(callbackfn: (value: string, index: number, array: string[]) => React.JSX.Element, thisArg?: any): React.JSX.Element[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
((item: stringitem, index: numberindex) => {
const const isFocused: booleanisFocused = const focusedListIndex: 0 | 1 | nullfocusedListIndex === 0 && const focusedItemIndex: number | nullfocusedItemIndex === index: numberindex; const const isSelected: booleanisSelected = const selectedItem: SelectedItem | nullselectedItem?.SelectedItem.listIndex: 0 | 1 | undefinedlistIndex === 0 && const selectedItem: SelectedItemselectedItem?.SelectedItem.itemIndex: numberitemIndex === index: numberindex; const const itemId: stringitemId = `list1-item-${item: stringitem}`; return ( <React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li React.Attributes.key?: React.Key | null | undefinedkey={const itemId: stringitemId} React.HTMLAttributes<T>.id?: string | undefinedid={const itemId: stringitemId} React.HTMLAttributes<T>.className?: string | undefinedclassName={`item ${const isFocused: booleanisFocused ? "item-focused" : ""} ${ const isSelected: booleanisSelected ? "item-selected" : "" }`} React.HTMLAttributes<T>.role?: React.AriaRole | undefinedrole="option" React.AriaAttributes["aria-selected"]?: Booleanish | undefined
Indicates the current "selected" state of various widgets.
@seearia-checked@seearia-pressed.
aria-selected
={const isFocused: booleanisFocused}
React.HTMLAttributes<T>.tabIndex?: number | undefinedtabIndex={-1} > {item: stringitem} </React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li> ); }) ) : ( <React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li React.HTMLAttributes<T>.className?: string | undefinedclassName="empty-list-message">Empty</React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li> )} </React.JSX.IntrinsicElements.ul: React.DetailedHTMLProps<React.HTMLAttributes<HTMLUListElement>, HTMLUListElement>ul> </React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div> {/* List 2 */} <React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div React.HTMLAttributes<HTMLDivElement>.className?: string | undefinedclassName="list-wrapper"> <React.JSX.IntrinsicElements.h2: React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>h2 React.HTMLAttributes<HTMLHeadingElement>.id?: string | undefinedid="list2-item-heading">List 2</React.JSX.IntrinsicElements.h2: React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>h2> <React.JSX.IntrinsicElements.ul: React.DetailedHTMLProps<React.HTMLAttributes<HTMLUListElement>, HTMLUListElement>ul React.RefAttributes<HTMLUListElement>.ref?: React.Ref<HTMLUListElement> | undefined
Allows getting a ref to the component instance. Once the component unmounts, React will set `ref.current` to `null` (or call the ref with `null` if you passed a callback ref).
@see{@link https://react.dev/learn/referencing-values-with-refs#refs-and-the-dom React Docs}
ref
={const list2Ref: React.RefObject<HTMLUListElement | null>list2Ref} // Assign ref from hook
React.HTMLAttributes<T>.className?: string | undefinedclassName="list" React.HTMLAttributes<HTMLUListElement>.tabIndex?: number | undefinedtabIndex={0} React.HTMLAttributes<HTMLUListElement>.role?: React.AriaRole | undefinedrole="listbox" React.AriaAttributes["aria-labelledby"]?: string | undefined
Identifies the element (or elements) that labels the current element.
@seearia-describedby.
aria-labelledby
="list2-item-heading"
React.AriaAttributes["aria-activedescendant"]?: string | undefined
Identifies the currently active element when DOM focus is on a composite widget, textbox, group, or application.
aria-activedescendant
={
const focusedListIndex: 0 | 1 | nullfocusedListIndex === 1 ? const focusedItemId: string | undefinedfocusedItemId : var undefinedundefined } React.DOMAttributes<HTMLUListElement>.onFocus?: React.FocusEventHandler<HTMLUListElement> | undefinedonFocus={() => const handleListFocus: (listIndex: 0 | 1) => voidhandleListFocus(1)} React.DOMAttributes<HTMLUListElement>.onBlur?: React.FocusEventHandler<HTMLUListElement> | undefinedonBlur={const handleListBlur: () => voidhandleListBlur} React.DOMAttributes<HTMLUListElement>.onKeyDown?: React.KeyboardEventHandler<HTMLUListElement> | undefinedonKeyDown={(e: React.KeyboardEvent<HTMLUListElement>e) => const handleListKeydown: (event: React.KeyboardEvent<HTMLUListElement>, listIndex: 0 | 1) => voidhandleListKeydown(e: React.KeyboardEvent<HTMLUListElement>e, 1)} > {const items2: string[]items2.Array<string>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
> 0 ? (
const items2: string[]items2.Array<string>.map<React.JSX.Element>(callbackfn: (value: string, index: number, array: string[]) => React.JSX.Element, thisArg?: any): React.JSX.Element[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
((item: stringitem, index: numberindex) => {
const const isFocused: booleanisFocused = const focusedListIndex: 0 | 1 | nullfocusedListIndex === 1 && const focusedItemIndex: number | nullfocusedItemIndex === index: numberindex; const const isSelected: booleanisSelected = const selectedItem: SelectedItem | nullselectedItem?.SelectedItem.listIndex: 0 | 1 | undefinedlistIndex === 1 && const selectedItem: SelectedItemselectedItem?.SelectedItem.itemIndex: numberitemIndex === index: numberindex; const const itemId: stringitemId = `list2-item-${item: stringitem}`; return ( <React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li React.Attributes.key?: React.Key | null | undefinedkey={const itemId: stringitemId} React.HTMLAttributes<T>.id?: string | undefinedid={const itemId: stringitemId} React.HTMLAttributes<T>.className?: string | undefinedclassName={`item ${const isFocused: booleanisFocused ? "item-focused" : ""} ${ const isSelected: booleanisSelected ? "item-selected" : "" }`} React.HTMLAttributes<T>.role?: React.AriaRole | undefinedrole="option" React.AriaAttributes["aria-selected"]?: Booleanish | undefined
Indicates the current "selected" state of various widgets.
@seearia-checked@seearia-pressed.
aria-selected
={const isFocused: booleanisFocused}
React.HTMLAttributes<T>.tabIndex?: number | undefinedtabIndex={-1} > {item: stringitem} </React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li> ); }) ) : ( <React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li React.HTMLAttributes<T>.className?: string | undefinedclassName="empty-list-message">Empty</React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li> )} </React.JSX.IntrinsicElements.ul: React.DetailedHTMLProps<React.HTMLAttributes<HTMLUListElement>, HTMLUListElement>ul> </React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div> </React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div> <React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div React.HTMLAttributes<HTMLDivElement>.className?: string | undefinedclassName="instructions"> <React.JSX.IntrinsicElements.h3: React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>h3>Keyboard Instructions</React.JSX.IntrinsicElements.h3: React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>h3> <React.JSX.IntrinsicElements.ul: React.DetailedHTMLProps<React.HTMLAttributes<HTMLUListElement>, HTMLUListElement>ul> <React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li> Use <React.JSX.IntrinsicElements.kbd: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>kbd>Tab</React.JSX.IntrinsicElements.kbd: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>kbd> or <React.JSX.IntrinsicElements.kbd: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>kbd>Shift+Tab</React.JSX.IntrinsicElements.kbd: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>kbd> to focus a list. </React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li> <React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li> Use <React.JSX.IntrinsicElements.kbd: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>kbd>↑</React.JSX.IntrinsicElements.kbd: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>kbd> / <React.JSX.IntrinsicElements.kbd: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>kbd>↓</React.JSX.IntrinsicElements.kbd: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>kbd> arrows to navigate items within the focused list. </React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li> <React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li> Press <React.JSX.IntrinsicElements.kbd: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>kbd>Spacebar</React.JSX.IntrinsicElements.kbd: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>kbd> to select/deselect the highlighted item for moving. </React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li> <React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li> With an item selected, use <React.JSX.IntrinsicElements.kbd: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>kbd>↑</React.JSX.IntrinsicElements.kbd: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>kbd> / <React.JSX.IntrinsicElements.kbd: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>kbd>↓</React.JSX.IntrinsicElements.kbd: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>kbd> (within the same or another focused list) to choose the drop position. </React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li> <React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li> Press <React.JSX.IntrinsicElements.kbd: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>kbd>Enter</React.JSX.IntrinsicElements.kbd: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>kbd> to drop the selected item at the highlighted position. </React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li> <React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li> Press <React.JSX.IntrinsicElements.kbd: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>kbd>Escape</React.JSX.IntrinsicElements.kbd: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>kbd> to cancel a selection or leave the list. </React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li> </React.JSX.IntrinsicElements.ul: React.DetailedHTMLProps<React.HTMLAttributes<HTMLUListElement>, HTMLUListElement>ul> </React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div> </React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div> {/* Styles assumed to be global or handled via CSS Modules/Tailwind etc. */} </React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div> ); }
<script setup lang="ts">
import { function ref<T>(value: T): [T] extends [Ref] ? IfAny<T, Ref<T>, T> : Ref<UnwrapRef<T>, UnwrapRef<T> | T> (+1 overload)
Takes an inner value and returns a reactive and mutable ref object, which has a single property `.value` that points to the inner value.
@paramvalue - The object to wrap in the ref.@see{@link https://vuejs.org/api/reactivity-core.html#ref}
ref
,
const computed: {
    <T>(getter: ComputedGetter<T>, debugOptions?: DebuggerOptions): ComputedRef<T>;
    <T, S = T>(options: WritableComputedOptions<T, S>, debugOptions?: DebuggerOptions): WritableComputedRef<T, S>;
}
computed
, function nextTick(): Promise<void> (+1 overload)nextTick } from "vue";
import { function useDragAndDrop<T>(initialValues: T[], options?: Partial<VueParentConfig<T>>): [Ref<HTMLElement | undefined>, Ref<T[]>, (config: Partial<VueParentConfig<T>>) => void]
Creates a new instance of drag and drop and returns the parent element and a ref of the values to use in your template.
@paraminitialValues - The initial values of the parent element.@returnsThe parent element and values for drag and drop.
useDragAndDrop
} from "@formkit/drag-and-drop/vue";
// Refs for ARIA Live region const const liveMessage: Ref<string, string>liveMessage = ref<string>(value: string): Ref<string, string> (+1 overload)
Takes an inner value and returns a reactive and mutable ref object, which has a single property `.value` that points to the inner value.
@paramvalue - The object to wrap in the ref.@see{@link https://vuejs.org/api/reactivity-core.html#ref}
ref
("");
const const liveRegion: Ref<HTMLDivElement | null, HTMLDivElement | null>liveRegion = ref<HTMLDivElement | null>(value: HTMLDivElement | null): Ref<HTMLDivElement | null, HTMLDivElement | null> (+1 overload)
Takes an inner value and returns a reactive and mutable ref object, which has a single property `.value` that points to the inner value.
@paramvalue - The object to wrap in the ref.@see{@link https://vuejs.org/api/reactivity-core.html#ref}
ref
<HTMLDivElement | null>(null);
// Function to update the live region function function announce(message: string): voidannounce(message: stringmessage: string) { const liveMessage: Ref<string, string>liveMessage.Ref<string, string>.value: stringvalue = message: stringmessage; // Optional: Clear the message after a delay if needed // setTimeout(() => { liveMessage.value = ''; }, 5000); } // Initial data for the lists const const initialItems1: string[]initialItems1 = ["Apples", "Bananas", "Oranges", "Grapes"]; const const initialItems2: string[]initialItems2 = ["Milk", "Cheese", "Yogurt"]; // Setup drag and drop for List 1 const [const list1Node: Ref<HTMLElement | undefined, HTMLElement | undefined>list1Node, const items1: Ref<string[], string[]>items1] = useDragAndDrop<string>(initialValues: string[], options?: Partial<Partial<ParentConfig<string>>>): [Ref<HTMLElement | undefined, HTMLElement | undefined>, Ref<string[], string[]>, (config: Partial<Partial<ParentConfig<string>>>) => void]
Creates a new instance of drag and drop and returns the parent element and a ref of the values to use in your template.
@paraminitialValues - The initial values of the parent element.@returnsThe parent element and values for drag and drop.
useDragAndDrop
(const initialItems1: string[]initialItems1, {
group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "accessibleList",
onDragstart?: DragstartEvent<string> | undefined
Fired when a drag is started, whether native drag or synthetic
onDragstart
: (state: DragstartEventData<string>state) => {
function announce(message: string): voidannounce(`Drag started for ${state: DragstartEventData<string>state.DragstartEventData<string>.draggedNode: NodeRecord<string>draggedNode.NodeRecord<string>.data: NodeData<string>data.NodeData<string>.value: string
The value of the node.
value
}.`);
}, onSort?: SortEvent<string> | undefined
Callback function for when a sort operation is performed.
onSort
: (event: SortEventData<string>event) => {
function announce(message: string): voidannounce( `Sorted ${event: SortEventData<string>event.SortEventData<string>.draggedNodes: NodeRecord<string>[]draggedNodes[0].NodeRecord<string>.data: NodeData<string>data.NodeData<string>.value: string
The value of the node.
value
} in List 1 to position ${
event: SortEventData<string>event.SortEventData<string>.position: numberposition + 1 }.` ); }, onTransfer?: TransferEvent<string> | undefined
Callback function for when a transfer operation is performed.
onTransfer
: (event: TransferEventData<string>event) => {
function announce(message: string): voidannounce( `Transferred ${event: TransferEventData<string>event.TransferEventData<string>.draggedNodes: NodeRecord<string>[]draggedNodes[0].NodeRecord<string>.data: NodeData<string>data.NodeData<string>.value: string
The value of the node.
value
} from List ${
event: TransferEventData<string>event.TransferEventData<string>.sourceParent: ParentRecord<string>sourceParent.ParentRecord<T>.el: HTMLElementel === const list1Node: Ref<HTMLElement | undefined, HTMLElement | undefined>list1Node.Ref<HTMLElement | undefined, HTMLElement | undefined>.value: HTMLElement | undefinedvalue ? 1 : 2 } to List 1 at position ${event: TransferEventData<string>event.TransferEventData<string>.targetIndex: numbertargetIndex + 1}.` ); }, onDragend?: DragendEvent<string> | undefined
Fired when a drag is ended, whether native drag or synthetic
onDragend
: (state: DragendEventData<string>state) => {
function announce(message: string): voidannounce(`Drag ended for ${state: DragendEventData<string>state.DragendEventData<string>.draggedNode: NodeRecord<string>draggedNode.NodeRecord<string>.data: NodeData<string>data.NodeData<string>.value: string
The value of the node.
value
}.`);
}, }); // Setup drag and drop for List 2 const [const list2Node: Ref<HTMLElement | undefined, HTMLElement | undefined>list2Node, const items2: Ref<string[], string[]>items2] = useDragAndDrop<string>(initialValues: string[], options?: Partial<Partial<ParentConfig<string>>>): [Ref<HTMLElement | undefined, HTMLElement | undefined>, Ref<string[], string[]>, (config: Partial<Partial<ParentConfig<string>>>) => void]
Creates a new instance of drag and drop and returns the parent element and a ref of the values to use in your template.
@paraminitialValues - The initial values of the parent element.@returnsThe parent element and values for drag and drop.
useDragAndDrop
(const initialItems2: string[]initialItems2, {
group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "accessibleList",
onDragstart?: DragstartEvent<string> | undefined
Fired when a drag is started, whether native drag or synthetic
onDragstart
: (state: DragstartEventData<string>state) => {
function announce(message: string): voidannounce(`Drag started for ${state: DragstartEventData<string>state.DragstartEventData<string>.draggedNode: NodeRecord<string>draggedNode.NodeRecord<string>.data: NodeData<string>data.NodeData<string>.value: string
The value of the node.
value
}.`);
}, onSort?: SortEvent<string> | undefined
Callback function for when a sort operation is performed.
onSort
: (event: SortEventData<string>event) => {
function announce(message: string): voidannounce( `Sorted ${event: SortEventData<string>event.SortEventData<string>.draggedNodes: NodeRecord<string>[]draggedNodes[0].NodeRecord<string>.data: NodeData<string>data.NodeData<string>.value: string
The value of the node.
value
} in List 2 to position ${
event: SortEventData<string>event.SortEventData<string>.position: numberposition + 1 }.` ); }, onTransfer?: TransferEvent<string> | undefined
Callback function for when a transfer operation is performed.
onTransfer
: (event: TransferEventData<string>event) => {
function announce(message: string): voidannounce( `Transferred ${event: TransferEventData<string>event.TransferEventData<string>.draggedNodes: NodeRecord<string>[]draggedNodes[0].NodeRecord<string>.data: NodeData<string>data.NodeData<string>.value: string
The value of the node.
value
} from List ${
event: TransferEventData<string>event.TransferEventData<string>.sourceParent: ParentRecord<string>sourceParent.ParentRecord<T>.el: HTMLElementel === const list1Node: Ref<HTMLElement | undefined, HTMLElement | undefined>list1Node.Ref<HTMLElement | undefined, HTMLElement | undefined>.value: HTMLElement | undefinedvalue ? 1 : 2 } to List 2 at position ${event: TransferEventData<string>event.TransferEventData<string>.targetIndex: numbertargetIndex + 1}.` ); }, onDragend?: DragendEvent<string> | undefined
Fired when a drag is ended, whether native drag or synthetic
onDragend
: (state: DragendEventData<string>state) => {
function announce(message: string): voidannounce(`Drag ended for ${state: DragendEventData<string>state.DragendEventData<string>.draggedNode: NodeRecord<string>draggedNode.NodeRecord<string>.data: NodeData<string>data.NodeData<string>.value: string
The value of the node.
value
}.`);
}, }); // State for keyboard navigation const const focusedListIndex: Ref<0 | 1 | null, 0 | 1 | null>focusedListIndex = ref<0 | 1 | null>(value: 0 | 1 | null): Ref<0 | 1 | null, 0 | 1 | null> (+1 overload)
Takes an inner value and returns a reactive and mutable ref object, which has a single property `.value` that points to the inner value.
@paramvalue - The object to wrap in the ref.@see{@link https://vuejs.org/api/reactivity-core.html#ref}
ref
<0 | 1 | null>(null);
const const focusedItemIndex: Ref<number | null, number | null>focusedItemIndex = ref<number | null>(value: number | null): Ref<number | null, number | null> (+1 overload)
Takes an inner value and returns a reactive and mutable ref object, which has a single property `.value` that points to the inner value.
@paramvalue - The object to wrap in the ref.@see{@link https://vuejs.org/api/reactivity-core.html#ref}
ref
<number | null>(null); // Index within the focused list
const
const selectedItem: Ref<{
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null, {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null>
selectedItem
=
ref<{
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null>(value: {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null): Ref<{
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null, {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null> (+1 overload)
Takes an inner value and returns a reactive and mutable ref object, which has a single property `.value` that points to the inner value.
@paramvalue - The object to wrap in the ref.@see{@link https://vuejs.org/api/reactivity-core.html#ref}
ref
<{
listIndex: 0 | 1listIndex: 0 | 1; itemIndex: numberitemIndex: number; value: stringvalue: string; } | null>(null); const
const lists: ComputedRef<{
    node: Ref<HTMLElement | undefined, HTMLElement | undefined>;
    items: Ref<string[], string[]>;
    idPrefix: string;
}[]>
lists
=
computed<{
    node: Ref<HTMLElement | undefined, HTMLElement | undefined>;
    items: Ref<string[], string[]>;
    idPrefix: string;
}[]>(getter: ComputedGetter<{
    node: Ref<HTMLElement | undefined, HTMLElement | undefined>;
    items: Ref<string[], string[]>;
    idPrefix: string;
}[]>, debugOptions?: DebuggerOptions): ComputedRef<{
    node: Ref<HTMLElement | undefined, HTMLElement | undefined>;
    items: Ref<string[], string[]>;
    idPrefix: string;
}[]> (+1 overload)
Takes a getter function and returns a readonly reactive ref object for the returned value from the getter. It can also take an object with get and set functions to create a writable ref object.
@example```js // Creating a readonly computed ref: const count = ref(1) const plusOne = computed(() => count.value + 1) console.log(plusOne.value) // 2 plusOne.value++ // error ``` ```js // Creating a writable computed ref: const count = ref(1) const plusOne = computed({ get: () => count.value + 1, set: (val) => { count.value = val - 1 } }) plusOne.value = 1 console.log(count.value) // 0 ```@paramgetter - Function that produces the next value.@paramdebugOptions - For debugging. See {@link https://vuejs.org/guide/extras/reactivity-in-depth.html#computed-debugging}.@see{@link https://vuejs.org/api/reactivity-core.html#computed}
computed
(() => [
{ node: Ref<HTMLElement | undefined, HTMLElement | undefined>node: const list1Node: Ref<HTMLElement | undefined, HTMLElement | undefined>list1Node, items: Ref<string[], string[]>items: const items1: Ref<string[], string[]>items1, idPrefix: stringidPrefix: "list1-item" }, { node: Ref<HTMLElement | undefined, HTMLElement | undefined>node: const list2Node: Ref<HTMLElement | undefined, HTMLElement | undefined>list2Node, items: Ref<string[], string[]>items: const items2: Ref<string[], string[]>items2, idPrefix: stringidPrefix: "list2-item" }, ]); const const focusedItemId: ComputedRef<string | undefined>focusedItemId = computed<string | undefined>(getter: ComputedGetter<string | undefined>, debugOptions?: DebuggerOptions): ComputedRef<string | undefined> (+1 overload)
Takes a getter function and returns a readonly reactive ref object for the returned value from the getter. It can also take an object with get and set functions to create a writable ref object.
@example```js // Creating a readonly computed ref: const count = ref(1) const plusOne = computed(() => count.value + 1) console.log(plusOne.value) // 2 plusOne.value++ // error ``` ```js // Creating a writable computed ref: const count = ref(1) const plusOne = computed({ get: () => count.value + 1, set: (val) => { count.value = val - 1 } }) plusOne.value = 1 console.log(count.value) // 0 ```@paramgetter - Function that produces the next value.@paramdebugOptions - For debugging. See {@link https://vuejs.org/guide/extras/reactivity-in-depth.html#computed-debugging}.@see{@link https://vuejs.org/api/reactivity-core.html#computed}
computed
(() => {
if (const focusedListIndex: Ref<0 | 1 | null, 0 | 1 | null>focusedListIndex.Ref<0 | 1 | null, 0 | 1 | null>.value: 0 | 1 | nullvalue !== null && const focusedItemIndex: Ref<number | null, number | null>focusedItemIndex.Ref<number | null, number | null>.value: number | nullvalue !== null) { const
const list: {
    node: Ref<HTMLElement | undefined, HTMLElement | undefined>;
    items: Ref<string[], string[]>;
    idPrefix: string;
}
list
=
const lists: ComputedRef<{
    node: Ref<HTMLElement | undefined, HTMLElement | undefined>;
    items: Ref<string[], string[]>;
    idPrefix: string;
}[]>
lists
.
ComputedRef<{ node: Ref<HTMLElement | undefined, HTMLElement | undefined>; items: Ref<string[], string[]>; idPrefix: string; }[]>.value: {
    node: Ref<HTMLElement | undefined, HTMLElement | undefined>;
    items: Ref<string[], string[]>;
    idPrefix: string;
}[]
value
[const focusedListIndex: Ref<0 | 1 | null, 0 | 1 | null>focusedListIndex.Ref<0 | 1 | null, 0 | 1 | null>.value: 0 | 1value];
if (
const list: {
    node: Ref<HTMLElement | undefined, HTMLElement | undefined>;
    items: Ref<string[], string[]>;
    idPrefix: string;
}
list
&& const focusedItemIndex: Ref<number | null, number | null>focusedItemIndex.Ref<number | null, number | null>.value: numbervalue <
const list: {
    node: Ref<HTMLElement | undefined, HTMLElement | undefined>;
    items: Ref<string[], string[]>;
    idPrefix: string;
}
list
.items: Ref<string[], string[]>items.Ref<string[], string[]>.value: string[]value.Array<string>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
) {
return `${
const list: {
    node: Ref<HTMLElement | undefined, HTMLElement | undefined>;
    items: Ref<string[], string[]>;
    idPrefix: string;
}
list
.idPrefix: stringidPrefix}-${
const list: {
    node: Ref<HTMLElement | undefined, HTMLElement | undefined>;
    items: Ref<string[], string[]>;
    idPrefix: string;
}
list
.items: Ref<string[], string[]>items.Ref<string[], string[]>.value: string[]value[const focusedItemIndex: Ref<number | null, number | null>focusedItemIndex.Ref<number | null, number | null>.value: numbervalue]}`;
} } return var undefinedundefined; }); // Function to handle focus moving to a list function function handleListFocus(listIndex: 0 | 1): voidhandleListFocus(listIndex: 0 | 1listIndex: 0 | 1) { const focusedListIndex: Ref<0 | 1 | null, 0 | 1 | null>focusedListIndex.Ref<0 | 1 | null, 0 | 1 | null>.value: 0 | 1 | nullvalue = listIndex: 0 | 1listIndex; // Optionally focus the first item if none is focused if ( const focusedItemIndex: Ref<number | null, number | null>focusedItemIndex.Ref<number | null, number | null>.value: number | nullvalue === null &&
const lists: ComputedRef<{
    node: Ref<HTMLElement | undefined, HTMLElement | undefined>;
    items: Ref<string[], string[]>;
    idPrefix: string;
}[]>
lists
.
ComputedRef<{ node: Ref<HTMLElement | undefined, HTMLElement | undefined>; items: Ref<string[], string[]>; idPrefix: string; }[]>.value: {
    node: Ref<HTMLElement | undefined, HTMLElement | undefined>;
    items: Ref<string[], string[]>;
    idPrefix: string;
}[]
value
[listIndex: 0 | 1listIndex].items: Ref<string[], string[]>items.Ref<string[], string[]>.value: string[]value.Array<string>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
> 0
) { const focusedItemIndex: Ref<number | null, number | null>focusedItemIndex.Ref<number | null, number | null>.value: number | nullvalue = 0; } function announce(message: string): voidannounce( `List ${listIndex: 0 | 1listIndex + 1} focused. Use up and down arrows to navigate items.` ); } // Function to handle blur from a list function function handleListBlur(): voidhandleListBlur() { // Keep focus state if moving between related elements or temporarily losing focus // For simplicity now, we clear it. More robust logic might be needed. // focusedListIndex.value = null; // focusedItemIndex.value = null; } // Function to handle keydown events on lists async function function handleListKeydown(event: KeyboardEvent, listIndex: 0 | 1): Promise<void>handleListKeydown(event: KeyboardEventevent: KeyboardEvent, listIndex: 0 | 1listIndex: 0 | 1) { if (const focusedListIndex: Ref<0 | 1 | null, 0 | 1 | null>focusedListIndex.Ref<0 | 1 | null, 0 | 1 | null>.value: 0 | 1 | nullvalue !== listIndex: 0 | 1listIndex) return; // Ignore if not the focused list const
const list: {
    node: Ref<HTMLElement | undefined, HTMLElement | undefined>;
    items: Ref<string[], string[]>;
    idPrefix: string;
}
list
=
const lists: ComputedRef<{
    node: Ref<HTMLElement | undefined, HTMLElement | undefined>;
    items: Ref<string[], string[]>;
    idPrefix: string;
}[]>
lists
.
ComputedRef<{ node: Ref<HTMLElement | undefined, HTMLElement | undefined>; items: Ref<string[], string[]>; idPrefix: string; }[]>.value: {
    node: Ref<HTMLElement | undefined, HTMLElement | undefined>;
    items: Ref<string[], string[]>;
    idPrefix: string;
}[]
value
[listIndex: 0 | 1listIndex];
const const items: string[]items =
const list: {
    node: Ref<HTMLElement | undefined, HTMLElement | undefined>;
    items: Ref<string[], string[]>;
    idPrefix: string;
}
list
.items: Ref<string[], string[]>items.Ref<string[], string[]>.value: string[]value;
const const currentItemIndex: number | nullcurrentItemIndex = const focusedItemIndex: Ref<number | null, number | null>focusedItemIndex.Ref<number | null, number | null>.value: number | nullvalue; switch (event: KeyboardEventevent.KeyboardEvent.key: string
The KeyboardEvent interface's **`key`** read-only property returns the value of the key pressed by the user, taking into consideration the state of modifier keys such as Shift as well as the keyboard locale and layout. [MDN Reference](https://developer.mozilla.org/docs/Web/API/KeyboardEvent/key)
key
) {
case "ArrowDown": event: KeyboardEventevent.Event.preventDefault(): void
The **`preventDefault()`** method of the Event interface tells the user agent that the event is being explicitly handled, so its default action, such as page scrolling, link navigation, or pasting text, should not be taken. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/preventDefault)
preventDefault
();
if (const items: string[]items.Array<string>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
> 0) {
const const nextIndex: numbernextIndex = const currentItemIndex: number | nullcurrentItemIndex === null ? 0 : (const currentItemIndex: numbercurrentItemIndex + 1) % const items: string[]items.Array<string>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
;
const focusedItemIndex: Ref<number | null, number | null>focusedItemIndex.Ref<number | null, number | null>.value: number | nullvalue = const nextIndex: numbernextIndex; function announce(message: string): voidannounce(const items: string[]items[const nextIndex: numbernextIndex]); await function nextTick(): Promise<void> (+1 overload)nextTick(); // Ensure DOM updates before focusing // Optionally focus the element itself if not purely virtual // const el = document.getElementById(focusedItemId.value!); // el?.focus(); } break; case "ArrowUp": event: KeyboardEventevent.Event.preventDefault(): void
The **`preventDefault()`** method of the Event interface tells the user agent that the event is being explicitly handled, so its default action, such as page scrolling, link navigation, or pasting text, should not be taken. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/preventDefault)
preventDefault
();
if (const items: string[]items.Array<string>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
> 0) {
const const prevIndex: numberprevIndex = const currentItemIndex: number | nullcurrentItemIndex === null ? const items: string[]items.Array<string>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
- 1
: (const currentItemIndex: numbercurrentItemIndex - 1 + const items: string[]items.Array<string>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
) % const items: string[]items.Array<string>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
;
const focusedItemIndex: Ref<number | null, number | null>focusedItemIndex.Ref<number | null, number | null>.value: number | nullvalue = const prevIndex: numberprevIndex; function announce(message: string): voidannounce(const items: string[]items[const prevIndex: numberprevIndex]); await function nextTick(): Promise<void> (+1 overload)nextTick(); // const el = document.getElementById(focusedItemId.value!); // el?.focus(); } break; case " ": // Spacebar event: KeyboardEventevent.Event.preventDefault(): void
The **`preventDefault()`** method of the Event interface tells the user agent that the event is being explicitly handled, so its default action, such as page scrolling, link navigation, or pasting text, should not be taken. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/preventDefault)
preventDefault
();
if (const currentItemIndex: number | nullcurrentItemIndex !== null) { if (
const selectedItem: Ref<{
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null, {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null>
selectedItem
.
Ref<{ listIndex: 0 | 1; itemIndex: number; value: string; } | null, { listIndex: 0 | 1; itemIndex: number; value: string; } | { listIndex: 0 | 1; itemIndex: number; value: string; } | null>.value: {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null
value
?.listIndex: 0 | 1 | undefinedlistIndex === listIndex: 0 | 1listIndex &&
const selectedItem: Ref<{
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null, {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null>
selectedItem
.
Ref<{ listIndex: 0 | 1; itemIndex: number; value: string; } | null, { listIndex: 0 | 1; itemIndex: number; value: string; } | { listIndex: 0 | 1; itemIndex: number; value: string; } | null>.value: {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
}
value
?.itemIndex: numberitemIndex === const currentItemIndex: numbercurrentItemIndex
) { // Deselect if selecting the same item again
const selectedItem: Ref<{
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null, {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null>
selectedItem
.
Ref<{ listIndex: 0 | 1; itemIndex: number; value: string; } | null, { listIndex: 0 | 1; itemIndex: number; value: string; } | { listIndex: 0 | 1; itemIndex: number; value: string; } | null>.value: {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null
value
= null;
function announce(message: string): voidannounce(`${const items: string[]items[const currentItemIndex: numbercurrentItemIndex]} deselected.`); } else { // Select the currently focused item
const selectedItem: Ref<{
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null, {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null>
selectedItem
.
Ref<{ listIndex: 0 | 1; itemIndex: number; value: string; } | null, { listIndex: 0 | 1; itemIndex: number; value: string; } | { listIndex: 0 | 1; itemIndex: number; value: string; } | null>.value: {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null
value
= {
listIndex: 0 | 1listIndex, itemIndex: numberitemIndex: const currentItemIndex: numbercurrentItemIndex, value: stringvalue: const items: string[]items[const currentItemIndex: numbercurrentItemIndex], }; function announce(message: string): voidannounce( `${const items: string[]items[const currentItemIndex: numbercurrentItemIndex]} selected. Use arrow keys to choose drop position, then press Enter.` ); } } break; case "Enter": event: KeyboardEventevent.Event.preventDefault(): void
The **`preventDefault()`** method of the Event interface tells the user agent that the event is being explicitly handled, so its default action, such as page scrolling, link navigation, or pasting text, should not be taken. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/preventDefault)
preventDefault
();
if (
const selectedItem: Ref<{
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null, {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null>
selectedItem
.
Ref<{ listIndex: 0 | 1; itemIndex: number; value: string; } | null, { listIndex: 0 | 1; itemIndex: number; value: string; } | { listIndex: 0 | 1; itemIndex: number; value: string; } | null>.value: {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null
value
&& const currentItemIndex: number | nullcurrentItemIndex !== null) {
const const sourceListIndex: 0 | 1sourceListIndex =
const selectedItem: Ref<{
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null, {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null>
selectedItem
.
Ref<{ listIndex: 0 | 1; itemIndex: number; value: string; } | null, { listIndex: 0 | 1; itemIndex: number; value: string; } | { listIndex: 0 | 1; itemIndex: number; value: string; } | null>.value: {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
}
value
.listIndex: 0 | 1listIndex;
const const sourceItemIndex: numbersourceItemIndex =
const selectedItem: Ref<{
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null, {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null>
selectedItem
.
Ref<{ listIndex: 0 | 1; itemIndex: number; value: string; } | null, { listIndex: 0 | 1; itemIndex: number; value: string; } | { listIndex: 0 | 1; itemIndex: number; value: string; } | null>.value: {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
}
value
.itemIndex: numberitemIndex;
const const targetListIndex: 0 | 1targetListIndex = listIndex: 0 | 1listIndex; const const targetItemIndex: numbertargetItemIndex = const currentItemIndex: numbercurrentItemIndex; const const itemValue: stringitemValue =
const selectedItem: Ref<{
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null, {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null>
selectedItem
.
Ref<{ listIndex: 0 | 1; itemIndex: number; value: string; } | null, { listIndex: 0 | 1; itemIndex: number; value: string; } | { listIndex: 0 | 1; itemIndex: number; value: string; } | null>.value: {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
}
value
.value: stringvalue;
// Prevent dropping onto itself without moving if ( const sourceListIndex: 0 | 1sourceListIndex === const targetListIndex: 0 | 1targetListIndex && const sourceItemIndex: numbersourceItemIndex === const targetItemIndex: numbertargetItemIndex ) { // Announce slightly different message for keyboard attempt function announce(message: string): voidannounce(`Keyboard: Cannot drop ${const itemValue: stringitemValue} onto itself.`);
const selectedItem: Ref<{
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null, {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null>
selectedItem
.
Ref<{ listIndex: 0 | 1; itemIndex: number; value: string; } | null, { listIndex: 0 | 1; itemIndex: number; value: string; } | { listIndex: 0 | 1; itemIndex: number; value: string; } | null>.value: {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null
value
= null; // Clear selection
break; } // Perform the move by directly modifying the reactive refs const const sourceItems: Ref<string[], string[]>sourceItems =
const lists: ComputedRef<{
    node: Ref<HTMLElement | undefined, HTMLElement | undefined>;
    items: Ref<string[], string[]>;
    idPrefix: string;
}[]>
lists
.
ComputedRef<{ node: Ref<HTMLElement | undefined, HTMLElement | undefined>; items: Ref<string[], string[]>; idPrefix: string; }[]>.value: {
    node: Ref<HTMLElement | undefined, HTMLElement | undefined>;
    items: Ref<string[], string[]>;
    idPrefix: string;
}[]
value
[const sourceListIndex: 0 | 1sourceListIndex].items: Ref<string[], string[]>items;
const const targetItems: Ref<string[], string[]>targetItems =
const lists: ComputedRef<{
    node: Ref<HTMLElement | undefined, HTMLElement | undefined>;
    items: Ref<string[], string[]>;
    idPrefix: string;
}[]>
lists
.
ComputedRef<{ node: Ref<HTMLElement | undefined, HTMLElement | undefined>; items: Ref<string[], string[]>; idPrefix: string; }[]>.value: {
    node: Ref<HTMLElement | undefined, HTMLElement | undefined>;
    items: Ref<string[], string[]>;
    idPrefix: string;
}[]
value
[const targetListIndex: 0 | 1targetListIndex].items: Ref<string[], string[]>items;
// 1. Remove from source const sourceItems: Ref<string[], string[]>sourceItems.Ref<string[], string[]>.value: string[]value.Array<string>.splice(start: number, deleteCount?: number): string[] (+1 overload)
Removes elements from an array and, if necessary, inserts new elements in their place, returning the deleted elements.
@paramstart The zero-based location in the array from which to start removing elements.@paramdeleteCount The number of elements to remove. Omitting this argument will remove all elements from the start paramater location to end of the array. If value of this argument is either a negative number, zero, undefined, or a type that cannot be converted to an integer, the function will evaluate the argument as zero and not remove any elements.@returnsAn array containing the elements that were deleted.
splice
(const sourceItemIndex: numbersourceItemIndex, 1);
// 2. Insert into target // Adjust target index if moving within the same list downwards let let effectiveTargetIndex: numbereffectiveTargetIndex = const targetItemIndex: numbertargetItemIndex; // If dropping onto the same list if (const sourceListIndex: 0 | 1sourceListIndex === const targetListIndex: 0 | 1targetListIndex) { // If dropping after the original position if (const sourceItemIndex: numbersourceItemIndex < const targetItemIndex: numbertargetItemIndex) { // No adjustment needed because the targetItemIndex already accounts // for the removal of the item before it. // However, if the target *was* the placeholder *after* the last item, // we might need to adjust. Let's refine this slightly. // The targetItemIndex is the index *before* insertion. let effectiveTargetIndex: numbereffectiveTargetIndex = const targetItemIndex: numbertargetItemIndex; // This seems correct for splice insertion point } else { // If dropping before the original position, the targetItemIndex is correct. let effectiveTargetIndex: numbereffectiveTargetIndex = const targetItemIndex: numbertargetItemIndex; } } else { // If dropping onto a different list, the targetItemIndex is correct. let effectiveTargetIndex: numbereffectiveTargetIndex = const targetItemIndex: numbertargetItemIndex; } // Ensure the index is valid for splice (handles dropping at the end) let effectiveTargetIndex: numbereffectiveTargetIndex = var Math: Math
An intrinsic object that provides basic mathematics functionality and constants.
Math
.Math.max(...values: number[]): number
Returns the larger of a set of supplied numeric expressions.
@paramvalues Numeric expressions to be evaluated.
max
(
0, var Math: Math
An intrinsic object that provides basic mathematics functionality and constants.
Math
.Math.min(...values: number[]): number
Returns the smaller of a set of supplied numeric expressions.
@paramvalues Numeric expressions to be evaluated.
min
(let effectiveTargetIndex: numbereffectiveTargetIndex, const targetItems: Ref<string[], string[]>targetItems.Ref<string[], string[]>.value: string[]value.Array<string>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
)
); const targetItems: Ref<string[], string[]>targetItems.Ref<string[], string[]>.value: string[]value.Array<string>.splice(start: number, deleteCount: number, ...items: string[]): string[] (+1 overload)
Removes elements from an array and, if necessary, inserts new elements in their place, returning the deleted elements.
@paramstart The zero-based location in the array from which to start removing elements.@paramdeleteCount The number of elements to remove. If value of this argument is either a negative number, zero, undefined, or a type that cannot be converted to an integer, the function will evaluate the argument as zero and not remove any elements.@paramitems Elements to insert into the array in place of the deleted elements.@returnsAn array containing the elements that were deleted.
splice
(let effectiveTargetIndex: numbereffectiveTargetIndex, 0, const itemValue: stringitemValue);
// Announce the keyboard-driven move function announce(message: string): voidannounce( `Keyboard: Moved ${const itemValue: stringitemValue} to position ${ let effectiveTargetIndex: numbereffectiveTargetIndex + 1 } in List ${const targetListIndex: 0 | 1targetListIndex + 1}.` ); // Reset state
const selectedItem: Ref<{
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null, {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null>
selectedItem
.
Ref<{ listIndex: 0 | 1; itemIndex: number; value: string; } | null, { listIndex: 0 | 1; itemIndex: number; value: string; } | { listIndex: 0 | 1; itemIndex: number; value: string; } | null>.value: {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null
value
= null;
// Keep focus on the item in its new position if possible const focusedItemIndex: Ref<number | null, number | null>focusedItemIndex.Ref<number | null, number | null>.value: number | nullvalue = let effectiveTargetIndex: numbereffectiveTargetIndex; const focusedListIndex: Ref<0 | 1 | null, 0 | 1 | null>focusedListIndex.Ref<0 | 1 | null, 0 | 1 | null>.value: 0 | 1 | nullvalue = const targetListIndex: 0 | 1targetListIndex; // Ensure focus stays on target list } break; case "Escape": event: KeyboardEventevent.Event.preventDefault(): void
The **`preventDefault()`** method of the Event interface tells the user agent that the event is being explicitly handled, so its default action, such as page scrolling, link navigation, or pasting text, should not be taken. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/preventDefault)
preventDefault
();
if (
const selectedItem: Ref<{
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null, {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null>
selectedItem
.
Ref<{ listIndex: 0 | 1; itemIndex: number; value: string; } | null, { listIndex: 0 | 1; itemIndex: number; value: string; } | { listIndex: 0 | 1; itemIndex: number; value: string; } | null>.value: {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null
value
) {
function announce(message: string): voidannounce(`Selection cancelled for ${
const selectedItem: Ref<{
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null, {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null>
selectedItem
.
Ref<{ listIndex: 0 | 1; itemIndex: number; value: string; } | null, { listIndex: 0 | 1; itemIndex: number; value: string; } | { listIndex: 0 | 1; itemIndex: number; value: string; } | null>.value: {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
}
value
.value: stringvalue}.`);
const selectedItem: Ref<{
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null, {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null>
selectedItem
.
Ref<{ listIndex: 0 | 1; itemIndex: number; value: string; } | null, { listIndex: 0 | 1; itemIndex: number; value: string; } | { listIndex: 0 | 1; itemIndex: number; value: string; } | null>.value: {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null
value
= null;
} else { // Optionally blur the list or reset focus function announce(message: string): voidannounce("Escape pressed. No item selected."); (event: KeyboardEventevent.Event.target: EventTarget | null
The read-only **`target`** property of the Event interface is a reference to the object onto which the event was dispatched. It is different from Event.currentTarget when the event handler is called during the bubbling or capturing phase of the event. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/target)
target
as HTMLElement).HTMLOrSVGElement.blur(): void
[MDN Reference](https://developer.mozilla.org/docs/Web/API/HTMLElement/blur)
blur
(); // Example: blur the list
const focusedListIndex: Ref<0 | 1 | null, 0 | 1 | null>focusedListIndex.Ref<0 | 1 | null, 0 | 1 | null>.value: 0 | 1 | nullvalue = null; const focusedItemIndex: Ref<number | null, number | null>focusedItemIndex.Ref<number | null, number | null>.value: number | nullvalue = null; } break; // Add Home/End key support if desired // case "Home": ... // case "End": ... default: // Allow other keys like Tab to function normally return; } } </script> <template> <div: HTMLAttributes & ReservedPropsdiv HTMLAttributes.class?: ClassValueclass="accessibility-demo"> <div: HTMLAttributes & ReservedPropsdiv ReservedProps.ref?: VNodeRef | undefinedref="liveRegion: HTMLDivElementliveRegion" aria-live="polite" HTMLAttributes.class?: ClassValueclass="sr-only"> {{ const liveMessage: Ref<string, string>liveMessage }} </div: HTMLAttributes & ReservedPropsdiv> <div: HTMLAttributes & ReservedPropsdiv HTMLAttributes.class?: ClassValueclass="lists-container"> <div: HTMLAttributes & ReservedPropsdiv HTMLAttributes.class?: ClassValueclass="list-wrapper"> <h2: HTMLAttributes & ReservedPropsh2 HTMLAttributes.id?: string | undefinedid="list1-heading">List 1</h2: HTMLAttributes & ReservedPropsh2> <ul: HTMLAttributes & ReservedPropsul ReservedProps.ref?: VNodeRef | undefinedref="list1Node: HTMLUListElementlist1Node" HTMLAttributes.class?: ClassValueclass="list" HTMLAttributes.tabindex?: Numberish | undefinedtabindex="0" HTMLAttributes.role?: string | undefinedrole="listbox" aria-labelledby="list1-heading" :aria-activedescendant=" const focusedListIndex: Ref<0 | 1 | null, 0 | 1 | null>focusedListIndex === 0 ? const focusedItemId: ComputedRef<string | undefined>focusedItemId : var undefinedundefined " @onFocus?: ((payload: FocusEvent) => void) | undefinedfocus="function handleListFocus(listIndex: 0 | 1): voidhandleListFocus(0)" @onBlur?: ((payload: FocusEvent) => void) | undefinedblur="function handleListBlur(): voidhandleListBlur" @onKeydown?: ((payload: KeyboardEvent) => void) | undefinedkeydown="function handleListKeydown(event: KeyboardEvent, listIndex: 0 | 1): Promise<void>handleListKeydown($event: KeyboardEvent$event, 0)" > <li: LiHTMLAttributes & ReservedPropsli v-for="(const item: stringitem, const index: numberindex) in const items1: Ref<string[], string[]>items1" ReservedProps.key?: PropertyKey | undefined:key="const item: stringitem" HTMLAttributes.id?: string | undefined:id="`list1-item-${const item: stringitem}`" HTMLAttributes.class?: ClassValueclass="item" HTMLAttributes.role?: string | undefinedrole="option" :aria-selected=" const focusedListIndex: Ref<0 | 1 | null, 0 | 1 | null>focusedListIndex === 0 && const focusedItemIndex: Ref<number | null, number | null>focusedItemIndex === const index: numberindex " HTMLAttributes.class?: ClassValue:class="{ 'item-focused': const focusedListIndex: Ref<0 | 1 | null, 0 | 1 | null>focusedListIndex === 0 && const focusedItemIndex: Ref<number | null, number | null>focusedItemIndex === const index: numberindex, 'item-selected':
const selectedItem: Ref<{
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null, {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null>
selectedItem
?.listIndex: 0 | 1 | undefinedlistIndex === 0 &&
const selectedItem: Ref<{
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null, {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null>
selectedItem
?.itemIndex: numberitemIndex === const index: numberindex,
}" HTMLAttributes.tabindex?: Numberish | undefinedtabindex="-1" > {{ const item: stringitem }} </li: LiHTMLAttributes & ReservedPropsli> <li: LiHTMLAttributes & ReservedPropsli v-if="const items1: Ref<string[], string[]>items1.Array<string>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
=== 0" HTMLAttributes.class?: ClassValueclass="empty-list-message">Empty</li: LiHTMLAttributes & ReservedPropsli>
</ul: HTMLAttributes & ReservedPropsul> </div: HTMLAttributes & ReservedPropsdiv> <div: HTMLAttributes & ReservedPropsdiv HTMLAttributes.class?: ClassValueclass="list-wrapper"> <h2: HTMLAttributes & ReservedPropsh2 HTMLAttributes.id?: string | undefinedid="list2-heading">List 2</h2: HTMLAttributes & ReservedPropsh2> <ul: HTMLAttributes & ReservedPropsul ReservedProps.ref?: VNodeRef | undefinedref="list2Node: HTMLUListElementlist2Node" HTMLAttributes.class?: ClassValueclass="list" HTMLAttributes.tabindex?: Numberish | undefinedtabindex="0" HTMLAttributes.role?: string | undefinedrole="listbox" aria-labelledby="list2-heading" :aria-activedescendant=" const focusedListIndex: Ref<0 | 1 | null, 0 | 1 | null>focusedListIndex === 1 ? const focusedItemId: ComputedRef<string | undefined>focusedItemId : var undefinedundefined " @onFocus?: ((payload: FocusEvent) => void) | undefinedfocus="function handleListFocus(listIndex: 0 | 1): voidhandleListFocus(1)" @onBlur?: ((payload: FocusEvent) => void) | undefinedblur="function handleListBlur(): voidhandleListBlur" @onKeydown?: ((payload: KeyboardEvent) => void) | undefinedkeydown="function handleListKeydown(event: KeyboardEvent, listIndex: 0 | 1): Promise<void>handleListKeydown($event: KeyboardEvent$event, 1)" > <li: LiHTMLAttributes & ReservedPropsli v-for="(const item: stringitem, const index: numberindex) in const items2: Ref<string[], string[]>items2" ReservedProps.key?: PropertyKey | undefined:key="const item: stringitem" HTMLAttributes.id?: string | undefined:id="`list2-item-${const item: stringitem}`" HTMLAttributes.class?: ClassValueclass="item" HTMLAttributes.role?: string | undefinedrole="option" :aria-selected=" const focusedListIndex: Ref<0 | 1 | null, 0 | 1 | null>focusedListIndex === 1 && const focusedItemIndex: Ref<number | null, number | null>focusedItemIndex === const index: numberindex " HTMLAttributes.class?: ClassValue:class="{ 'item-focused': const focusedListIndex: Ref<0 | 1 | null, 0 | 1 | null>focusedListIndex === 1 && const focusedItemIndex: Ref<number | null, number | null>focusedItemIndex === const index: numberindex, 'item-selected':
const selectedItem: Ref<{
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null, {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null>
selectedItem
?.listIndex: 0 | 1 | undefinedlistIndex === 1 &&
const selectedItem: Ref<{
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null, {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null>
selectedItem
?.itemIndex: numberitemIndex === const index: numberindex,
}" HTMLAttributes.tabindex?: Numberish | undefinedtabindex="-1" > {{ const item: stringitem }} </li: LiHTMLAttributes & ReservedPropsli> <li: LiHTMLAttributes & ReservedPropsli v-if="const items2: Ref<string[], string[]>items2.Array<string>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
=== 0" HTMLAttributes.class?: ClassValueclass="empty-list-message">Empty</li: LiHTMLAttributes & ReservedPropsli>
</ul: HTMLAttributes & ReservedPropsul> </div: HTMLAttributes & ReservedPropsdiv> </div: HTMLAttributes & ReservedPropsdiv> <div: HTMLAttributes & ReservedPropsdiv HTMLAttributes.class?: ClassValueclass="instructions"> <h3: HTMLAttributes & ReservedPropsh3>Keyboard Instructions</h3: HTMLAttributes & ReservedPropsh3> <ul: HTMLAttributes & ReservedPropsul> <li: LiHTMLAttributes & ReservedPropsli>Use <kbd: HTMLAttributes & ReservedPropskbd>Tab</kbd: HTMLAttributes & ReservedPropskbd> or <kbd: HTMLAttributes & ReservedPropskbd>Shift+Tab</kbd: HTMLAttributes & ReservedPropskbd> to focus a list.</li: LiHTMLAttributes & ReservedPropsli> <li: LiHTMLAttributes & ReservedPropsli> Use <kbd: HTMLAttributes & ReservedPropskbd>↑</kbd: HTMLAttributes & ReservedPropskbd> / <kbd: HTMLAttributes & ReservedPropskbd>↓</kbd: HTMLAttributes & ReservedPropskbd> arrows to navigate items within the focused list. </li: LiHTMLAttributes & ReservedPropsli> <li: LiHTMLAttributes & ReservedPropsli> Press <kbd: HTMLAttributes & ReservedPropskbd>Spacebar</kbd: HTMLAttributes & ReservedPropskbd> to select/deselect the highlighted item for moving. </li: LiHTMLAttributes & ReservedPropsli> <li: LiHTMLAttributes & ReservedPropsli> With an item selected, use <kbd: HTMLAttributes & ReservedPropskbd>↑</kbd: HTMLAttributes & ReservedPropskbd> / <kbd: HTMLAttributes & ReservedPropskbd>↓</kbd: HTMLAttributes & ReservedPropskbd> (within the same or another focused list) to choose the drop position. </li: LiHTMLAttributes & ReservedPropsli> <li: LiHTMLAttributes & ReservedPropsli> Press <kbd: HTMLAttributes & ReservedPropskbd>Enter</kbd: HTMLAttributes & ReservedPropskbd> to drop the selected item at the highlighted position. </li: LiHTMLAttributes & ReservedPropsli> <li: LiHTMLAttributes & ReservedPropsli> Press <kbd: HTMLAttributes & ReservedPropskbd>Escape</kbd: HTMLAttributes & ReservedPropskbd> to cancel a selection or leave the list. </li: LiHTMLAttributes & ReservedPropsli> </ul: HTMLAttributes & ReservedPropsul> </div: HTMLAttributes & ReservedPropsdiv> </div: HTMLAttributes & ReservedPropsdiv> </template>
/** @jsxImportSource solid-js */
import { function createSignal<T>(): Signal<T | undefined> (+1 overload)
Creates a simple reactive state with a getter and setter ```typescript const [state: Accessor<T>, setState: Setter<T>] = createSignal<T>( value: T, options?: { name?: string, equals?: false | ((prev: T, next: T) => boolean) } ) ```
@paramvalue initial value of the state; if empty, the state's type will automatically extended with undefined; otherwise you need to extend the type manually if you want setting to undefined not be an error@paramoptions optional object with a name for debugging purposes and equals, a comparator function for the previous and next value to allow fine-grained control over the reactivity@returns```typescript [state: Accessor<T>, setState: Setter<T>] ``` * the Accessor is merely a function that returns the current value and registers each call to the reactive root * the Setter is a function that allows directly setting or mutating the value: ```typescript const [count, setCount] = createSignal(0); setCount(count => count + 1); ```@descriptionhttps://docs.solidjs.com/reference/basic-reactivity/create-signal
createSignal
, function createMemo<Next extends Prev, Prev = Next>(fn: EffectFunction<undefined | NoInfer<Prev>, Next>): Accessor<Next> (+1 overload)
Creates a readonly derived reactive memoized signal ```typescript export function createMemo<T>( fn: (v: T) => T, value?: T, options?: { name?: string, equals?: false | ((prev: T, next: T) => boolean) } ): () => T; ```
@paramfn a function that receives its previous or the initial value, if set, and returns a new value used to react on a computation@paramvalue an optional initial value for the computation; if set, fn will never receive undefined as first argument@paramoptions allows to set a name in dev mode for debugging purposes and use a custom comparison function in equals@descriptionhttps://docs.solidjs.com/reference/basic-reactivity/create-memo
createMemo
,
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
} from "solid-js";
import { function useDragAndDrop<E extends HTMLElement, T = unknown>(initValues: T[], options?: Partial<ParentConfig<T>>): [Setter<E | null>, Accessor<Store<T[]>>, ReturnType<typeof createStore>[1], (config?: Partial<ParentConfig<T>>) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paraminitValues - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
} from "@formkit/drag-and-drop/solid";
// Initial data for the lists const const initialItems1: string[]initialItems1 = ["Apples", "Bananas", "Oranges", "Grapes"]; const const initialItems2: string[]initialItems2 = ["Milk", "Cheese", "Yogurt"]; interface SelectedItem { SelectedItem.listIndex: 0 | 1listIndex: 0 | 1; SelectedItem.itemIndex: numberitemIndex: number; SelectedItem.value: stringvalue: string; } export default function function AccessibilityDemoSolid(): JSX.ElementAccessibilityDemoSolid() { // --- Refs and Signals --- const [const liveMessage: Accessor<string>liveMessage, const setLiveMessage: Setter<string>setLiveMessage] = createSignal<string>(value: string, options?: SignalOptions<string> | undefined): Signal<string> (+1 overload)
Creates a simple reactive state with a getter and setter ```typescript const [state: Accessor<T>, setState: Setter<T>] = createSignal<T>( value: T, options?: { name?: string, equals?: false | ((prev: T, next: T) => boolean) } ) ```
@paramvalue initial value of the state; if empty, the state's type will automatically extended with undefined; otherwise you need to extend the type manually if you want setting to undefined not be an error@paramoptions optional object with a name for debugging purposes and equals, a comparator function for the previous and next value to allow fine-grained control over the reactivity@returns```typescript [state: Accessor<T>, setState: Setter<T>] ``` * the Accessor is merely a function that returns the current value and registers each call to the reactive root * the Setter is a function that allows directly setting or mutating the value: ```typescript const [count, setCount] = createSignal(0); setCount(count => count + 1); ```@descriptionhttps://docs.solidjs.com/reference/basic-reactivity/create-signal
createSignal
("");
let let liveRegionRef: HTMLDivElement | undefinedliveRegionRef: HTMLDivElement | undefined; // Variables to hold the actual DOM elements for comparison let let list1RefEl: HTMLUListElement | undefinedlist1RefEl: HTMLUListElement | undefined; let let list2RefEl: HTMLUListElement | undefinedlist2RefEl: HTMLUListElement | undefined; // --- Announcer Function --- const const announce: (message: string) => voidannounce = (message: stringmessage: string) => { const setLiveMessage: <string>(value: string | ((prev: string) => string)) => string (+3 overloads)setLiveMessage(message: stringmessage); // Optional: Clear message after delay // setTimeout(() => setLiveMessage(''), 5000); }; // --- Drag and Drop Setup --- // useDragAndDrop returns [setRef, itemsSignal, setItemsSignal] in Solid const [const setList1Ref: Setter<HTMLUListElement | null>setList1Ref, const items1: Accessor<string[]>items1, const setItems1: SetStoreFunction<string[]>setItems1] = useDragAndDrop<HTMLUListElement, string>(initValues: string[], options?: Partial<ParentConfig<string>>): [Setter<HTMLUListElement | null>, Accessor<string[]>, SetStoreFunction<string[]>, (config?: Partial<ParentConfig<string>> | undefined) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paraminitValues - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
<
HTMLUListElement, string >(const initialItems1: string[]initialItems1, { group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "accessibleList",
// Let types be inferred onDragstart?: DragstartEvent<string> | undefined
Fired when a drag is started, whether native drag or synthetic
onDragstart
: (state: DragstartEventData<string>state) =>
const announce: (message: string) => voidannounce(`Drag started for ${state: DragstartEventData<string>state.DragstartEventData<string>.draggedNode: NodeRecord<string>draggedNode.NodeRecord<string>.data: NodeData<string>data.NodeData<string>.value: string
The value of the node.
value
}.`),
onSort?: SortEvent<string> | undefined
Callback function for when a sort operation is performed.
onSort
: (event: SortEventData<string>event) =>
const announce: (message: string) => voidannounce( `Sorted ${event: SortEventData<string>event.SortEventData<string>.draggedNodes: NodeRecord<string>[]draggedNodes[0].NodeRecord<string>.data: NodeData<string>data.NodeData<string>.value: string
The value of the node.
value
} in List 1 to position ${
event: SortEventData<string>event.SortEventData<string>.position: numberposition + 1 }.` ), onTransfer?: TransferEvent<string> | undefined
Callback function for when a transfer operation is performed.
onTransfer
: (event: TransferEventData<string>event) => {
// Compare event source element with the element stored in list1RefEl const announce: (message: string) => voidannounce( `Transferred ${event: TransferEventData<string>event.TransferEventData<string>.draggedNodes: NodeRecord<string>[]draggedNodes[0].NodeRecord<string>.data: NodeData<string>data.NodeData<string>.value: string
The value of the node.
value
} from List ${
event: TransferEventData<string>event.TransferEventData<string>.sourceParent: ParentRecord<string>sourceParent.ParentRecord<string>.el: HTMLElementel === let list1RefEl: HTMLUListElement | undefinedlist1RefEl ? 1 : 2 } to List 1 at position ${event: TransferEventData<string>event.TransferEventData<string>.targetIndex: numbertargetIndex + 1}.` ); }, onDragend?: DragendEvent<string> | undefined
Fired when a drag is ended, whether native drag or synthetic
onDragend
: (state: DragendEventData<string>state) =>
const announce: (message: string) => voidannounce(`Drag ended for ${state: DragendEventData<string>state.DragendEventData<string>.draggedNode: NodeRecord<string>draggedNode.NodeRecord<string>.data: NodeData<string>data.NodeData<string>.value: string
The value of the node.
value
}.`),
}); const [const setList2Ref: Setter<HTMLUListElement | null>setList2Ref, const items2: Accessor<string[]>items2, const setItems2: SetStoreFunction<string[]>setItems2] = useDragAndDrop<HTMLUListElement, string>(initValues: string[], options?: Partial<ParentConfig<string>>): [Setter<HTMLUListElement | null>, Accessor<string[]>, SetStoreFunction<string[]>, (config?: Partial<ParentConfig<string>> | undefined) => void]
Hook for adding drag and drop/sortable support to a list of items.
@paraminitValues - Initial list of data.@paramoptions - The drag and drop configuration.@returns
useDragAndDrop
<
HTMLUListElement, string >(const initialItems2: string[]initialItems2, { group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "accessibleList",
onDragstart?: DragstartEvent<string> | undefined
Fired when a drag is started, whether native drag or synthetic
onDragstart
: (state: DragstartEventData<string>state) =>
const announce: (message: string) => voidannounce(`Drag started for ${state: DragstartEventData<string>state.DragstartEventData<string>.draggedNode: NodeRecord<string>draggedNode.NodeRecord<string>.data: NodeData<string>data.NodeData<string>.value: string
The value of the node.
value
}.`),
onSort?: SortEvent<string> | undefined
Callback function for when a sort operation is performed.
onSort
: (event: SortEventData<string>event) =>
const announce: (message: string) => voidannounce( `Sorted ${event: SortEventData<string>event.SortEventData<string>.draggedNodes: NodeRecord<string>[]draggedNodes[0].NodeRecord<string>.data: NodeData<string>data.NodeData<string>.value: string
The value of the node.
value
} in List 2 to position ${
event: SortEventData<string>event.SortEventData<string>.position: numberposition + 1 }.` ), onTransfer?: TransferEvent<string> | undefined
Callback function for when a transfer operation is performed.
onTransfer
: (event: TransferEventData<string>event) => {
// Compare event source element with the element stored in list1RefEl const announce: (message: string) => voidannounce( `Transferred ${event: TransferEventData<string>event.TransferEventData<string>.draggedNodes: NodeRecord<string>[]draggedNodes[0].NodeRecord<string>.data: NodeData<string>data.NodeData<string>.value: string
The value of the node.
value
} from List ${
event: TransferEventData<string>event.TransferEventData<string>.sourceParent: ParentRecord<string>sourceParent.ParentRecord<string>.el: HTMLElementel === let list1RefEl: HTMLUListElement | undefinedlist1RefEl ? 1 : 2 } to List 2 at position ${event: TransferEventData<string>event.TransferEventData<string>.targetIndex: numbertargetIndex + 1}.` ); }, onDragend?: DragendEvent<string> | undefined
Fired when a drag is ended, whether native drag or synthetic
onDragend
: (state: DragendEventData<string>state) =>
const announce: (message: string) => voidannounce(`Drag ended for ${state: DragendEventData<string>state.DragendEventData<string>.draggedNode: NodeRecord<string>draggedNode.NodeRecord<string>.data: NodeData<string>data.NodeData<string>.value: string
The value of the node.
value
}.`),
}); // --- Keyboard Navigation State --- const [const focusedListIndex: Accessor<0 | 1 | null>focusedListIndex, const setFocusedListIndex: Setter<0 | 1 | null>setFocusedListIndex] = createSignal<0 | 1 | null>(value: 0 | 1 | null, options?: SignalOptions<0 | 1 | null> | undefined): Signal<0 | 1 | null> (+1 overload)
Creates a simple reactive state with a getter and setter ```typescript const [state: Accessor<T>, setState: Setter<T>] = createSignal<T>( value: T, options?: { name?: string, equals?: false | ((prev: T, next: T) => boolean) } ) ```
@paramvalue initial value of the state; if empty, the state's type will automatically extended with undefined; otherwise you need to extend the type manually if you want setting to undefined not be an error@paramoptions optional object with a name for debugging purposes and equals, a comparator function for the previous and next value to allow fine-grained control over the reactivity@returns```typescript [state: Accessor<T>, setState: Setter<T>] ``` * the Accessor is merely a function that returns the current value and registers each call to the reactive root * the Setter is a function that allows directly setting or mutating the value: ```typescript const [count, setCount] = createSignal(0); setCount(count => count + 1); ```@descriptionhttps://docs.solidjs.com/reference/basic-reactivity/create-signal
createSignal
<0 | 1 | null>(
null ); const [const focusedItemIndex: Accessor<number | null>focusedItemIndex, const setFocusedItemIndex: Setter<number | null>setFocusedItemIndex] = createSignal<number | null>(value: number | null, options?: SignalOptions<number | null> | undefined): Signal<number | null> (+1 overload)
Creates a simple reactive state with a getter and setter ```typescript const [state: Accessor<T>, setState: Setter<T>] = createSignal<T>( value: T, options?: { name?: string, equals?: false | ((prev: T, next: T) => boolean) } ) ```
@paramvalue initial value of the state; if empty, the state's type will automatically extended with undefined; otherwise you need to extend the type manually if you want setting to undefined not be an error@paramoptions optional object with a name for debugging purposes and equals, a comparator function for the previous and next value to allow fine-grained control over the reactivity@returns```typescript [state: Accessor<T>, setState: Setter<T>] ``` * the Accessor is merely a function that returns the current value and registers each call to the reactive root * the Setter is a function that allows directly setting or mutating the value: ```typescript const [count, setCount] = createSignal(0); setCount(count => count + 1); ```@descriptionhttps://docs.solidjs.com/reference/basic-reactivity/create-signal
createSignal
<number | null>(
null ); const [const selectedItem: Accessor<SelectedItem | null>selectedItem, const setSelectedItem: Setter<SelectedItem | null>setSelectedItem] = createSignal<SelectedItem | null>(value: SelectedItem | null, options?: SignalOptions<SelectedItem | null> | undefined): Signal<SelectedItem | null> (+1 overload)
Creates a simple reactive state with a getter and setter ```typescript const [state: Accessor<T>, setState: Setter<T>] = createSignal<T>( value: T, options?: { name?: string, equals?: false | ((prev: T, next: T) => boolean) } ) ```
@paramvalue initial value of the state; if empty, the state's type will automatically extended with undefined; otherwise you need to extend the type manually if you want setting to undefined not be an error@paramoptions optional object with a name for debugging purposes and equals, a comparator function for the previous and next value to allow fine-grained control over the reactivity@returns```typescript [state: Accessor<T>, setState: Setter<T>] ``` * the Accessor is merely a function that returns the current value and registers each call to the reactive root * the Setter is a function that allows directly setting or mutating the value: ```typescript const [count, setCount] = createSignal(0); setCount(count => count + 1); ```@descriptionhttps://docs.solidjs.com/reference/basic-reactivity/create-signal
createSignal
<SelectedItem | null>(
null ); // --- Computed Values --- const const focusedItemId: Accessor<string | undefined>focusedItemId = createMemo<string | undefined, string | undefined>(fn: EffectFunction<string | undefined, string | undefined>): Accessor<string | undefined> (+1 overload)
Creates a readonly derived reactive memoized signal ```typescript export function createMemo<T>( fn: (v: T) => T, value?: T, options?: { name?: string, equals?: false | ((prev: T, next: T) => boolean) } ): () => T; ```
@paramfn a function that receives its previous or the initial value, if set, and returns a new value used to react on a computation@paramvalue an optional initial value for the computation; if set, fn will never receive undefined as first argument@paramoptions allows to set a name in dev mode for debugging purposes and use a custom comparison function in equals@descriptionhttps://docs.solidjs.com/reference/basic-reactivity/create-memo
createMemo
(() => {
const const listIndex: 0 | 1 | nulllistIndex = const focusedListIndex: () => 0 | 1 | nullfocusedListIndex(); const const itemIndex: number | nullitemIndex = const focusedItemIndex: () => number | nullfocusedItemIndex(); const const currentItems: string[]currentItems = const listIndex: 0 | 1 | nulllistIndex === 0 ? const items1: () => string[]items1() : const items2: () => string[]items2(); // Access signal value const const prefix: "list1-item" | "list2-item"prefix = const listIndex: 0 | 1 | nulllistIndex === 0 ? "list1-item" : "list2-item"; if ( const itemIndex: number | nullitemIndex !== null && const itemIndex: numberitemIndex >= 0 && const itemIndex: numberitemIndex < const currentItems: string[]currentItems.Array<string>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
) { return `${const prefix: "list1-item" | "list2-item"prefix}-${const currentItems: string[]currentItems[const itemIndex: numberitemIndex]}`; } return var undefinedundefined; }); // --- Event Handlers --- const const handleListFocus: (listIndex: 0 | 1) => voidhandleListFocus = (listIndex: 0 | 1listIndex: 0 | 1) => { const setFocusedListIndex: <0 | 1>(value: 0 | 1 | ((prev: 0 | 1 | null) => 0 | 1)) => 0 | 1 (+3 overloads)setFocusedListIndex(listIndex: 0 | 1listIndex); const const currentItems: string[]currentItems = listIndex: 0 | 1listIndex === 0 ? const items1: () => string[]items1() : const items2: () => string[]items2(); if (const focusedItemIndex: () => number | nullfocusedItemIndex() === null && const currentItems: string[]currentItems.Array<string>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
> 0) {
const setFocusedItemIndex: <0>(value: 0 | ((prev: number | null) => 0)) => 0 (+3 overloads)setFocusedItemIndex(0); } const announce: (message: string) => voidannounce( `List ${listIndex: 0 | 1listIndex + 1} focused. Use up and down arrows to navigate items.` ); }; const const handleListBlur: () => voidhandleListBlur = () => { // Basic blur handling }; const const handleListKeydown: (event: KeyboardEvent, listIndex: 0 | 1) => voidhandleListKeydown = (event: KeyboardEventevent: KeyboardEvent, listIndex: 0 | 1listIndex: 0 | 1) => { if (const focusedListIndex: () => 0 | 1 | nullfocusedListIndex() !== listIndex: 0 | 1listIndex) return; const const currentItems: string[]currentItems = listIndex: 0 | 1listIndex === 0 ? const items1: () => string[]items1() : const items2: () => string[]items2(); const const setItems: SetStoreFunction<string[]>setItems = listIndex: 0 | 1listIndex === 0 ? const setItems1: SetStoreFunction<string[]>setItems1 : const setItems2: SetStoreFunction<string[]>setItems2; const const currentItemIndex: number | nullcurrentItemIndex = const focusedItemIndex: () => number | nullfocusedItemIndex(); // Access signal value switch (event: KeyboardEventevent.KeyboardEvent.key: string
The KeyboardEvent interface's **`key`** read-only property returns the value of the key pressed by the user, taking into consideration the state of modifier keys such as Shift as well as the keyboard locale and layout. [MDN Reference](https://developer.mozilla.org/docs/Web/API/KeyboardEvent/key)
key
) {
case "ArrowDown": event: KeyboardEventevent.Event.preventDefault(): void
The **`preventDefault()`** method of the Event interface tells the user agent that the event is being explicitly handled, so its default action, such as page scrolling, link navigation, or pasting text, should not be taken. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/preventDefault)
preventDefault
();
if (const currentItems: string[]currentItems.Array<string>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
> 0) {
const const nextIndex: numbernextIndex = const currentItemIndex: number | nullcurrentItemIndex === null ? 0 : (const currentItemIndex: numbercurrentItemIndex + 1) % const currentItems: string[]currentItems.Array<string>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
;
const setFocusedItemIndex: <number>(value: number | ((prev: number | null) => number)) => number (+3 overloads)setFocusedItemIndex(const nextIndex: numbernextIndex); const announce: (message: string) => voidannounce(const currentItems: string[]currentItems[const nextIndex: numbernextIndex]); } break; case "ArrowUp": event: KeyboardEventevent.Event.preventDefault(): void
The **`preventDefault()`** method of the Event interface tells the user agent that the event is being explicitly handled, so its default action, such as page scrolling, link navigation, or pasting text, should not be taken. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/preventDefault)
preventDefault
();
if (const currentItems: string[]currentItems.Array<string>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
> 0) {
const const prevIndex: numberprevIndex = const currentItemIndex: number | nullcurrentItemIndex === null ? const currentItems: string[]currentItems.Array<string>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
- 1
: (const currentItemIndex: numbercurrentItemIndex - 1 + const currentItems: string[]currentItems.Array<string>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
) %
const currentItems: string[]currentItems.Array<string>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
;
const setFocusedItemIndex: <number>(value: number | ((prev: number | null) => number)) => number (+3 overloads)setFocusedItemIndex(const prevIndex: numberprevIndex); const announce: (message: string) => voidannounce(const currentItems: string[]currentItems[const prevIndex: numberprevIndex]); } break; case " ": // Spacebar event: KeyboardEventevent.Event.preventDefault(): void
The **`preventDefault()`** method of the Event interface tells the user agent that the event is being explicitly handled, so its default action, such as page scrolling, link navigation, or pasting text, should not be taken. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/preventDefault)
preventDefault
();
if ( const currentItemIndex: number | nullcurrentItemIndex !== null && const currentItemIndex: numbercurrentItemIndex >= 0 && const currentItemIndex: numbercurrentItemIndex < const currentItems: string[]currentItems.Array<string>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
) { const const currentItemValue: stringcurrentItemValue = const currentItems: string[]currentItems[const currentItemIndex: numbercurrentItemIndex]; const const currentSelection: SelectedItem | nullcurrentSelection = const selectedItem: () => SelectedItem | nullselectedItem(); // Access signal value if ( const currentSelection: SelectedItem | nullcurrentSelection?.SelectedItem.listIndex: 0 | 1 | undefinedlistIndex === listIndex: 0 | 1listIndex && const currentSelection: SelectedItemcurrentSelection?.SelectedItem.itemIndex: numberitemIndex === const currentItemIndex: numbercurrentItemIndex ) { const setSelectedItem: <null>(value: ((prev: SelectedItem | null) => null) | null) => null (+3 overloads)setSelectedItem(null); const announce: (message: string) => voidannounce(`${const currentItemValue: stringcurrentItemValue} deselected.`); } else {
const setSelectedItem: <{
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
}>(value: {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | ((prev: SelectedItem | null) => {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
})) => {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} (+3 overloads)
setSelectedItem
({
listIndex: 0 | 1listIndex, itemIndex: numberitemIndex: const currentItemIndex: numbercurrentItemIndex, value: stringvalue: const currentItemValue: stringcurrentItemValue, }); const announce: (message: string) => voidannounce( `${const currentItemValue: stringcurrentItemValue} selected. Use arrow keys to choose drop position, then press Enter.` ); } } break; case "Enter": event: KeyboardEventevent.Event.preventDefault(): void
The **`preventDefault()`** method of the Event interface tells the user agent that the event is being explicitly handled, so its default action, such as page scrolling, link navigation, or pasting text, should not be taken. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/preventDefault)
preventDefault
();
const const currentSelection: SelectedItem | nullcurrentSelection = const selectedItem: () => SelectedItem | nullselectedItem(); // Access signal value if ( const currentSelection: SelectedItem | nullcurrentSelection && const currentItemIndex: number | nullcurrentItemIndex !== null && const currentItemIndex: numbercurrentItemIndex >= 0 && const currentItemIndex: numbercurrentItemIndex < const currentItems: string[]currentItems.Array<string>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
) { const { SelectedItem.listIndex: 0 | 1listIndex: const sourceListIndex: 0 | 1sourceListIndex, SelectedItem.itemIndex: numberitemIndex: const sourceItemIndex: numbersourceItemIndex, SelectedItem.value: stringvalue: const itemValue: stringitemValue, } = const currentSelection: SelectedItemcurrentSelection; const const targetListIndex: 0 | 1targetListIndex = listIndex: 0 | 1listIndex; const const targetItemIndex: numbertargetItemIndex = const currentItemIndex: numbercurrentItemIndex; if ( const sourceListIndex: 0 | 1sourceListIndex === const targetListIndex: 0 | 1targetListIndex && const sourceItemIndex: numbersourceItemIndex === const targetItemIndex: numbertargetItemIndex ) { const announce: (message: string) => voidannounce(`Keyboard: Cannot drop ${const itemValue: stringitemValue} onto itself.`); const setSelectedItem: <null>(value: ((prev: SelectedItem | null) => null) | null) => null (+3 overloads)setSelectedItem(null); break; } const const sourceItemsArray: string[]sourceItemsArray = const sourceListIndex: 0 | 1sourceListIndex === 0 ? const items1: () => string[]items1() : const items2: () => string[]items2(); const const setSourceItems: SetStoreFunction<string[]>setSourceItems = const sourceListIndex: 0 | 1sourceListIndex === 0 ? const setItems1: SetStoreFunction<string[]>setItems1 : const setItems2: SetStoreFunction<string[]>setItems2; const const targetItemsArray: string[]targetItemsArray = const targetListIndex: 0 | 1targetListIndex === 0 ? const items1: () => string[]items1() : const items2: () => string[]items2(); const const setTargetItems: SetStoreFunction<string[]>setTargetItems = const targetListIndex: 0 | 1targetListIndex === 0 ? const setItems1: SetStoreFunction<string[]>setItems1 : const setItems2: SetStoreFunction<string[]>setItems2; const const newSourceItems: string[]newSourceItems = [...const sourceItemsArray: string[]sourceItemsArray]; const newSourceItems: string[]newSourceItems.Array<string>.splice(start: number, deleteCount?: number): string[] (+1 overload)
Removes elements from an array and, if necessary, inserts new elements in their place, returning the deleted elements.
@paramstart The zero-based location in the array from which to start removing elements.@paramdeleteCount The number of elements to remove. Omitting this argument will remove all elements from the start paramater location to end of the array. If value of this argument is either a negative number, zero, undefined, or a type that cannot be converted to an integer, the function will evaluate the argument as zero and not remove any elements.@returnsAn array containing the elements that were deleted.
splice
(const sourceItemIndex: numbersourceItemIndex, 1);
const const newTargetItems: string[]newTargetItems = const sourceListIndex: 0 | 1sourceListIndex === const targetListIndex: 0 | 1targetListIndex ? const newSourceItems: string[]newSourceItems : [...const targetItemsArray: string[]targetItemsArray]; let let effectiveTargetIndex: numbereffectiveTargetIndex = const targetItemIndex: numbertargetItemIndex; if (const sourceListIndex: 0 | 1sourceListIndex === const targetListIndex: 0 | 1targetListIndex) { if (const sourceItemIndex: numbersourceItemIndex < const targetItemIndex: numbertargetItemIndex) { let effectiveTargetIndex: numbereffectiveTargetIndex = const targetItemIndex: numbertargetItemIndex - 1; } else { let effectiveTargetIndex: numbereffectiveTargetIndex = const targetItemIndex: numbertargetItemIndex; } } else { let effectiveTargetIndex: numbereffectiveTargetIndex = const targetItemIndex: numbertargetItemIndex; } let effectiveTargetIndex: numbereffectiveTargetIndex = var Math: Math
An intrinsic object that provides basic mathematics functionality and constants.
Math
.Math.max(...values: number[]): number
Returns the larger of a set of supplied numeric expressions.
@paramvalues Numeric expressions to be evaluated.
max
(
0, var Math: Math
An intrinsic object that provides basic mathematics functionality and constants.
Math
.Math.min(...values: number[]): number
Returns the smaller of a set of supplied numeric expressions.
@paramvalues Numeric expressions to be evaluated.
min
(let effectiveTargetIndex: numbereffectiveTargetIndex, const newTargetItems: string[]newTargetItems.Array<string>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
)
); const newTargetItems: string[]newTargetItems.Array<string>.splice(start: number, deleteCount: number, ...items: string[]): string[] (+1 overload)
Removes elements from an array and, if necessary, inserts new elements in their place, returning the deleted elements.
@paramstart The zero-based location in the array from which to start removing elements.@paramdeleteCount The number of elements to remove. If value of this argument is either a negative number, zero, undefined, or a type that cannot be converted to an integer, the function will evaluate the argument as zero and not remove any elements.@paramitems Elements to insert into the array in place of the deleted elements.@returnsAn array containing the elements that were deleted.
splice
(let effectiveTargetIndex: numbereffectiveTargetIndex, 0, const itemValue: stringitemValue);
// Use signal setters to update state
const setSourceItems: SetStoreFunction
(setter: StoreSetter<string[], []>) => void (+8 overloads)
setSourceItems
(const newSourceItems: string[]newSourceItems);
if (const sourceListIndex: 0 | 1sourceListIndex !== const targetListIndex: 0 | 1targetListIndex) {
const setTargetItems: SetStoreFunction
(setter: StoreSetter<string[], []>) => void (+8 overloads)
setTargetItems
(const newTargetItems: string[]newTargetItems);
} // If same list, setSourceItems updated the array const announce: (message: string) => voidannounce( `Keyboard: Moved ${const itemValue: stringitemValue} to position ${ let effectiveTargetIndex: numbereffectiveTargetIndex + 1 } in List ${const targetListIndex: 0 | 1targetListIndex + 1}.` ); const setSelectedItem: <null>(value: ((prev: SelectedItem | null) => null) | null) => null (+3 overloads)setSelectedItem(null); const setFocusedItemIndex: <number>(value: number | ((prev: number | null) => number)) => number (+3 overloads)setFocusedItemIndex(let effectiveTargetIndex: numbereffectiveTargetIndex); const setFocusedListIndex: <0 | 1>(value: 0 | 1 | ((prev: 0 | 1 | null) => 0 | 1)) => 0 | 1 (+3 overloads)setFocusedListIndex(const targetListIndex: 0 | 1targetListIndex); } break; case "Escape": event: KeyboardEventevent.Event.preventDefault(): void
The **`preventDefault()`** method of the Event interface tells the user agent that the event is being explicitly handled, so its default action, such as page scrolling, link navigation, or pasting text, should not be taken. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/preventDefault)
preventDefault
();
if (const selectedItem: () => SelectedItem | nullselectedItem()) { // Access signal value const announce: (message: string) => voidannounce(`Selection cancelled for ${const selectedItem: () => SelectedItem | nullselectedItem()!.SelectedItem.value: stringvalue}.`); const setSelectedItem: <null>(value: ((prev: SelectedItem | null) => null) | null) => null (+3 overloads)setSelectedItem(null); } else { const announce: (message: string) => voidannounce("Escape pressed. No item selected."); (event: KeyboardEventevent.Event.target: EventTarget | null
The read-only **`target`** property of the Event interface is a reference to the object onto which the event was dispatched. It is different from Event.currentTarget when the event handler is called during the bubbling or capturing phase of the event. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/target)
target
as HTMLElement).HTMLOrSVGElement.blur(): void
[MDN Reference](https://developer.mozilla.org/docs/Web/API/HTMLElement/blur)
blur
();
const setFocusedListIndex: <null>(value: ((prev: 0 | 1 | null) => null) | null) => null (+3 overloads)setFocusedListIndex(null); const setFocusedItemIndex: <null>(value: ((prev: number | null) => null) | null) => null (+3 overloads)setFocusedItemIndex(null); } break; default: return; } }; // --- JSX --- return ( // Using a standard div wrapper <JSX.HTMLElementTags.div: JSX.HTMLAttributes<HTMLDivElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/div@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLDivElement
div
JSX.DOMAttributes<HTMLDivElement>.class?: string | undefinedclass="container p-4 border-4 border-blue-300">
<JSX.HTMLElementTags.h1: JSX.HTMLAttributes<HTMLHeadingElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/h1@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLHeadingElement
h1
JSX.DOMAttributes<T>.class?: string | undefinedclass="text-xl font-bold mb-4">SolidJS Accessibility Demo</JSX.HTMLElementTags.h1: JSX.HTMLAttributes<HTMLHeadingElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/h1@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLHeadingElement
h1
>
<JSX.HTMLElementTags.div: JSX.HTMLAttributes<HTMLDivElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/div@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLDivElement
div
JSX.DOMAttributes<HTMLDivElement>.class?: string | undefinedclass="accessibility-demo">
{/* ARIA Live Region */} <JSX.HTMLElementTags.div: JSX.HTMLAttributes<HTMLDivElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/div@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLDivElement
div
ref?: HTMLDivElement | ((el: HTMLDivElement) => void) | undefinedref={let liveRegionRef: HTMLDivElement | undefinedliveRegionRef} JSX.AriaAttributes["aria-live"]?: "polite" | "off" | "assertive" | undefined
Indicates that an element will be updated, and describes the types of updates the user agents, assistive technologies, and user can expect from the live region.
aria-live
="polite" JSX.DOMAttributes<HTMLDivElement>.class?: string | undefinedclass="sr-only">
{const liveMessage: () => stringliveMessage()} {/* Access signal value */} </JSX.HTMLElementTags.div: JSX.HTMLAttributes<HTMLDivElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/div@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLDivElement
div
>
<JSX.HTMLElementTags.div: JSX.HTMLAttributes<HTMLDivElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/div@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLDivElement
div
JSX.DOMAttributes<HTMLDivElement>.class?: string | undefinedclass="lists-container">
{/* List 1 */} <JSX.HTMLElementTags.div: JSX.HTMLAttributes<HTMLDivElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/div@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLDivElement
div
JSX.DOMAttributes<HTMLDivElement>.class?: string | undefinedclass="list-wrapper">
<JSX.HTMLElementTags.h2: JSX.HTMLAttributes<HTMLHeadingElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/h2@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLHeadingElement
h2
JSX.DOMAttributes<HTMLHeadingElement>.id?: string | undefinedid="list1-item-heading">List 1</JSX.HTMLElementTags.h2: JSX.HTMLAttributes<HTMLHeadingElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/h2@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLHeadingElement
h2
>
<JSX.HTMLElementTags.ul: JSX.HTMLAttributes<HTMLUListElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLUListElement
ul
// Assign element to variable via ref callback ref?: HTMLUListElement | ((el: HTMLUListElement) => void) | undefinedref={let list1RefEl: HTMLUListElement | undefinedlist1RefEl} // Assign element directly JSX.DOMAttributes<T>.class?: string | undefinedclass="list" JSX.DOMAttributes<HTMLUListElement>.tabindex?: string | number | undefinedtabindex="0" JSX.AriaAttributes.role?: "group" | "list" | "listbox" | "alert" | "alertdialog" | "application" | "article" | "banner" | "button" | "cell" | "checkbox" | "columnheader" | "combobox" | "complementary" | "contentinfo" | "definition" | "dialog" | "directory" | "document" | "feed" | "figure" | "form" | "grid" | "gridcell" | "heading" | "img" | "link" | "listitem" | "log" | "main" | "marquee" | "math" | "menu" | "menubar" | "menuitem" | "menuitemcheckbox" | "menuitemradio" | "meter" | "navigation" | "none" | "note" | "option" | "presentation" | "progressbar" | "radio" | ... 25 more ... | undefinedrole="listbox" JSX.AriaAttributes["aria-labelledby"]?: string | undefined
Identifies the element (or elements) that labels the current element.
@seearia-describedby.
aria-labelledby
="list1-item-heading"
JSX.AriaAttributes["aria-activedescendant"]?: string | undefined
Identifies the currently active element when DOM focus is on a composite widget, textbox, group, or application.
aria-activedescendant
={
const focusedListIndex: () => 0 | 1 | nullfocusedListIndex() === 0 ? const focusedItemId: () => string | undefinedfocusedItemId() : var undefinedundefined } JSX.CustomEventHandlersCamelCase<HTMLUListElement>.onFocus?: JSX.FocusEventHandlerUnion<HTMLUListElement, FocusEvent> | undefinedonFocus={() => const handleListFocus: (listIndex: 0 | 1) => voidhandleListFocus(0)} JSX.CustomEventHandlersCamelCase<HTMLUListElement>.onBlur?: JSX.FocusEventHandlerUnion<HTMLUListElement, FocusEvent> | undefinedonBlur={const handleListBlur: () => voidhandleListBlur} JSX.CustomEventHandlersCamelCase<HTMLUListElement>.onKeyDown?: JSX.EventHandlerUnion<HTMLUListElement, KeyboardEvent, JSX.EventHandler<HTMLUListElement, KeyboardEvent>> | undefinedonKeyDown={(
e: KeyboardEvent & {
    currentTarget: HTMLUListElement;
    target: DOMElement;
}
e
) => const handleListKeydown: (event: KeyboardEvent, listIndex: 0 | 1) => voidhandleListKeydown(
e: KeyboardEvent & {
    currentTarget: HTMLUListElement;
    target: DOMElement;
}
e
, 0)}
> <
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
each: false | string[] | null | undefinedeach={const items1: () => string[]items1()} fallback?: JSX.Elementfallback={<JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
JSX.DOMAttributes<T>.class?: string | undefinedclass="empty-list-message">Empty</JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
>}
> {(item: stringitem, index: Accessor<number>index) => { // Use memos or functions for computed values inside For if needed const const isFocused: () => booleanisFocused = () => const focusedListIndex: () => 0 | 1 | nullfocusedListIndex() === 0 && const focusedItemIndex: () => number | nullfocusedItemIndex() === index: () => numberindex(); const const isSelected: () => booleanisSelected = () => const selectedItem: () => SelectedItem | nullselectedItem()?.SelectedItem.listIndex: 0 | 1 | undefinedlistIndex === 0 && const selectedItem: () => SelectedItem | nullselectedItem()?.SelectedItem.itemIndex: number | undefineditemIndex === index: () => numberindex(); const const itemId: () => stringitemId = () => `list1-item-${item: stringitem}`; return ( <JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
JSX.DOMAttributes<T>.id?: string | undefinedid={const itemId: () => stringitemId()} // Use classList directive for dynamic classes
JSX.CustomAttributes<HTMLLIElement>.classList?: {
    [k: string]: boolean | undefined;
} | undefined
classList
={{
item: trueitem: true, "item-focused": const isFocused: () => booleanisFocused(), "item-selected": const isSelected: () => booleanisSelected(), }} JSX.AriaAttributes.role?: "group" | "list" | "listbox" | "alert" | "alertdialog" | "application" | "article" | "banner" | "button" | "cell" | "checkbox" | "columnheader" | "combobox" | "complementary" | "contentinfo" | "definition" | "dialog" | "directory" | "document" | "feed" | "figure" | "form" | "grid" | "gridcell" | "heading" | "img" | "link" | "listitem" | "log" | "main" | "marquee" | "math" | "menu" | "menubar" | "menuitem" | "menuitemcheckbox" | "menuitemradio" | "meter" | "navigation" | "none" | "note" | "option" | "presentation" | "progressbar" | "radio" | ... 25 more ... | undefinedrole="option" JSX.AriaAttributes["aria-selected"]?: boolean | "false" | "true" | undefined
Indicates the current "selected" state of various widgets.
@seearia-checked@seearia-pressed.
aria-selected
={const isFocused: () => booleanisFocused()}
JSX.DOMAttributes<T>.tabindex?: string | number | undefinedtabindex="-1" > {item: stringitem} </JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
>
); }} </
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
>
</JSX.HTMLElementTags.ul: JSX.HTMLAttributes<HTMLUListElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLUListElement
ul
>
</JSX.HTMLElementTags.div: JSX.HTMLAttributes<HTMLDivElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/div@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLDivElement
div
>
{/* List 2 */} <JSX.HTMLElementTags.div: JSX.HTMLAttributes<HTMLDivElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/div@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLDivElement
div
JSX.DOMAttributes<HTMLDivElement>.class?: string | undefinedclass="list-wrapper">
<JSX.HTMLElementTags.h2: JSX.HTMLAttributes<HTMLHeadingElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/h2@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLHeadingElement
h2
JSX.DOMAttributes<HTMLHeadingElement>.id?: string | undefinedid="list2-item-heading">List 2</JSX.HTMLElementTags.h2: JSX.HTMLAttributes<HTMLHeadingElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/h2@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLHeadingElement
h2
>
<JSX.HTMLElementTags.ul: JSX.HTMLAttributes<HTMLUListElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLUListElement
ul
ref?: HTMLUListElement | ((el: HTMLUListElement) => void) | undefinedref={let list2RefEl: HTMLUListElement | undefinedlist2RefEl} // Assign element directly JSX.DOMAttributes<T>.class?: string | undefinedclass="list" JSX.DOMAttributes<HTMLUListElement>.tabindex?: string | number | undefinedtabindex="0" JSX.AriaAttributes.role?: "group" | "list" | "listbox" | "alert" | "alertdialog" | "application" | "article" | "banner" | "button" | "cell" | "checkbox" | "columnheader" | "combobox" | "complementary" | "contentinfo" | "definition" | "dialog" | "directory" | "document" | "feed" | "figure" | "form" | "grid" | "gridcell" | "heading" | "img" | "link" | "listitem" | "log" | "main" | "marquee" | "math" | "menu" | "menubar" | "menuitem" | "menuitemcheckbox" | "menuitemradio" | "meter" | "navigation" | "none" | "note" | "option" | "presentation" | "progressbar" | "radio" | ... 25 more ... | undefinedrole="listbox" JSX.AriaAttributes["aria-labelledby"]?: string | undefined
Identifies the element (or elements) that labels the current element.
@seearia-describedby.
aria-labelledby
="list2-item-heading"
JSX.AriaAttributes["aria-activedescendant"]?: string | undefined
Identifies the currently active element when DOM focus is on a composite widget, textbox, group, or application.
aria-activedescendant
={
const focusedListIndex: () => 0 | 1 | nullfocusedListIndex() === 1 ? const focusedItemId: () => string | undefinedfocusedItemId() : var undefinedundefined } JSX.CustomEventHandlersCamelCase<HTMLUListElement>.onFocus?: JSX.FocusEventHandlerUnion<HTMLUListElement, FocusEvent> | undefinedonFocus={() => const handleListFocus: (listIndex: 0 | 1) => voidhandleListFocus(1)} JSX.CustomEventHandlersCamelCase<HTMLUListElement>.onBlur?: JSX.FocusEventHandlerUnion<HTMLUListElement, FocusEvent> | undefinedonBlur={const handleListBlur: () => voidhandleListBlur} JSX.CustomEventHandlersCamelCase<HTMLUListElement>.onKeyDown?: JSX.EventHandlerUnion<HTMLUListElement, KeyboardEvent, JSX.EventHandler<HTMLUListElement, KeyboardEvent>> | undefinedonKeyDown={(
e: KeyboardEvent & {
    currentTarget: HTMLUListElement;
    target: DOMElement;
}
e
) => const handleListKeydown: (event: KeyboardEvent, listIndex: 0 | 1) => voidhandleListKeydown(
e: KeyboardEvent & {
    currentTarget: HTMLUListElement;
    target: DOMElement;
}
e
, 1)}
> <
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
each: false | string[] | null | undefinedeach={const items2: () => string[]items2()} fallback?: JSX.Elementfallback={<JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
JSX.DOMAttributes<T>.class?: string | undefinedclass="empty-list-message">Empty</JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
>}
> {(item: stringitem, index: Accessor<number>index) => { const const isFocused: () => booleanisFocused = () => const focusedListIndex: () => 0 | 1 | nullfocusedListIndex() === 1 && const focusedItemIndex: () => number | nullfocusedItemIndex() === index: () => numberindex(); const const isSelected: () => booleanisSelected = () => const selectedItem: () => SelectedItem | nullselectedItem()?.SelectedItem.listIndex: 0 | 1 | undefinedlistIndex === 1 && const selectedItem: () => SelectedItem | nullselectedItem()?.SelectedItem.itemIndex: number | undefineditemIndex === index: () => numberindex(); const const itemId: () => stringitemId = () => `list2-item-${item: stringitem}`; return ( <JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
JSX.DOMAttributes<T>.id?: string | undefinedid={const itemId: () => stringitemId()}
JSX.CustomAttributes<HTMLLIElement>.classList?: {
    [k: string]: boolean | undefined;
} | undefined
classList
={{
item: trueitem: true, "item-focused": const isFocused: () => booleanisFocused(), "item-selected": const isSelected: () => booleanisSelected(), }} JSX.AriaAttributes.role?: "group" | "list" | "listbox" | "alert" | "alertdialog" | "application" | "article" | "banner" | "button" | "cell" | "checkbox" | "columnheader" | "combobox" | "complementary" | "contentinfo" | "definition" | "dialog" | "directory" | "document" | "feed" | "figure" | "form" | "grid" | "gridcell" | "heading" | "img" | "link" | "listitem" | "log" | "main" | "marquee" | "math" | "menu" | "menubar" | "menuitem" | "menuitemcheckbox" | "menuitemradio" | "meter" | "navigation" | "none" | "note" | "option" | "presentation" | "progressbar" | "radio" | ... 25 more ... | undefinedrole="option" JSX.AriaAttributes["aria-selected"]?: boolean | "false" | "true" | undefined
Indicates the current "selected" state of various widgets.
@seearia-checked@seearia-pressed.
aria-selected
={const isFocused: () => booleanisFocused()}
JSX.DOMAttributes<T>.tabindex?: string | number | undefinedtabindex="-1" > {item: stringitem} </JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
>
); }} </
function For<T extends readonly any[], U extends JSX.Element>(props: {
    each: T | undefined | null | false;
    fallback?: JSX.Element;
    children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element
Creates a list elements from a list it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned: ```typescript <For each={items} fallback={<div>No items</div>}> {(item, index) => <div data-index={index()}>{item}</div>} </For> ``` If you have a list with fixed indices and changing values, consider using `<Index>` instead.
@descriptionhttps://docs.solidjs.com/reference/components/for
For
>
</JSX.HTMLElementTags.ul: JSX.HTMLAttributes<HTMLUListElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLUListElement
ul
>
</JSX.HTMLElementTags.div: JSX.HTMLAttributes<HTMLDivElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/div@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLDivElement
div
>
</JSX.HTMLElementTags.div: JSX.HTMLAttributes<HTMLDivElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/div@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLDivElement
div
>
{/* Instructions */} <JSX.HTMLElementTags.div: JSX.HTMLAttributes<HTMLDivElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/div@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLDivElement
div
JSX.DOMAttributes<HTMLDivElement>.class?: string | undefinedclass="instructions">
<JSX.HTMLElementTags.h3: JSX.HTMLAttributes<HTMLHeadingElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/h3@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLHeadingElement
h3
>Keyboard Instructions</JSX.HTMLElementTags.h3: JSX.HTMLAttributes<HTMLHeadingElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/h3@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLHeadingElement
h3
>
<JSX.HTMLElementTags.ul: JSX.HTMLAttributes<HTMLUListElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLUListElement
ul
>
<JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
>
Use <JSX.HTMLElementTags.kbd: JSX.HTMLAttributes<HTMLElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/kbd@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLElement
kbd
>Tab</JSX.HTMLElementTags.kbd: JSX.HTMLAttributes<HTMLElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/kbd@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLElement
kbd
> or <JSX.HTMLElementTags.kbd: JSX.HTMLAttributes<HTMLElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/kbd@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLElement
kbd
>Shift+Tab</JSX.HTMLElementTags.kbd: JSX.HTMLAttributes<HTMLElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/kbd@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLElement
kbd
> to focus a list.
</JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
>
<JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
>
Use <JSX.HTMLElementTags.kbd: JSX.HTMLAttributes<HTMLElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/kbd@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLElement
kbd
>↑</JSX.HTMLElementTags.kbd: JSX.HTMLAttributes<HTMLElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/kbd@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLElement
kbd
> / <JSX.HTMLElementTags.kbd: JSX.HTMLAttributes<HTMLElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/kbd@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLElement
kbd
>↓</JSX.HTMLElementTags.kbd: JSX.HTMLAttributes<HTMLElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/kbd@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLElement
kbd
> arrows to navigate items within
the focused list. </JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
>
<JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
>
Press <JSX.HTMLElementTags.kbd: JSX.HTMLAttributes<HTMLElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/kbd@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLElement
kbd
>Spacebar</JSX.HTMLElementTags.kbd: JSX.HTMLAttributes<HTMLElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/kbd@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLElement
kbd
> to select/deselect the highlighted item
for moving. </JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
>
<JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
>
With an item selected, use <JSX.HTMLElementTags.kbd: JSX.HTMLAttributes<HTMLElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/kbd@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLElement
kbd
>↑</JSX.HTMLElementTags.kbd: JSX.HTMLAttributes<HTMLElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/kbd@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLElement
kbd
> / <JSX.HTMLElementTags.kbd: JSX.HTMLAttributes<HTMLElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/kbd@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLElement
kbd
>↓</JSX.HTMLElementTags.kbd: JSX.HTMLAttributes<HTMLElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/kbd@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLElement
kbd
> (within the
same or another focused list) to choose the drop position. </JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
>
<JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
>
Press <JSX.HTMLElementTags.kbd: JSX.HTMLAttributes<HTMLElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/kbd@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLElement
kbd
>Enter</JSX.HTMLElementTags.kbd: JSX.HTMLAttributes<HTMLElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/kbd@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLElement
kbd
> to drop the selected item at the
highlighted position. </JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
>
<JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
>
Press <JSX.HTMLElementTags.kbd: JSX.HTMLAttributes<HTMLElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/kbd@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLElement
kbd
>Escape</JSX.HTMLElementTags.kbd: JSX.HTMLAttributes<HTMLElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/kbd@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLElement
kbd
> to cancel a selection or leave the list.
</JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/li@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement
li
>
</JSX.HTMLElementTags.ul: JSX.HTMLAttributes<HTMLUListElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLUListElement
ul
>
</JSX.HTMLElementTags.div: JSX.HTMLAttributes<HTMLDivElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/div@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLDivElement
div
>
</JSX.HTMLElementTags.div: JSX.HTMLAttributes<HTMLDivElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/div@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLDivElement
div
>
{/* Styles needed externally */} </JSX.HTMLElementTags.div: JSX.HTMLAttributes<HTMLDivElement>
@urlhttps://developer.mozilla.org/en-US/docs/Web/HTML/Element/div@urlhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLDivElement
div
>
); }
import { function dragAndDrop<T>({ parent, getValues, setValues, config, }: DragAndDrop<T>): void
Initializes the drag and drop functionality for a given parent.
@paramdragAndDrop - The drag and drop configuration.@returnsvoid
dragAndDrop
} from "@formkit/drag-and-drop";
import type { interface DragstartEventData<T>DragstartEventData, interface SortEventData<T>SortEventData, interface TransferEventData<T>TransferEventData, interface DragendEventData<T>DragendEventData, } from "@formkit/drag-and-drop"; // --- State Management --- let let items1: string[]items1 = ["Apples", "Bananas", "Oranges", "Grapes"]; let let items2: string[]items2 = ["Milk", "Cheese", "Yogurt"]; let let focusedListIndex: 0 | 1 | nullfocusedListIndex: 0 | 1 | null = null; let let focusedItemIndex: number | nullfocusedItemIndex: number | null = null; let
let selectedItem: {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null
selectedItem
: {
listIndex: 0 | 1listIndex: 0 | 1; itemIndex: numberitemIndex: number; value: stringvalue: string; } | null = null; let let liveMessage: stringliveMessage = ""; // --- DOM References (Assume these elements exist in the HTML) --- const const list1Element: HTMLUListElementlist1Element = var document: Document
**`window.document`** returns a reference to the document contained in the window. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)
document
.Document.getElementById(elementId: string): HTMLElement | null
The **`getElementById()`** method of the Document interface returns an Element object representing the element whose id property matches the specified string. Since element IDs are required to be unique if specified, they're a useful way to get access to a specific element quickly.
getElementById
("list1") as HTMLUListElement;
const const list2Element: HTMLUListElementlist2Element = var document: Document
**`window.document`** returns a reference to the document contained in the window. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)
document
.Document.getElementById(elementId: string): HTMLElement | null
The **`getElementById()`** method of the Document interface returns an Element object representing the element whose id property matches the specified string. Since element IDs are required to be unique if specified, they're a useful way to get access to a specific element quickly.
getElementById
("list2") as HTMLUListElement;
const const liveRegionElement: HTMLDivElementliveRegionElement = var document: Document
**`window.document`** returns a reference to the document contained in the window. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)
document
.Document.getElementById(elementId: string): HTMLElement | null
The **`getElementById()`** method of the Document interface returns an Element object representing the element whose id property matches the specified string. Since element IDs are required to be unique if specified, they're a useful way to get access to a specific element quickly.
getElementById
(
"live-region" ) as HTMLDivElement; if (!const list1Element: HTMLUListElementlist1Element || !const list2Element: HTMLUListElementlist2Element || !const liveRegionElement: HTMLDivElementliveRegionElement) { var console: Consoleconsole.Console.error(...data: any[]): void
The **`console.error()`** static method outputs a message to the console at the "error" log level. The message is only displayed to the user if the console is configured to display error output. In most cases, the log level is configured within the console UI. The message may be formatted as an error, with red colors and call stack information. [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/error_static)
error
("Required DOM elements not found for accessibility demo.");
// Handle the error appropriately, maybe return or throw } const
const lists: {
    el: HTMLUListElement;
    items: () => string[];
    setItems: (newItems: string[]) => void;
    idPrefix: string;
    name: string;
}[]
lists
= [
{ el: HTMLUListElementel: const list1Element: HTMLUListElementlist1Element, items: () => string[]items: () => let items1: string[]items1, setItems: (newItems: string[]) => voidsetItems: (newItems: string[]newItems: string[]) => { let items1: string[]items1 = newItems: string[]newItems; }, idPrefix: stringidPrefix: "list1-item", name: stringname: "List 1", }, { el: HTMLUListElementel: const list2Element: HTMLUListElementlist2Element, items: () => string[]items: () => let items2: string[]items2, setItems: (newItems: string[]) => voidsetItems: (newItems: string[]newItems: string[]) => { let items2: string[]items2 = newItems: string[]newItems; }, idPrefix: stringidPrefix: "list2-item", name: stringname: "List 2", }, ]; // --- ARIA Live Region --- function function announce(message: string): voidannounce(message: stringmessage: string) { let liveMessage: stringliveMessage = message: stringmessage; if (const liveRegionElement: HTMLDivElementliveRegionElement) { const liveRegionElement: HTMLDivElementliveRegionElement.Element.textContent: string | null
[MDN Reference](https://developer.mozilla.org/docs/Web/API/Node/textContent)
textContent
= let liveMessage: stringliveMessage;
} // Optional: Clear message after delay // setTimeout(() => { if (liveRegionElement) liveRegionElement.textContent = ''; }, 5000); } // --- Rendering --- function function renderList(listIndex: 0 | 1): voidrenderList(listIndex: 0 | 1listIndex: 0 | 1) { const
const listData: {
    el: HTMLUListElement;
    items: () => string[];
    setItems: (newItems: string[]) => void;
    idPrefix: string;
    name: string;
}
listData
=
const lists: {
    el: HTMLUListElement;
    items: () => string[];
    setItems: (newItems: string[]) => void;
    idPrefix: string;
    name: string;
}[]
lists
[listIndex: 0 | 1listIndex];
if (!
const listData: {
    el: HTMLUListElement;
    items: () => string[];
    setItems: (newItems: string[]) => void;
    idPrefix: string;
    name: string;
}
listData
|| !
const listData: {
    el: HTMLUListElement;
    items: () => string[];
    setItems: (newItems: string[]) => void;
    idPrefix: string;
    name: string;
}
listData
.el: HTMLUListElementel) return;
const const currentItems: string[]currentItems =
const listData: {
    el: HTMLUListElement;
    items: () => string[];
    setItems: (newItems: string[]) => void;
    idPrefix: string;
    name: string;
}
listData
.items: () => string[]items();
const listData: {
    el: HTMLUListElement;
    items: () => string[];
    setItems: (newItems: string[]) => void;
    idPrefix: string;
    name: string;
}
listData
.el: HTMLUListElementel.Element.innerHTML: string
The **`innerHTML`** property of the Element interface gets or sets the HTML or XML markup contained within the element, omitting any shadow roots in both cases. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Element/innerHTML)
innerHTML
= ""; // Clear existing items
if (const currentItems: string[]currentItems.Array<string>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
=== 0) {
const const li: HTMLLIElementli = var document: Document
**`window.document`** returns a reference to the document contained in the window. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)
document
.Document.createElement<"li">(tagName: "li", options?: ElementCreationOptions): HTMLLIElement (+2 overloads)
In an HTML document, the **`document.createElement()`** method creates the HTML element specified by localName, or an HTMLUnknownElement if localName isn't recognized. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Document/createElement)
createElement
("li");
const li: HTMLLIElementli.Element.className: string
The **`className`** property of the Element interface gets and sets the value of the class attribute of the specified element. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Element/className)
className
= "empty-list-message";
const li: HTMLLIElementli.Element.textContent: string | null
[MDN Reference](https://developer.mozilla.org/docs/Web/API/Node/textContent)
textContent
= "Empty";
const listData: {
    el: HTMLUListElement;
    items: () => string[];
    setItems: (newItems: string[]) => void;
    idPrefix: string;
    name: string;
}
listData
.el: HTMLUListElementel.Node.appendChild<HTMLLIElement>(node: HTMLLIElement): HTMLLIElement
The **`appendChild()`** method of the Node interface adds a node to the end of the list of children of a specified parent node. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Node/appendChild)
appendChild
(const li: HTMLLIElementli);
// Clear active descendant when list is empty
const listData: {
    el: HTMLUListElement;
    items: () => string[];
    setItems: (newItems: string[]) => void;
    idPrefix: string;
    name: string;
}
listData
.el: HTMLUListElementel.Element.removeAttribute(qualifiedName: string): void
The Element method **`removeAttribute()`** removes the attribute with the specified name from the element. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Element/removeAttribute)
removeAttribute
("aria-activedescendant");
return; } const currentItems: string[]currentItems.Array<string>.forEach(callbackfn: (value: string, index: number, array: string[]) => void, thisArg?: any): void
Performs the specified action for each element in an array.
@paramcallbackfn A function that accepts up to three arguments. forEach calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
forEach
((item: stringitem, index: numberindex) => {
const const li: HTMLLIElementli = var document: Document
**`window.document`** returns a reference to the document contained in the window. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)
document
.Document.createElement<"li">(tagName: "li", options?: ElementCreationOptions): HTMLLIElement (+2 overloads)
In an HTML document, the **`document.createElement()`** method creates the HTML element specified by localName, or an HTMLUnknownElement if localName isn't recognized. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Document/createElement)
createElement
("li");
const const itemId: stringitemId = `${
const listData: {
    el: HTMLUListElement;
    items: () => string[];
    setItems: (newItems: string[]) => void;
    idPrefix: string;
    name: string;
}
listData
.idPrefix: stringidPrefix}-${item: stringitem}`; // Consider making IDs more robust if items can have same name
const li: HTMLLIElementli.Element.id: string
The **`id`** property of the Element interface represents the element's identifier, reflecting the id global attribute. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Element/id)
id
= const itemId: stringitemId;
const li: HTMLLIElementli.Element.className: string
The **`className`** property of the Element interface gets and sets the value of the class attribute of the specified element. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Element/className)
className
= "item";
const li: HTMLLIElementli.Element.setAttribute(qualifiedName: string, value: string): void
The **`setAttribute()`** method of the Element interface sets the value of an attribute on the specified element. If the attribute already exists, the value is updated; otherwise a new attribute is added with the specified name and value. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Element/setAttribute)
setAttribute
("role", "option");
const li: HTMLLIElementli.Element.setAttribute(qualifiedName: string, value: string): void
The **`setAttribute()`** method of the Element interface sets the value of an attribute on the specified element. If the attribute already exists, the value is updated; otherwise a new attribute is added with the specified name and value. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Element/setAttribute)
setAttribute
("tabindex", "-1"); // Items are not directly tabbable
const li: HTMLLIElementli.Element.textContent: string | null
[MDN Reference](https://developer.mozilla.org/docs/Web/API/Node/textContent)
textContent
= item: stringitem;
const const isFocused: booleanisFocused = let focusedListIndex: 0 | 1 | nullfocusedListIndex === listIndex: 0 | 1listIndex && let focusedItemIndex: number | nullfocusedItemIndex === index: numberindex; const const isSelected: booleanisSelected =
let selectedItem: {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null
selectedItem
?.listIndex: 0 | 1 | undefinedlistIndex === listIndex: 0 | 1listIndex &&
let selectedItem: {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
}
selectedItem
?.itemIndex: numberitemIndex === index: numberindex;
const li: HTMLLIElementli.Element.setAttribute(qualifiedName: string, value: string): void
The **`setAttribute()`** method of the Element interface sets the value of an attribute on the specified element. If the attribute already exists, the value is updated; otherwise a new attribute is added with the specified name and value. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Element/setAttribute)
setAttribute
("aria-selected",
var String: StringConstructor
(value?: any) => string
Allows manipulation and formatting of text strings and determination and location of substrings within strings.
String
(const isFocused: booleanisFocused)); // Reflect focus state
if (const isFocused: booleanisFocused) { const li: HTMLLIElementli.Element.classList: DOMTokenList
The read-only **`classList`** property of the Element interface contains a live DOMTokenList collection representing the class attribute of the element. This can then be used to manipulate the class list. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Element/classList)
classList
.DOMTokenList.add(...tokens: string[]): void
The **`add()`** method of the DOMTokenList interface adds the given tokens to the list, omitting any that are already present. [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMTokenList/add)
add
("item-focused");
} else { const li: HTMLLIElementli.Element.classList: DOMTokenList
The read-only **`classList`** property of the Element interface contains a live DOMTokenList collection representing the class attribute of the element. This can then be used to manipulate the class list. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Element/classList)
classList
.DOMTokenList.remove(...tokens: string[]): void
The **`remove()`** method of the DOMTokenList interface removes the specified tokens from the list. [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMTokenList/remove)
remove
("item-focused");
} if (const isSelected: booleanisSelected) { const li: HTMLLIElementli.Element.classList: DOMTokenList
The read-only **`classList`** property of the Element interface contains a live DOMTokenList collection representing the class attribute of the element. This can then be used to manipulate the class list. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Element/classList)
classList
.DOMTokenList.add(...tokens: string[]): void
The **`add()`** method of the DOMTokenList interface adds the given tokens to the list, omitting any that are already present. [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMTokenList/add)
add
("item-selected");
} else { const li: HTMLLIElementli.Element.classList: DOMTokenList
The read-only **`classList`** property of the Element interface contains a live DOMTokenList collection representing the class attribute of the element. This can then be used to manipulate the class list. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Element/classList)
classList
.DOMTokenList.remove(...tokens: string[]): void
The **`remove()`** method of the DOMTokenList interface removes the specified tokens from the list. [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMTokenList/remove)
remove
("item-selected");
}
const listData: {
    el: HTMLUListElement;
    items: () => string[];
    setItems: (newItems: string[]) => void;
    idPrefix: string;
    name: string;
}
listData
.el: HTMLUListElementel.Node.appendChild<HTMLLIElement>(node: HTMLLIElement): HTMLLIElement
The **`appendChild()`** method of the Node interface adds a node to the end of the list of children of a specified parent node. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Node/appendChild)
appendChild
(const li: HTMLLIElementli);
}); // Update aria-activedescendant on the list itself if ( let focusedListIndex: 0 | 1 | nullfocusedListIndex === listIndex: 0 | 1listIndex && let focusedItemIndex: number | nullfocusedItemIndex !== null && let focusedItemIndex: numberfocusedItemIndex < const currentItems: string[]currentItems.Array<string>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
) { const const activeDescendantId: stringactiveDescendantId = `${
const listData: {
    el: HTMLUListElement;
    items: () => string[];
    setItems: (newItems: string[]) => void;
    idPrefix: string;
    name: string;
}
listData
.idPrefix: stringidPrefix}-${const currentItems: string[]currentItems[let focusedItemIndex: numberfocusedItemIndex]}`;
const listData: {
    el: HTMLUListElement;
    items: () => string[];
    setItems: (newItems: string[]) => void;
    idPrefix: string;
    name: string;
}
listData
.el: HTMLUListElementel.Element.setAttribute(qualifiedName: string, value: string): void
The **`setAttribute()`** method of the Element interface sets the value of an attribute on the specified element. If the attribute already exists, the value is updated; otherwise a new attribute is added with the specified name and value. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Element/setAttribute)
setAttribute
("aria-activedescendant", const activeDescendantId: stringactiveDescendantId);
} else {
const listData: {
    el: HTMLUListElement;
    items: () => string[];
    setItems: (newItems: string[]) => void;
    idPrefix: string;
    name: string;
}
listData
.el: HTMLUListElementel.Element.removeAttribute(qualifiedName: string): void
The Element method **`removeAttribute()`** removes the attribute with the specified name from the element. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Element/removeAttribute)
removeAttribute
("aria-activedescendant");
} } // --- Drag and Drop Initialization --- dragAndDrop<string>({ parent, getValues, setValues, config, }: DragAndDrop<string>): void
Initializes the drag and drop functionality for a given parent.
@paramdragAndDrop - The drag and drop configuration.@returnsvoid
dragAndDrop
<string>({
// List 1 DragAndDrop<string>.parent: HTMLElement
The parent element that will contain the draggable nodes.
parent
: const list1Element: HTMLUListElementlist1Element,
DragAndDrop<string>.getValues: (parent: HTMLElement) => string[]
A function that returns the values assigned to the parent.
getValues
: () => let items1: string[]items1,
DragAndDrop<string>.setValues: (values: string[], parent: HTMLElement) => void
A function that sets the values assigned to the parent.
setValues
: (newValues: string[]newValues) => {
let items1: string[]items1 = newValues: string[]newValues; function renderList(listIndex: 0 | 1): voidrenderList(0); // If items were potentially transferred from list 2, ensure it's re-rendered // Note: The library should ideally handle calling setValues on the source list too. // If it doesn't reliably, we might need a flag or check here. // For simplicity, we assume the library calls setValues on both lists involved in a transfer. }, DragAndDrop<string>.config?: Partial<ParentConfig<string>> | undefined
An optional configuration object.
config
: {
group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "accessibleList",
onDragstart?: DragstartEvent<string> | undefined
Fired when a drag is started, whether native drag or synthetic
onDragstart
: (state: DragstartEventData<string>state) =>
function announce(message: string): voidannounce(`Drag started for ${state: DragstartEventData<string>state.DragstartEventData<string>.draggedNode: NodeRecord<string>draggedNode.NodeRecord<string>.data: NodeData<string>data.NodeData<string>.value: string
The value of the node.
value
}.`),
onSort?: SortEvent<string> | undefined
Callback function for when a sort operation is performed.
onSort
: (event: SortEventData<string>event) =>
function announce(message: string): voidannounce( `Sorted ${event: SortEventData<string>event.SortEventData<string>.draggedNodes: NodeRecord<string>[]draggedNodes[0].NodeRecord<string>.data: NodeData<string>data.NodeData<string>.value: string
The value of the node.
value
} in List 1 to position ${
event: SortEventData<string>event.SortEventData<string>.position: numberposition + 1 }.` ), onTransfer?: TransferEvent<string> | undefined
Callback function for when a transfer operation is performed.
onTransfer
: (event: TransferEventData<string>event) => {
function announce(message: string): voidannounce( `Transferred ${event: TransferEventData<string>event.TransferEventData<string>.draggedNodes: NodeRecord<string>[]draggedNodes[0].NodeRecord<string>.data: NodeData<string>data.NodeData<string>.value: string
The value of the node.
value
} from List ${
event: TransferEventData<string>event.TransferEventData<string>.sourceParent: ParentRecord<string>sourceParent.ParentRecord<string>.el: HTMLElementel === const list1Element: HTMLUListElementlist1Element ? 1 : 2 } to List 1 at position ${event: TransferEventData<string>event.TransferEventData<string>.targetIndex: numbertargetIndex + 1}.` ); // Since setValues in the target (list 1) already re-renders list 1, // and we assume the lib calls setValues on source (list 2), list 2 should also re-render. }, onDragend?: DragendEvent<string> | undefined
Fired when a drag is ended, whether native drag or synthetic
onDragend
: (state: DragendEventData<string>state) =>
function announce(message: string): voidannounce(`Drag ended for ${state: DragendEventData<string>state.DragendEventData<string>.draggedNode: NodeRecord<string>draggedNode.NodeRecord<string>.data: NodeData<string>data.NodeData<string>.value: string
The value of the node.
value
}.`),
}, }); dragAndDrop<string>({ parent, getValues, setValues, config, }: DragAndDrop<string>): void
Initializes the drag and drop functionality for a given parent.
@paramdragAndDrop - The drag and drop configuration.@returnsvoid
dragAndDrop
<string>({
// List 2 DragAndDrop<string>.parent: HTMLElement
The parent element that will contain the draggable nodes.
parent
: const list2Element: HTMLUListElementlist2Element,
DragAndDrop<string>.getValues: (parent: HTMLElement) => string[]
A function that returns the values assigned to the parent.
getValues
: () => let items2: string[]items2,
DragAndDrop<string>.setValues: (values: string[], parent: HTMLElement) => void
A function that sets the values assigned to the parent.
setValues
: (newValues: string[]newValues) => {
let items2: string[]items2 = newValues: string[]newValues; function renderList(listIndex: 0 | 1): voidrenderList(1); }, DragAndDrop<string>.config?: Partial<ParentConfig<string>> | undefined
An optional configuration object.
config
: {
group?: string | undefined
The group that the parent belongs to. This is used for allowing multiple parents to transfer nodes between each other.
group
: "accessibleList",
onDragstart?: DragstartEvent<string> | undefined
Fired when a drag is started, whether native drag or synthetic
onDragstart
: (state: DragstartEventData<string>state) =>
function announce(message: string): voidannounce(`Drag started for ${state: DragstartEventData<string>state.DragstartEventData<string>.draggedNode: NodeRecord<string>draggedNode.NodeRecord<string>.data: NodeData<string>data.NodeData<string>.value: string
The value of the node.
value
}.`),
onSort?: SortEvent<string> | undefined
Callback function for when a sort operation is performed.
onSort
: (event: SortEventData<string>event) =>
function announce(message: string): voidannounce( `Sorted ${event: SortEventData<string>event.SortEventData<string>.draggedNodes: NodeRecord<string>[]draggedNodes[0].NodeRecord<string>.data: NodeData<string>data.NodeData<string>.value: string
The value of the node.
value
} in List 2 to position ${
event: SortEventData<string>event.SortEventData<string>.position: numberposition + 1 }.` ), onTransfer?: TransferEvent<string> | undefined
Callback function for when a transfer operation is performed.
onTransfer
: (event: TransferEventData<string>event) => {
function announce(message: string): voidannounce( `Transferred ${event: TransferEventData<string>event.TransferEventData<string>.draggedNodes: NodeRecord<string>[]draggedNodes[0].NodeRecord<string>.data: NodeData<string>data.NodeData<string>.value: string
The value of the node.
value
} from List ${
event: TransferEventData<string>event.TransferEventData<string>.sourceParent: ParentRecord<string>sourceParent.ParentRecord<string>.el: HTMLElementel === const list1Element: HTMLUListElementlist1Element ? 1 : 2 } to List 2 at position ${event: TransferEventData<string>event.TransferEventData<string>.targetIndex: numbertargetIndex + 1}.` ); // Assume setValues on source (list 1) handles its re-render. }, onDragend?: DragendEvent<string> | undefined
Fired when a drag is ended, whether native drag or synthetic
onDragend
: (state: DragendEventData<string>state) =>
function announce(message: string): voidannounce(`Drag ended for ${state: DragendEventData<string>state.DragendEventData<string>.draggedNode: NodeRecord<string>draggedNode.NodeRecord<string>.data: NodeData<string>data.NodeData<string>.value: string
The value of the node.
value
}.`),
}, }); // --- Event Handlers --- function function handleFocus(listIndex: 0 | 1): voidhandleFocus(listIndex: 0 | 1listIndex: 0 | 1) { let focusedListIndex: 0 | 1 | nullfocusedListIndex = listIndex: 0 | 1listIndex; const const currentItems: string[]currentItems =
const lists: {
    el: HTMLUListElement;
    items: () => string[];
    setItems: (newItems: string[]) => void;
    idPrefix: string;
    name: string;
}[]
lists
[listIndex: 0 | 1listIndex].items: () => string[]items();
if (let focusedItemIndex: number | nullfocusedItemIndex === null && const currentItems: string[]currentItems.Array<string>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
> 0) {
let focusedItemIndex: number | nullfocusedItemIndex = 0; // Default to first item on focus } function announce(message: string): voidannounce( `List ${listIndex: 0 | 1listIndex + 1} focused. Use up and down arrows to navigate items.` ); function renderList(listIndex: 0 | 1): voidrenderList(listIndex: 0 | 1listIndex); // Update focused list visuals // Render the other list to remove potential old focus styles function renderList(listIndex: 0 | 1): voidrenderList(listIndex: 0 | 1listIndex === 0 ? 1 : 0); } function function handleBlur(event: FocusEvent, listIndex: 0 | 1): voidhandleBlur(event: FocusEventevent: FocusEvent, listIndex: 0 | 1listIndex: 0 | 1) { // Simple blur handling: Reset focus only if focus moves outside the component entirely. // A more robust solution might involve checking relatedTarget against a container element. // For this example, we'll reset if focus leaves the list element itself. const const listElement: HTMLUListElementlistElement =
const lists: {
    el: HTMLUListElement;
    items: () => string[];
    setItems: (newItems: string[]) => void;
    idPrefix: string;
    name: string;
}[]
lists
[listIndex: 0 | 1listIndex].el: HTMLUListElementel;
// Check if relatedTarget is null or outside the current list element if ( !event: FocusEventevent.FocusEvent.relatedTarget: EventTarget | null
The **`relatedTarget`** read-only property of the FocusEvent interface is the secondary target, depending on the type of event: [MDN Reference](https://developer.mozilla.org/docs/Web/API/FocusEvent/relatedTarget)
relatedTarget
||
(event: FocusEventevent.FocusEvent.relatedTarget: EventTarget
The **`relatedTarget`** read-only property of the FocusEvent interface is the secondary target, depending on the type of event: [MDN Reference](https://developer.mozilla.org/docs/Web/API/FocusEvent/relatedTarget)
relatedTarget
instanceof
var Node: {
    new (): Node;
    prototype: Node;
    readonly ELEMENT_NODE: 1;
    readonly ATTRIBUTE_NODE: 2;
    readonly TEXT_NODE: 3;
    readonly CDATA_SECTION_NODE: 4;
    readonly ENTITY_REFERENCE_NODE: 5;
    readonly ENTITY_NODE: 6;
    readonly PROCESSING_INSTRUCTION_NODE: 7;
    readonly COMMENT_NODE: 8;
    readonly DOCUMENT_NODE: 9;
    readonly DOCUMENT_TYPE_NODE: 10;
    readonly DOCUMENT_FRAGMENT_NODE: 11;
    readonly NOTATION_NODE: 12;
    readonly DOCUMENT_POSITION_DISCONNECTED: 1;
    readonly DOCUMENT_POSITION_PRECEDING: 2;
    readonly DOCUMENT_POSITION_FOLLOWING: 4;
    readonly DOCUMENT_POSITION_CONTAINS: 8;
    readonly DOCUMENT_POSITION_CONTAINED_BY: 16;
    readonly DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC: 32;
}
The DOM **`Node`** interface is an abstract base class upon which many other DOM API objects are based, thus letting those object types be used similarly and often interchangeably. As an abstract class, there is no such thing as a plain Node object. All objects that implement Node functionality are based on one of its subclasses. Most notable are Document, Element, and DocumentFragment. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Node)
Node
&&
!const listElement: HTMLUListElementlistElement.Node.contains(other: Node | null): boolean
The **`contains()`** method of the Node interface returns a boolean value indicating whether a node is a descendant of a given node, that is the node itself, one of its direct children (childNodes), one of the children's direct children, and so on. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Node/contains)
contains
(event: FocusEventevent.FocusEvent.relatedTarget: Node
The **`relatedTarget`** read-only property of the FocusEvent interface is the secondary target, depending on the type of event: [MDN Reference](https://developer.mozilla.org/docs/Web/API/FocusEvent/relatedTarget)
relatedTarget
))
) { // Check if focus moved to the *other* list, if so, handleFocus will manage it. const const otherListIndex: 0 | 1otherListIndex = listIndex: 0 | 1listIndex === 0 ? 1 : 0; const const otherListElement: HTMLUListElementotherListElement =
const lists: {
    el: HTMLUListElement;
    items: () => string[];
    setItems: (newItems: string[]) => void;
    idPrefix: string;
    name: string;
}[]
lists
[const otherListIndex: 0 | 1otherListIndex].el: HTMLUListElementel;
if (event: FocusEventevent.FocusEvent.relatedTarget: Node | null
The **`relatedTarget`** read-only property of the FocusEvent interface is the secondary target, depending on the type of event: [MDN Reference](https://developer.mozilla.org/docs/Web/API/FocusEvent/relatedTarget)
relatedTarget
!== const otherListElement: HTMLUListElementotherListElement) {
let focusedListIndex: 0 | 1 | nullfocusedListIndex = null; let focusedItemIndex: number | nullfocusedItemIndex = null; // Don't announce blur unless necessary, can be noisy // announce("List blurred."); function renderList(listIndex: 0 | 1): voidrenderList(listIndex: 0 | 1listIndex); // Re-render to remove focus styles } } } function function handleKeydown(event: KeyboardEvent, listIndex: 0 | 1): voidhandleKeydown(event: KeyboardEventevent: KeyboardEvent, listIndex: 0 | 1listIndex: 0 | 1) { if (let focusedListIndex: 0 | 1 | nullfocusedListIndex !== listIndex: 0 | 1listIndex) return; const const currentItems: string[]currentItems =
const lists: {
    el: HTMLUListElement;
    items: () => string[];
    setItems: (newItems: string[]) => void;
    idPrefix: string;
    name: string;
}[]
lists
[listIndex: 0 | 1listIndex].items: () => string[]items();
let let currentItemIndex: number | nullcurrentItemIndex = let focusedItemIndex: number | nullfocusedItemIndex; // Use local var for modifications switch (event: KeyboardEventevent.KeyboardEvent.key: string
The KeyboardEvent interface's **`key`** read-only property returns the value of the key pressed by the user, taking into consideration the state of modifier keys such as Shift as well as the keyboard locale and layout. [MDN Reference](https://developer.mozilla.org/docs/Web/API/KeyboardEvent/key)
key
) {
case "ArrowDown": case "ArrowUp": event: KeyboardEventevent.Event.preventDefault(): void
The **`preventDefault()`** method of the Event interface tells the user agent that the event is being explicitly handled, so its default action, such as page scrolling, link navigation, or pasting text, should not be taken. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/preventDefault)
preventDefault
();
if (const currentItems: string[]currentItems.Array<string>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
> 0) {
let let nextIndex: anynextIndex; if (event: KeyboardEventevent.KeyboardEvent.key: "ArrowDown" | "ArrowUp"
The KeyboardEvent interface's **`key`** read-only property returns the value of the key pressed by the user, taking into consideration the state of modifier keys such as Shift as well as the keyboard locale and layout. [MDN Reference](https://developer.mozilla.org/docs/Web/API/KeyboardEvent/key)
key
=== "ArrowDown") {
let nextIndex: anynextIndex = let currentItemIndex: number | nullcurrentItemIndex === null ? 0 : (let currentItemIndex: numbercurrentItemIndex + 1) % const currentItems: string[]currentItems.Array<string>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
;
} else { // ArrowUp let nextIndex: anynextIndex = let currentItemIndex: number | nullcurrentItemIndex === null ? const currentItems: string[]currentItems.Array<string>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
- 1
: (let currentItemIndex: numbercurrentItemIndex - 1 + const currentItems: string[]currentItems.Array<string>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
) %
const currentItems: string[]currentItems.Array<string>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
;
} let focusedItemIndex: number | nullfocusedItemIndex = let nextIndex: numbernextIndex; // Update state function announce(message: string): voidannounce(const currentItems: string[]currentItems[let nextIndex: numbernextIndex]); function renderList(listIndex: 0 | 1): voidrenderList(listIndex: 0 | 1listIndex); // Re-render to update focus style and aria-activedescendant } break; case " ": // Spacebar event: KeyboardEventevent.Event.preventDefault(): void
The **`preventDefault()`** method of the Event interface tells the user agent that the event is being explicitly handled, so its default action, such as page scrolling, link navigation, or pasting text, should not be taken. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/preventDefault)
preventDefault
();
if ( let currentItemIndex: number | nullcurrentItemIndex !== null && let currentItemIndex: numbercurrentItemIndex >= 0 && let currentItemIndex: numbercurrentItemIndex < const currentItems: string[]currentItems.Array<string>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
) { const const currentItemValue: stringcurrentItemValue = const currentItems: string[]currentItems[let currentItemIndex: numbercurrentItemIndex]; if (
let selectedItem: {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null
selectedItem
?.listIndex: 0 | 1 | undefinedlistIndex === listIndex: 0 | 1listIndex &&
let selectedItem: {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
}
selectedItem
?.itemIndex: numberitemIndex === let currentItemIndex: numbercurrentItemIndex
) {
let selectedItem: {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null
selectedItem
= null; // Deselect
function announce(message: string): voidannounce(`${const currentItemValue: stringcurrentItemValue} deselected.`); } else {
let selectedItem: {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null
selectedItem
= {
listIndex: 0 | 1listIndex, itemIndex: numberitemIndex: let currentItemIndex: numbercurrentItemIndex, value: stringvalue: const currentItemValue: stringcurrentItemValue, }; // Select function announce(message: string): voidannounce( `${const currentItemValue: stringcurrentItemValue} selected. Use arrow keys to choose drop position, then press Enter.` ); } function renderList(listIndex: 0 | 1): voidrenderList(listIndex: 0 | 1listIndex); // Re-render to update selection style } break; case "Enter": event: KeyboardEventevent.Event.preventDefault(): void
The **`preventDefault()`** method of the Event interface tells the user agent that the event is being explicitly handled, so its default action, such as page scrolling, link navigation, or pasting text, should not be taken. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/preventDefault)
preventDefault
();
if (
let selectedItem: {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null
selectedItem
&&
let currentItemIndex: number | nullcurrentItemIndex !== null && let currentItemIndex: numbercurrentItemIndex >= 0 && let currentItemIndex: numbercurrentItemIndex < const currentItems: string[]currentItems.Array<string>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
) { const { listIndex: 0 | 1listIndex: const sourceListIndex: 0 | 1sourceListIndex, itemIndex: numberitemIndex: const sourceItemIndex: numbersourceItemIndex, value: stringvalue: const itemValue: stringitemValue, } =
let selectedItem: {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
}
selectedItem
;
const const targetListIndex: 0 | 1targetListIndex = listIndex: 0 | 1listIndex; const const targetItemIndex: numbertargetItemIndex = let currentItemIndex: numbercurrentItemIndex; if ( const sourceListIndex: 0 | 1sourceListIndex === const targetListIndex: 0 | 1targetListIndex && const sourceItemIndex: numbersourceItemIndex === const targetItemIndex: numbertargetItemIndex ) { function announce(message: string): voidannounce(`Keyboard: Cannot drop ${const itemValue: stringitemValue} onto itself.`);
let selectedItem: {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null
selectedItem
= null;
function renderList(listIndex: 0 | 1): voidrenderList(listIndex: 0 | 1listIndex); // Update style break; } // Perform move in data arrays const const sourceItemsArray: string[]sourceItemsArray =
const lists: {
    el: HTMLUListElement;
    items: () => string[];
    setItems: (newItems: string[]) => void;
    idPrefix: string;
    name: string;
}[]
lists
[const sourceListIndex: 0 | 1sourceListIndex].items: () => string[]items();
const const targetItemsArray: string[]targetItemsArray =
const lists: {
    el: HTMLUListElement;
    items: () => string[];
    setItems: (newItems: string[]) => void;
    idPrefix: string;
    name: string;
}[]
lists
[const targetListIndex: 0 | 1targetListIndex].items: () => string[]items();
const const newSourceItems: string[]newSourceItems = [...const sourceItemsArray: string[]sourceItemsArray]; const newSourceItems: string[]newSourceItems.Array<string>.splice(start: number, deleteCount?: number): string[] (+1 overload)
Removes elements from an array and, if necessary, inserts new elements in their place, returning the deleted elements.
@paramstart The zero-based location in the array from which to start removing elements.@paramdeleteCount The number of elements to remove. Omitting this argument will remove all elements from the start paramater location to end of the array. If value of this argument is either a negative number, zero, undefined, or a type that cannot be converted to an integer, the function will evaluate the argument as zero and not remove any elements.@returnsAn array containing the elements that were deleted.
splice
(const sourceItemIndex: numbersourceItemIndex, 1);
const const newTargetItems: string[]newTargetItems = const sourceListIndex: 0 | 1sourceListIndex === const targetListIndex: 0 | 1targetListIndex ? const newSourceItems: string[]newSourceItems : [...const targetItemsArray: string[]targetItemsArray]; let let effectiveTargetIndex: numbereffectiveTargetIndex = const targetItemIndex: numbertargetItemIndex; if (const sourceListIndex: 0 | 1sourceListIndex === const targetListIndex: 0 | 1targetListIndex) { if (const sourceItemIndex: numbersourceItemIndex < const targetItemIndex: numbertargetItemIndex) { let effectiveTargetIndex: numbereffectiveTargetIndex = const targetItemIndex: numbertargetItemIndex - 1; } else { let effectiveTargetIndex: numbereffectiveTargetIndex = const targetItemIndex: numbertargetItemIndex; } } else { let effectiveTargetIndex: numbereffectiveTargetIndex = const targetItemIndex: numbertargetItemIndex; } let effectiveTargetIndex: numbereffectiveTargetIndex = var Math: Math
An intrinsic object that provides basic mathematics functionality and constants.
Math
.Math.max(...values: number[]): number
Returns the larger of a set of supplied numeric expressions.
@paramvalues Numeric expressions to be evaluated.
max
(
0, var Math: Math
An intrinsic object that provides basic mathematics functionality and constants.
Math
.Math.min(...values: number[]): number
Returns the smaller of a set of supplied numeric expressions.
@paramvalues Numeric expressions to be evaluated.
min
(let effectiveTargetIndex: numbereffectiveTargetIndex, const newTargetItems: string[]newTargetItems.Array<string>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
)
); const newTargetItems: string[]newTargetItems.Array<string>.splice(start: number, deleteCount: number, ...items: string[]): string[] (+1 overload)
Removes elements from an array and, if necessary, inserts new elements in their place, returning the deleted elements.
@paramstart The zero-based location in the array from which to start removing elements.@paramdeleteCount The number of elements to remove. If value of this argument is either a negative number, zero, undefined, or a type that cannot be converted to an integer, the function will evaluate the argument as zero and not remove any elements.@paramitems Elements to insert into the array in place of the deleted elements.@returnsAn array containing the elements that were deleted.
splice
(let effectiveTargetIndex: numbereffectiveTargetIndex, 0, const itemValue: stringitemValue);
// Update state arrays *before* calling render
const lists: {
    el: HTMLUListElement;
    items: () => string[];
    setItems: (newItems: string[]) => void;
    idPrefix: string;
    name: string;
}[]
lists
[const sourceListIndex: 0 | 1sourceListIndex].setItems: (newItems: string[]) => voidsetItems(const newSourceItems: string[]newSourceItems);
if (const sourceListIndex: 0 | 1sourceListIndex !== const targetListIndex: 0 | 1targetListIndex) {
const lists: {
    el: HTMLUListElement;
    items: () => string[];
    setItems: (newItems: string[]) => void;
    idPrefix: string;
    name: string;
}[]
lists
[const targetListIndex: 0 | 1targetListIndex].setItems: (newItems: string[]) => voidsetItems(const newTargetItems: string[]newTargetItems);
} // If same list, the source setter already updated the correct underlying array function announce(message: string): voidannounce( `Keyboard: Moved ${const itemValue: stringitemValue} to position ${ let effectiveTargetIndex: numbereffectiveTargetIndex + 1 } in List ${const targetListIndex: 0 | 1targetListIndex + 1}.` ); // Reset selection and update focus state
let selectedItem: {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null
selectedItem
= null;
let focusedItemIndex: number | nullfocusedItemIndex = let effectiveTargetIndex: numbereffectiveTargetIndex; let focusedListIndex: 0 | 1 | nullfocusedListIndex = const targetListIndex: 0 | 1targetListIndex; // Focus stays on the target list // Re-render both lists with updated data and focus function renderList(listIndex: 0 | 1): voidrenderList(0); function renderList(listIndex: 0 | 1): voidrenderList(1); } break; case "Escape": event: KeyboardEventevent.Event.preventDefault(): void
The **`preventDefault()`** method of the Event interface tells the user agent that the event is being explicitly handled, so its default action, such as page scrolling, link navigation, or pasting text, should not be taken. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/preventDefault)
preventDefault
();
if (
let selectedItem: {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null
selectedItem
) {
function announce(message: string): voidannounce(`Selection cancelled for ${
let selectedItem: {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
}
selectedItem
.value: stringvalue}.`);
let selectedItem: {
    listIndex: 0 | 1;
    itemIndex: number;
    value: string;
} | null
selectedItem
= null;
function renderList(listIndex: 0 | 1): voidrenderList(listIndex: 0 | 1listIndex); // Update style } else { function announce(message: string): voidannounce("Escape pressed. No item selected."); (event: KeyboardEventevent.Event.target: EventTarget | null
The read-only **`target`** property of the Event interface is a reference to the object onto which the event was dispatched. It is different from Event.currentTarget when the event handler is called during the bubbling or capturing phase of the event. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/target)
target
as HTMLElement).HTMLOrSVGElement.blur(): void
[MDN Reference](https://developer.mozilla.org/docs/Web/API/HTMLElement/blur)
blur
(); // Blur the list
// Blur handler should take care of resetting state and rendering } break; default: return; // Allow other keys } } // --- Initial Setup --- if (const list1Element: HTMLUListElementlist1Element && const list2Element: HTMLUListElementlist2Element) { // Make lists tabbable const list1Element: HTMLUListElementlist1Element.Element.setAttribute(qualifiedName: string, value: string): void
The **`setAttribute()`** method of the Element interface sets the value of an attribute on the specified element. If the attribute already exists, the value is updated; otherwise a new attribute is added with the specified name and value. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Element/setAttribute)
setAttribute
("tabindex", "0");
const list2Element: HTMLUListElementlist2Element.Element.setAttribute(qualifiedName: string, value: string): void
The **`setAttribute()`** method of the Element interface sets the value of an attribute on the specified element. If the attribute already exists, the value is updated; otherwise a new attribute is added with the specified name and value. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Element/setAttribute)
setAttribute
("tabindex", "0");
// Add ARIA roles const list1Element: HTMLUListElementlist1Element.Element.setAttribute(qualifiedName: string, value: string): void
The **`setAttribute()`** method of the Element interface sets the value of an attribute on the specified element. If the attribute already exists, the value is updated; otherwise a new attribute is added with the specified name and value. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Element/setAttribute)
setAttribute
("role", "listbox");
const list1Element: HTMLUListElementlist1Element.Element.setAttribute(qualifiedName: string, value: string): void
The **`setAttribute()`** method of the Element interface sets the value of an attribute on the specified element. If the attribute already exists, the value is updated; otherwise a new attribute is added with the specified name and value. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Element/setAttribute)
setAttribute
("aria-labelledby", "list1-heading"); // Assume h2 has id='list1-heading'
const list2Element: HTMLUListElementlist2Element.Element.setAttribute(qualifiedName: string, value: string): void
The **`setAttribute()`** method of the Element interface sets the value of an attribute on the specified element. If the attribute already exists, the value is updated; otherwise a new attribute is added with the specified name and value. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Element/setAttribute)
setAttribute
("role", "listbox");
const list2Element: HTMLUListElementlist2Element.Element.setAttribute(qualifiedName: string, value: string): void
The **`setAttribute()`** method of the Element interface sets the value of an attribute on the specified element. If the attribute already exists, the value is updated; otherwise a new attribute is added with the specified name and value. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Element/setAttribute)
setAttribute
("aria-labelledby", "list2-heading"); // Assume h2 has id='list2-heading'
const list1Element: HTMLUListElementlist1Element.HTMLUListElement.addEventListener<"focus">(type: "focus", listener: (this: HTMLUListElement, ev: FocusEvent) => any, options?: boolean | AddEventListenerOptions): void (+1 overload)
The **`addEventListener()`** method of the EventTarget interface sets up a function that will be called whenever the specified event is delivered to the target. [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventTarget/addEventListener)
addEventListener
("focus", () => function handleFocus(listIndex: 0 | 1): voidhandleFocus(0));
const list1Element: HTMLUListElementlist1Element.HTMLUListElement.addEventListener<"blur">(type: "blur", listener: (this: HTMLUListElement, ev: FocusEvent) => any, options?: boolean | AddEventListenerOptions): void (+1 overload)
The **`addEventListener()`** method of the EventTarget interface sets up a function that will be called whenever the specified event is delivered to the target. [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventTarget/addEventListener)
addEventListener
("blur", (e: FocusEvente) => function handleBlur(event: FocusEvent, listIndex: 0 | 1): voidhandleBlur(e: FocusEvente, 0));
const list1Element: HTMLUListElementlist1Element.HTMLUListElement.addEventListener<"keydown">(type: "keydown", listener: (this: HTMLUListElement, ev: KeyboardEvent) => any, options?: boolean | AddEventListenerOptions): void (+1 overload)
The **`addEventListener()`** method of the EventTarget interface sets up a function that will be called whenever the specified event is delivered to the target. [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventTarget/addEventListener)
addEventListener
("keydown", (e: KeyboardEvente) => function handleKeydown(event: KeyboardEvent, listIndex: 0 | 1): voidhandleKeydown(e: KeyboardEvente, 0));
const list2Element: HTMLUListElementlist2Element.HTMLUListElement.addEventListener<"focus">(type: "focus", listener: (this: HTMLUListElement, ev: FocusEvent) => any, options?: boolean | AddEventListenerOptions): void (+1 overload)
The **`addEventListener()`** method of the EventTarget interface sets up a function that will be called whenever the specified event is delivered to the target. [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventTarget/addEventListener)
addEventListener
("focus", () => function handleFocus(listIndex: 0 | 1): voidhandleFocus(1));
const list2Element: HTMLUListElementlist2Element.HTMLUListElement.addEventListener<"blur">(type: "blur", listener: (this: HTMLUListElement, ev: FocusEvent) => any, options?: boolean | AddEventListenerOptions): void (+1 overload)
The **`addEventListener()`** method of the EventTarget interface sets up a function that will be called whenever the specified event is delivered to the target. [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventTarget/addEventListener)
addEventListener
("blur", (e: FocusEvente) => function handleBlur(event: FocusEvent, listIndex: 0 | 1): voidhandleBlur(e: FocusEvente, 1));
const list2Element: HTMLUListElementlist2Element.HTMLUListElement.addEventListener<"keydown">(type: "keydown", listener: (this: HTMLUListElement, ev: KeyboardEvent) => any, options?: boolean | AddEventListenerOptions): void (+1 overload)
The **`addEventListener()`** method of the EventTarget interface sets up a function that will be called whenever the specified event is delivered to the target. [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventTarget/addEventListener)
addEventListener
("keydown", (e: KeyboardEvente) => function handleKeydown(event: KeyboardEvent, listIndex: 0 | 1): voidhandleKeydown(e: KeyboardEvente, 1));
// Initial render function renderList(listIndex: 0 | 1): voidrenderList(0); function renderList(listIndex: 0 | 1): voidrenderList(1); }
static const initialItems1 = ["Apples", "Bananas", "Oranges", "Grapes"];
static const initialItems2 = ["Milk", "Cheese", "Yogurt"];
static const group = "accessibleList";

<let/liveMessage="">
<let/items1=initialItems1>
<let/items2=initialItems2>
<let/focusedList=null>
<let/focusedIdx=null>
<let/selected=null>

<let/config1={
  group,
  onDragstart: (s) => { liveMessage = `Drag started for ${s.draggedNode.data.value}.`; },
  onSort: (e) => { liveMessage = `Sorted ${e.draggedNodes[0].data.value} in List 1 to position ${e.position + 1}.`; },
  onTransfer: (e) => { liveMessage = `Transferred ${e.draggedNodes[0].data.value} to List 1 at position ${e.targetIndex + 1}.`; },
  onDragend: (s) => { liveMessage = `Drag ended for ${s.draggedNode.data.value}.`; },
}>
<let/config2={
  group,
  onDragstart: (s) => { liveMessage = `Drag started for ${s.draggedNode.data.value}.`; },
  onSort: (e) => { liveMessage = `Sorted ${e.draggedNodes[0].data.value} in List 2 to position ${e.position + 1}.`; },
  onTransfer: (e) => { liveMessage = `Transferred ${e.draggedNodes[0].data.value} to List 2 at position ${e.targetIndex + 1}.`; },
  onDragend: (s) => { liveMessage = `Drag ended for ${s.draggedNode.data.value}.`; },
}>

<div class="accessibility-demo">
  <div aria-live="polite" class="sr-only">${liveMessage}</div>

  <div class="lists-container">
    <div class="list-wrapper">
      <h2 id="list1-heading">List 1</h2>
      <ul/list1
        class="list"
        tabindex="0"
        role="listbox"
        aria-labelledby="list1-heading"
        aria-activedescendant=(focusedList === 0 && focusedIdx !== null ? `list1-item-${items1[focusedIdx]}` : undefined)
        onFocus() { focusedList = 0; if (focusedIdx === null && items1.length > 0) focusedIdx = 0; liveMessage = "List 1 focused. Use up and down arrows to navigate items."; }
        onKeydown(e) {
          if (focusedList !== 0) return;
          const items = items1;
          if (e.key === "ArrowDown") {
            e.preventDefault();
            if (items.length > 0) { focusedIdx = focusedIdx === null ? 0 : (focusedIdx + 1) % items.length; liveMessage = items[focusedIdx]; }
          } else if (e.key === "ArrowUp") {
            e.preventDefault();
            if (items.length > 0) { focusedIdx = focusedIdx === null ? items.length - 1 : (focusedIdx - 1 + items.length) % items.length; liveMessage = items[focusedIdx]; }
          } else if (e.key === " ") {
            e.preventDefault();
            if (focusedIdx !== null) {
              if (selected?.listIndex === 0 && selected?.itemIndex === focusedIdx) { selected = null; liveMessage = `${items[focusedIdx]} deselected.`; }
              else { selected = { listIndex: 0, itemIndex: focusedIdx, value: items[focusedIdx] }; liveMessage = `${items[focusedIdx]} selected. Use arrow keys to choose drop position, then press Enter.`; }
            }
          } else if (e.key === "Enter") {
            e.preventDefault();
            if (selected && focusedIdx !== null) {
              const { listIndex: srcList, itemIndex: srcIdx, value } = selected;
              const tgtList = 0; const tgtIdx = focusedIdx;
              if (srcList === tgtList && srcIdx === tgtIdx) { liveMessage = `Cannot drop ${value} onto itself.`; selected = null; return; }
              const srcItems = srcList === 0 ? [...items1] : [...items2];
              const tgtItems = [...items1];
              srcItems.splice(srcIdx, 1);
              const effIdx = Math.max(0, Math.min(tgtIdx, tgtItems.length));
              tgtItems.splice(effIdx, 0, value);
              if (srcList === 0) items1 = tgtItems;
              else { items2 = srcItems; items1 = tgtItems; }
              liveMessage = `Moved ${value} to position ${effIdx + 1} in List 1.`;
              selected = null; focusedIdx = effIdx; focusedList = 0;
            }
          } else if (e.key === "Escape") {
            e.preventDefault();
            if (selected) { liveMessage = `Selection cancelled for ${selected.value}.`; selected = null; }
            else { e.target.blur(); focusedList = null; focusedIdx = null; }
          }
        }
      >
        <for|item, index| of=items1 by=(i => i)>
          <li
            id=`list1-item-${item}`
            class=["item", focusedList === 0 && focusedIdx === index && "item-focused", selected?.listIndex === 0 && selected?.itemIndex === index && "item-selected"]
            role="option"
            aria-selected=(focusedList === 0 && focusedIdx === index)
            tabindex="-1"
          >
            ${item}
          </li>
        </for>
        <if=items1.length === 0>
          <li class="empty-list-message">Empty</li>
        </if>
      </ul>
    </div>

    <div class="list-wrapper">
      <h2 id="list2-heading">List 2</h2>
      <ul/list2
        class="list"
        tabindex="0"
        role="listbox"
        aria-labelledby="list2-heading"
        aria-activedescendant=(focusedList === 1 && focusedIdx !== null ? `list2-item-${items2[focusedIdx]}` : undefined)
        onFocus() { focusedList = 1; if (focusedIdx === null && items2.length > 0) focusedIdx = 0; liveMessage = "List 2 focused. Use up and down arrows to navigate items."; }
        onKeydown(e) {
          if (focusedList !== 1) return;
          const items = items2;
          if (e.key === "ArrowDown") {
            e.preventDefault();
            if (items.length > 0) { focusedIdx = focusedIdx === null ? 0 : (focusedIdx + 1) % items.length; liveMessage = items[focusedIdx]; }
          } else if (e.key === "ArrowUp") {
            e.preventDefault();
            if (items.length > 0) { focusedIdx = focusedIdx === null ? items.length - 1 : (focusedIdx - 1 + items.length) % items.length; liveMessage = items[focusedIdx]; }
          } else if (e.key === " ") {
            e.preventDefault();
            if (focusedIdx !== null) {
              if (selected?.listIndex === 1 && selected?.itemIndex === focusedIdx) { selected = null; liveMessage = `${items[focusedIdx]} deselected.`; }
              else { selected = { listIndex: 1, itemIndex: focusedIdx, value: items[focusedIdx] }; liveMessage = `${items[focusedIdx]} selected. Use arrow keys to choose drop position, then press Enter.`; }
            }
          } else if (e.key === "Enter") {
            e.preventDefault();
            if (selected && focusedIdx !== null) {
              const { listIndex: srcList, itemIndex: srcIdx, value } = selected;
              const tgtList = 1; const tgtIdx = focusedIdx;
              if (srcList === tgtList && srcIdx === tgtIdx) { liveMessage = `Cannot drop ${value} onto itself.`; selected = null; return; }
              const srcItems = srcList === 0 ? [...items1] : [...items2];
              const tgtItems = [...items2];
              srcItems.splice(srcIdx, 1);
              const effIdx = Math.max(0, Math.min(tgtIdx, tgtItems.length));
              tgtItems.splice(effIdx, 0, value);
              if (srcList === 1) items2 = tgtItems;
              else { items1 = srcItems; items2 = tgtItems; }
              liveMessage = `Moved ${value} to position ${effIdx + 1} in List 2.`;
              selected = null; focusedIdx = effIdx; focusedList = 1;
            }
          } else if (e.key === "Escape") {
            e.preventDefault();
            if (selected) { liveMessage = `Selection cancelled for ${selected.value}.`; selected = null; }
            else { e.target.blur(); focusedList = null; focusedIdx = null; }
          }
        }
      >
        <for|item, index| of=items2 by=(i => i)>
          <li
            id=`list2-item-${item}`
            class=["item", focusedList === 1 && focusedIdx === index && "item-focused", selected?.listIndex === 1 && selected?.itemIndex === index && "item-selected"]
            role="option"
            aria-selected=(focusedList === 1 && focusedIdx === index)
            tabindex="-1"
          >
            ${item}
          </li>
        </for>
        <if=items2.length === 0>
          <li class="empty-list-message">Empty</li>
        </if>
      </ul>
    </div>
  </div>

  <div class="instructions">
    <h3>Keyboard Instructions</h3>
    <ul>
      <li>Use <kbd>Tab</kbd> or <kbd>Shift+Tab</kbd> to focus a list.</li>
      <li>Use <kbd>↑</kbd> / <kbd>↓</kbd> arrows to navigate items within the focused list.</li>
      <li>Press <kbd>Spacebar</kbd> to select/deselect the highlighted item for moving.</li>
      <li>With an item selected, navigate to choose the drop position, then press <kbd>Enter</kbd>.</li>
      <li>Press <kbd>Escape</kbd> to cancel a selection or leave the list.</li>
    </ul>
  </div>
</div>

<dnd:=items1 parent=list1 config=config1/>
<dnd:=items2 parent=list2 config=config2/>

Support Us

FormKit Drag and Drop is made with love by the FormKit team — the creators of open-source projects such as:

  • FormKit - The open-source form framework for Vue.
  • AutoAnimate - Add motion to your apps with a single line of code.
  • Tempo - The easiest way to work with dates in JavaScript.
  • ArrowJS - Reactivity without the Framework.

If you find our projects useful and would like to support their ongoing development, please consider sponsoring us on GitHub!