Any other framework

Solid, Qwik, Lit, Angular, or none at all.

Three frameworks have a first-party adapter. Everything else uses the same call, because loopem is a function that takes an element and returns a handle.

ts
import { createPicker } from 'loopem'

const picker = createPicker(element, { items, renderItem })

// later
picker.destroy()

Two lines to integrate anywhere: create it when your component mounts, destroy it when it unmounts.

Solid

tsx
function Gallery(props) {
  let el
  onMount(() => {
    const picker = createPicker(el, { items: props.photos, renderItem })
    onCleanup(() => picker.destroy())
  })
  return <div ref={el} class="picker" />
}

Lit

ts
firstUpdated() {
  this.picker = createPicker(this.renderRoot.querySelector('.picker'), {
    items: this.photos,
    renderItem,
  })
}

disconnectedCallback() {
  super.disconnectedCallback()
  this.picker?.destroy()
}

Angular

ts
ngAfterViewInit() {
  this.picker = createPicker(this.el.nativeElement, {
    items: this.photos,
    renderItem,
  })
}

ngOnDestroy() {
  this.picker?.destroy()
}

The rules that apply everywhere

  • Give the container a height, and each item a size. Loopem positions, it never sizes.
  • spacing has to be larger than an item or they overlap.
  • Call destroy() on unmount. It removes the listeners, the slots, and the rAF loop.
  • Nothing runs while the track is still. There is no rAF at all when idle, so a page full of settled pickers costs only its DOM.