We build a data grid, and its cell editors (combo box, date picker, number input...) also had to work as standalone components. People kept asking to restyle them without forking. So we split every component into two parts.
The core is a plain function. It takes getters for its inputs and returns state plus "prop-getters" you spread onto your own elements:
<script lang="ts"> import { createListbox } from '@svgrid/grid' let value = $state(null) const options = [{ value: 'a', label: 'Apple' }, { value: 'b', label: 'Banana' }] const lb = createListbox({ options: () => options, value: () => value, onChange: (v) => (value = v), }) </script> <ul {...lb.rootProps()}> {#each options as opt, i (opt.value)} <li {...lb.optionProps(i)}>{opt.label}</li> {/each} </ul>
rootProps() and optionProps(i) return the role, the aria-* attributes, tabindex and the key/click handlers.…