{"slug":"framework-adapters","title":"Building a Framework Adapter","description":"Build and maintain a framework adapter for Zag machines","contentType":"guides","content":"A framework adapter connects Zag's framework-agnostic machines to your\nframework's reactivity, lifecycle, and DOM bindings.\n\n```text\nmachine + user props\n  -> useMachine()\n  -> service\n  -> connect(service, normalizeProps)\n  -> element props\n```\n\nDon't implement the machine interpreter from scratch. Port the official adapter\nwhose reactivity model is closest to your framework:\n\n| Reactivity model                          | Starting point                                                                                                                                                   |\n| ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| Hook-based rendering                      | [React](https://github.com/chakra-ui/zag/tree/main/packages/frameworks/react) or [Preact](https://github.com/chakra-ui/zag/tree/main/packages/frameworks/preact) |\n| Signals and computed values               | [Solid](https://github.com/chakra-ui/zag/tree/main/packages/frameworks/solid)                                                                                    |\n| Refs, computed values, and watchers       | [Vue](https://github.com/chakra-ui/zag/tree/main/packages/frameworks/vue)                                                                                        |\n| Compiler-managed reactivity               | [Svelte](https://github.com/chakra-ui/zag/tree/main/packages/frameworks/svelte)                                                                                  |\n| Subscriptions without a component runtime | [Vanilla JavaScript](https://github.com/chakra-ui/zag/tree/main/packages/frameworks/vanilla)                                                                     |\n\n## Implement the Adapter\n\nAn adapter has three main responsibilities.\n\n### 1. Bind the Machine\n\nCopy `machine.ts` and its supporting reactive primitives from your chosen\nadapter. Replace the framework-specific parts:\n\n- Reactive state and controlled values\n- Mutable, non-reactive refs\n- Computed values and dependency tracking\n- Mount and unmount hooks\n- Synchronous update behavior\n\nThese are the main contracts to map to your framework:\n\n#### Bindable\n\nMaps controlled and uncontrolled values to reactive state.\n\n```ts\ninterface Bindable<T> {\n  initial: T | undefined\n  ref: unknown\n  get(): T\n  set(value: T | ((previous: T) => T)): void\n  invoke(nextValue: T, previousValue: T): void\n  hash(value: T): string\n}\n```\n\n#### Refs\n\nHold mutable values without triggering a render.\n\n```ts\ninterface Refs<T> {\n  get<K extends keyof T>(key: K): T[K]\n  set<K extends keyof T>(key: K, value: T[K]): void\n}\n```\n\n#### Watch\n\nMaps machine dependencies to your framework's effect primitive.\n\n```ts\ntype Track = (\n  dependencies: Array<() => string | number | boolean | null | undefined>,\n  effect: () => void,\n) => void\n```\n\n```ts\nwatch({ track, prop, action }) {\n  track([() => prop(\"disabled\")], () => {\n    action([\"syncDisabled\"])\n  })\n}\n```\n\n#### useMachine\n\nRuns the machine lifecycle and returns the service consumed by `connect`.\n\n```ts\nfunction useMachine<T extends MachineSchema>(\n  machine: Machine<T>,\n  props?: Partial<T[\"props\"]>,\n): Service<T>\n```\n\nKeep Zag's core transition helpers and effect ordering intact.\n\n### 2. Normalize DOM Props\n\nZag prop getters use a canonical, React-like shape. Use `createNormalizer` from\n`@zag-js/types` to convert those props to your framework's format.\n\nAt minimum, test:\n\n- Focus, blur, input, change, and double-click events\n- `className`, `htmlFor`, `defaultValue`, and `defaultChecked`\n- Style objects and CSS custom properties\n- Case-sensitive SVG attributes such as `viewBox`\n\nCompare your implementation with the official\n[normalizers](https://github.com/chakra-ui/zag/tree/main/packages/frameworks).\n\n### 3. Apply Props to Elements\n\nFrameworks with prop spreading can apply a prop getter directly:\n\n```tsx\n<button {...api.getTriggerProps()}>Open</button>\n```\n\nIf your framework doesn't support this, provide a directive, action, or helper\nthat applies attributes, properties, styles, and event listeners. It must also\nremove values that disappear when the props change.\n\n## Test the Adapter\n\nBefore publishing, verify:\n\n- Controlled and uncontrolled values stay in sync\n- User props update reactively\n- Entry and exit effects run and clean up\n- Prop normalization works for inputs, buttons, styles, and SVG\n- Event listeners update without duplicates\n- Server rendering doesn't access the DOM before mount\n\nUse Checkbox, Tooltip, and Combobox as integration tests. Together they cover\ncontrolled state, effects, timers, keyboard events, and collections.\n\nDeclare Zag and your framework as peer dependencies, and document the version\nranges you test. Adapter internals can change with Zag's machine contract, so\ncompare your implementation with its official starting point when upgrading.\n\n## Community Adapters\n\nThese adapters are maintained by community members. They are not covered by\nZag's official support or release process, so check each project's supported Zag\nand framework versions before adopting it.\n\n| Framework | Adapter                                                | Status               |\n| --------- | ------------------------------------------------------ | -------------------- |\n| Angular   | [`zag-angular`](https://github.com/makuko/zag-angular) | Community maintained |\n| Marko     | [`marko-zag`](https://github.com/svallory/marko-zag)   | Work in progress     |\n\nBuilt an adapter for another framework? Open a documentation pull request that\nlinks to its source, package, usage example, test suite, and supported version\nranges.","editUrl":"https://github.com/chakra-ui/zag/edit/main/website/data/guides/framework-adapters.mdx"}