{"slug":"migration","title":"Migration Guide","description":"Migrating your project to v1","contentType":"guides","content":"After years of refinement and iteration, we've cemented Zag to work seamlessly\nacross major JavaScript frameworks.\n\nNow, we're taking things to the next level by focusing on:\n\n- **Performance**: Improving the runtime and rendering performance of every\n  component\n- **Bundle Size**: Reducing the gross bundle size of each component + framework\n  adapters\n\nWe achieved this by **moving from an external store to native reactive\nprimitives** provided by each framework.\n\nOur rigorous performance testing, which involved stress-testing with 10,000\ninstances of the same component, revealed roughly **1.5x - 4x** performance\nimprovements across components. [View Breakdown](#performance)\n\n## Changed\n\nThe major changes are quite simple, and are listed below:\n\n### useMachine\n\n`useMachine` now returns a `service` object instead of a tuple of\n`[state, send]`.\n\nThis change is the same across all components. Using \"find and replace\" will\nhelp you migrate faster.\n\n**Before**\n\n```tsx\nconst [state, send] = useMachine(avatar.machine({ id: useId() }))\n```\n\n**After**\n\n```tsx\nconst service = useMachine(avatar.machine, { id: useId() })\n```\n\n> Notice that `avatar.machine` is no longer a function, it is passed directly to\n> `useMachine`.\n\n#### Caveats\n\nDue to the switch from `<component>.machine()` as a function to\n`<component>.machine` as an object, the TS inference is limited for generic\ncomponents like combobox and select.\n\nTo help with this, we've exported an equivalent `<component>.Machine` type to\nhelp with the casting.\n\n```ts\nuseMachine(combobox.machine as combobox.Machine<Item>)\n```\n\n### Controlled vs Uncontrolled value\n\nManaging controlled and uncontrolled values is a fairly common need in most\ncomponent libraries.\n\nPreviously, we handled this by providing initial and controlled context to the\nmachine.\n\n```tsx\n///                                                    👇🏻 Default value\nconst [state, send] = useMachine(numberInput.machine({ value: \"10\" }), {\n  context: {\n    // 👇🏻 Controlled value\n    value: \"10\",\n  },\n})\n```\n\nThis can be initially confusing to users and is error prone.\n\nNow, we've moved the logic to the machine itself. Allowing users to explicitly\nprovide a default value and a controlled value.\n\n```tsx\nconst service = useMachine(numberInput.machine, {\n  // 👇🏻 Default value\n  defaultValue: \"10\",\n  // 👇🏻 Controlled value\n  value: \"10\",\n})\n```\n\n> This change applies all component with some form of `value` prop.\n\n### Controlled vs Uncontrolled open\n\nPreviously, we handled controlled and uncontrolled open states by providing\ninitial `open` state and an additional `open.controlled` property.\n\n```tsx\n//                                                    👇🏻 Default value\nconst [state, send] = useMachine(dialog.machine({ open: true }), {\n  context: {\n    // 👇🏻 Controlled value\n    open: true,\n    \"open.controlled\": true,\n  },\n})\n```\n\nNow, we've moved the logic to the machine itself. Allowing users to explicitly\nprovide a default and controlled open state.\n\n```tsx\nconst service = useMachine(dialog.machine, {\n  // 👇🏻 Default value\n  defaultOpen: true,\n  // 👇🏻 Controlled value\n  open: true,\n})\n```\n\n### Typings\n\n`<component>.Context` is now renamed to `<component>.Props`\n\n**Before**\n\n```tsx\nimport * as accordion from \"@zag-js/accordion\"\n\ninterface Props extends accordion.Context {}\n```\n\n**After**\n\n```tsx\nimport * as accordion from \"@zag-js/accordion\"\n\ninterface Props extends accordion.Props {}\n```\n\n### Toast\n\nThe toast component new requires that you create a toast store (or manager), and\npass that store to the toast group machine.\n\nThis store is to be used in userland to create and manage toasts.\n\n> Refer to the [toast](/components/react/toast) documentation for more details.\n\n**Before**\n\n```tsx\nconst [state, send] = useMachine(\n  toast.group.machine({\n    overlap: false,\n    placement: \"bottom\",\n  }),\n)\n\nconst toaster = toast.group.connect(state, send, normalizeProps)\n\n// propagate the `toaster` via context and use it in your app.\n\ntoaster.create({\n  title: \"Hello\",\n  description: \"World\",\n})\n```\n\n**After**\n\n```tsx\nconst toaster = toast.createStore({\n  overlap: false,\n  placement: \"bottom\",\n})\n\nconst service = useMachine(toast.group.machine, {\n  store: toaster,\n})\n\n// use the `toaster` store to create and manage toasts. No need for context.\n\ntoaster.create({\n  title: \"Hello\",\n  description: \"World\",\n})\n```\n\nFor Solid.js users, we recommend using `<Key>` exported from `@zag-js/solid`\nwhen mapping over the toasts, instead of the `<For>` component.\n\n## Fixed\n\n- **Menu**: Fix issue where context menu doesn't update positioning on\n  subsequent right clicks.\n\n- **Avatar**: Fix issue where `api.setSrc` doesn't work.\n\n- **File Upload**: Fix issue where drag-and-drop doesn't work when `directory`\n  is `true`.\n\n- **Carousel**\n  - Fix issue where initial page is not working.\n  - Fix issue where pagination sync broken after using dots indicators.\n\n## Removed\n\n- General\n  - Removed `useActor` hook in favor of `useMachine` everywhere.\n  - Removed `open.controlled` in favor of `defaultOpen` and `open` props.\n\n- Pagination\n  - `api.setCount` is removed in favor of explicitly setting the `count` prop.\n\n- Select, Combobox\n  - `api.setCollection` is removed in favor of explicitly setting the\n    `collection` prop.\n\n## Performance\n\nWe measured the mount performance of 10k instances of each component, and\ncompared the before and after.\n\n### Avatar\n\n**Result**: ~27% faster mount time and ~99% faster update time\n\n#**Before**\n\n```sh\n{phase: 'mount', duration: 1007.3000000119209}\n{phase: 'update', duration: 890.4000000357628}\n```\n\n**#After:**\n\n```sh\n{phase: 'mount', duration: 736.9999999403954}\n{phase: 'update', duration: 1.899999976158142}\n```\n\n### Accordion\n\n**Result**: ~61% faster mount time and no update time\n\n**Before**\n\n```sh\n{phase: 'mount', duration: 2778.4999997913837}\n{phase: 'update', duration: 2.3000000715255737}\n```\n\n**After**\n\n```sh\n{phase: 'mount', duration: 1079.0000001490116}\n```\n\n### Collapsible\n\n**Result**: ~65% faster mount time and no update time\n\n**Before**\n\n```sh\n{phase: 'mount', duration: 834.4000000357628}\n{phase: 'update', duration: 2.1999999284744263}\n```\n\n**After**\n\n```sh\n{phase: 'mount', duration: 290.3000001013279}\n```\n\n### Dialog\n\n**Result**: ~80% faster mount time and no update time\n\n**Before**\n\n```sh\n{phase: 'mount', duration: 688.9000000357628}\n{phase: 'update', duration: 2.0000000298023224}\n```\n\n**After**\n\n```sh\n{phase: 'mount', duration: 135.50000008940697}\n```\n\n### Editable\n\n**Result**: ~56% faster mount time and no update time\n\n**Before**\n\n```sh\n{phase: 'mount', duration: 1679.500000089407}\n{phase: 'update', duration: 2.0000000298023224}\n```\n\n**After**\n\n```sh\n{phase: 'mount', duration: 737.5999999940395}\n```\n\n### Tooltip\n\n**Result**: ~82% faster mount time and no update time\n\n**Before**\n\n```sh\n{phase: 'mount', duration: 797.7999999821186}\n{phase: 'update', duration: 2.5999999940395355}\n```\n\n**After**\n\n```sh\n{phase: 'mount', duration: 139.9000000357628}\n```\n\n### Presence\n\n**Result**: ~64% faster mount time and eliminated update time\n\n**Before**\n\n```sh\n{ phase: \"mount\", duration: 1414 }\n{ phase: \"update\", duration: 0 }\n```\n\n**After**\n\n```sh\n{ phase: \"mount\", duration: 502 }\n```\n\n### Tabs\n\n**Result**: ~6% faster mount time\n\n**Before**\n\n```sh\n{ phase: \"mount\", duration: 4120 }\n{ phase: \"update\", duration: 2014 }\n```\n\n**After**\n\n```sh\n{ phase: \"mount\", duration: 3880 }\n{ phase: \"nested-update\", duration: 3179 }\n```\n\n## Bundle Size\n\nWe've made significant strides in reducing the bundle size of the overall\nlibrary. The core package powers all components. It is now less than 2KB\nminified, a whopping **98% reduction** in size.\n\n**Before**: 13.78 KB\n\n**After**: 1.52 KB\n\n## Contributors Notes\n\n- `activities` is now renamed to `effects`\n\n- `prop`, `context` and `refs` are now explicitly passed to the machine. Prior\n  to this everything was pass to the `context` object which was quite expensive\n  (performance wise).\n\n- The syntax for `watch` has changed significantly, refer to the new machines to\n  learn how it works. It is somewhat similar to how `useEffect` works in react.\n\n- `createMachine` is just an identity function, it doesn't do anything. The\n  machine work is now moved to the framework `useMachine` hook.\n\n## Thank you\n\nWe'd like to thank the following contributors for their help in making this\nrelease possible:\n\n- [Segun Adebayo](https://github.com/segunadebayo) for leading the charge and\n  making such engineering feats possible.\n\n- [Christian Schroeter](https://github.com/cschroeter) for providing valuable\n  feedback and suggestions to improve the library.","editUrl":"https://github.com/chakra-ui/zag/edit/main/website/data/guides/migration.mdx"}