Qwik
gridla/qwik binds the layout engine to Qwik components: GridProvider, GridCanvas, GridItem, GridPreviewOutline, and GridTransferScope, with the same props and the same data-gridla-* attributes as the other adapters. It is a thin binding over gridla/interaction, the same layer the React adapter is built on.
Appearance is yours: see the styling guide for every data-gridla-* attribute, resize handle sizing, the preview outline, and a starter stylesheet.
Qwik's constraints shape the adapter in three visible ways:
- Callbacks carry the
$suffix (onLayoutChange$,onCommit$,onItemClick$): Qwik serializes function props as QRLs, and the suffix is what its optimizer looks for. - The controller is client only. The server renders the layout at its authored size from props alone; once the provider is visible in the browser, a
GridControlleris created in a visible task and mirrored into a signal. Nothing that cannot be serialized crosses the server/client boundary. - Children are projected, not rendered through a function.
GridItemrenders aSlot; readuseGridItemView(id)for the item's geometry and flags.
Install
The adapter ships inside the gridla package as the gridla/qwik subpath, with @builder.io/qwik (1.14 or newer) as an optional peer dependency. Its build keeps the $ boundaries intact and is published as qwik.qwik.js, the file shape the Qwik optimizer transforms inside your application build, exactly like any other Qwik library. No configuration is needed in a Qwik City project.
Minimal example
What happens:
- On the server,
GridProvidercomputes the rendered layout fromlayout(ordefaultLayout) and everyGridItemis positioned at its authored geometry, so the HTML already contains the grid. - In the browser, the provider's visible task (strategy
document-ready) creates the controller.GridCanvasthen measures itself withResizeObserver, feeds the size to the controller, and binds pointer and keyboard handling with native listeners. Because the layout isresponsiveby default, items are re-projected to the measured width on the first frame after resume. - Every store change is written into one signal, and each component reads the slice it needs from that signal during render. Item geometry is set as inline styles (
transformby default, orleft/topwithpositioning="absolute").
Controlled and uncontrolled
Pass layout and onLayoutChange$ to own the state (the example above keeps it in a signal), or defaultLayout to let the controller own it and still be notified. Because layout is read from a signal, Qwik hands it to the provider as a derived prop; the provider tracks it and forwards each change to the controller.
selectedId and onSelectedIdChange$ work the same way for the selection. acceptTransfers is a boolean only: the controller needs a synchronous answer and a QRL resolves asynchronously.
Imperative actions
The controller lives in a client-only store. Capture that store in an event handler and use the controller when it exists:
runtime.controller is undefined on the server and until the provider has mounted; it is a noSerialize value, so read it inside the handler rather than capturing it.
Reading state
useGridState()returns the provider'sGridStateas a read-only signal.useGridVisibleLayout()returns the layout to paint right now: the solver's preview during a gesture, otherwise the rendered layout.useGridItemView(id)returns a computed signal with one item's rect, its pre-gesture rect, and itsisActive,isSelected,isShifted, andisTransferringflags.
Nested layouts and transfers
A nested layout is a GridProvider rendered inside a GridItem, as in the other adapters. Wrap several providers in GridTransferScope and items move between them. The scope object itself is created on the client by the first provider that mounts, so nested layouts and transfers work without any serialization concerns:
Server rendering
renderToString from @builder.io/qwik/server renders the components without a DOM; the unit suite (tests/adapters/qwik.test.ts) does exactly that and checks the emitted attributes. Nothing in gridla/qwik touches window or document at import time. When the page resumes, the visible task creates the controller from the props that are current at that moment, so a layout that changed between render and resume is picked up.
Building without Qwik City
The Qwik optimizer normally runs inside Vite through @builder.io/qwik/optimizer. It is a plain API, so any bundler can call it per module. The demo app for this adapter (examples/adapters/qwik) is built with Rsbuild and a small loader that runs transformModules with the inline entry strategy over the app's .tsx files and over gridla's qwik.qwik.js; the qwikloader script is inlined into the page. That app drives the shared browser contract suite for this adapter.