Web Component with craftit
Problem
You are building a Craftit web component that contains a sortable list. The drag-and-drop lifecycle must be tied to the component's own mount and unmount so it does not leak after the element is removed from the DOM.
Solution
ts
import { define, html, onCleanup, ref, signal } from '@vielzeug/craftit';
import { createDropZone } from '@vielzeug/dragit';
define('my-dropzone', (props) => {
const isDragging = signal(false);
const dropzoneRef = ref<HTMLElement>();
return {
mount() {
const el = dropzoneRef.value!;
const zone = createDropZone({
element: el,
accept: ['image/*'],
onDrop: (files) => {
/* handle upload */
},
onHoverChange: (hovered) => {
isDragging.value = hovered;
},
});
onCleanup(() => zone.destroy());
},
render: () => html`
<div ref=${dropzoneRef} class="dropzone" :class=${{ 'drag-over': () => isDragging.value }}>
<slot>Drop images here</slot>
</div>
`,
};
});Pitfalls
makeSortable()must be called after the element is connected to the DOM — insideonMounted, not the constructor. The scroll container does not exist before connection.- Each Craftit component instance needs its own sortable instance. Sharing one across instances causes them to manipulate each other's DOM.
- Return the sortable's
disposefromonMountedso Craftit calls it indisconnectedCallbackautomatically.