{"slug":"presence","title":"Presence","description":"Supporting exit animations using the presence machine.","contentType":"component","framework":"vue","content":"Presence helps manage mount/unmount transitions with exit animations.\n\nWhen a component is hidden or removed, the DOM usually removes it immediately.\nPresence keeps it mounted long enough for exit animations to finish.\n\n> The presence machine requires using **CSS animations** to animate the\n> component's exit.\n\n## Resources\n\n\n[Latest version: v1.41.1](https://www.npmjs.com/package/@zag-js/presence)\n[Logic Visualizer](https://zag-visualizer.vercel.app/presence)\n[Source Code](https://github.com/chakra-ui/zag/tree/main/packages/machines/presence)\n\n\n\n## Installation\n\nInstall the presence package:\n\n```bash\nnpm install @zag-js/presence @zag-js/vue\n# or\nyarn add @zag-js/presence @zag-js/vue\n```\n\n## Usage\n\nImport the presence package:\n\n```tsx\nimport * as presence from \"@zag-js/presence\"\n```\n\nThe presence package exports two key functions:\n\n- `machine` - State machine logic.\n- `connect` - Maps machine state to JSX props and event handlers.\n\nThen use the framework integration helpers:\n\n```html\n<script setup lang=\"ts\">\n  import * as presence from \"@zag-js/presence\"\n  import { useMachine, normalizeProps } from \"@zag-js/vue\"\n  import { computed, watch, ref } from \"vue\"\n\n  const props = defineProps<{\n    present: boolean\n    unmountOnExit?: boolean\n  }>()\n\n  const emit = defineEmits<{\n    (e: \"exit-complete\"): void\n  }>()\n\n  const service = useMachine(presence.machine, {\n    get present() {\n      return props.present\n    },\n    onExitComplete: () => emit(\"exit-complete\"),\n  })\n\n  const api = computed(() => presence.connect(service, normalizeProps))\n\n  const nodeRef = ref<HTMLElement | null>(null)\n\n  watch(nodeRef, () => {\n    api.value.setNode(nodeRef.value)\n  })\n\n  const unmount = computed(() => !api.value.present && unmountOnExit)\n</script>\n\n<template>\n  <div\n    v-show=\"!unmount\"\n    :hidden=\"!api.present\"\n    :data-state=\"api.skip ? undefined : present ? 'open' : 'closed'\"\n    ref=\"nodeRef\"\n    v-bind=\"$attrs\"\n  />\n</template>\n```\n\n### Running code after exit animation\n\nUse `onExitComplete` to run logic after the exit animation finishes.\n\n```tsx\nconst service = useMachine(presence.machine, {\n  present: open,\n  onExitComplete() {\n    console.log(\"Exit animation finished\")\n  },\n})\n```\n\n### Applying presence changes immediately\n\nSet `immediate` to `true` to skip deferring present-state changes to the next\nframe.\n\n```tsx\nconst service = useMachine(presence.machine, {\n  present: open,\n  immediate: true,\n})\n```\n\n## Styling guide\n\nTo style any entry and exit animations, set up the `@keyframes` and apply the\nanimations.\n\n```css\n@keyframes enter {\n  from {\n    scale: 0.9;\n    opacity: 0;\n  }\n\n  to {\n    opacity: 1;\n    scale: 1;\n  }\n}\n\n@keyframes exit {\n  to {\n    opacity: 0;\n    scale: 0.9;\n  }\n}\n\n[data-state=\"open\"] {\n  animation: enter 0.15s ease-out;\n}\n\n[data-state=\"closed\"] {\n  animation: exit 0.1s ease-in;\n}\n```\n\nYou can then use the `Presence` component in your project.\n\n```tsx\nfunction Example() {\n  const [open, setOpen] = React.useState(true)\n  return (\n    <>\n      <button onClick={() => setOpen((c) => !c)}>Toggle</button>\n      <Presence present={open} unmountOnExit>\n        <div>Content</div>\n      </Presence>\n    </>\n  )\n}\n```\n\n## Methods and Properties\n\n### Machine Context\n\nThe presence machine exposes the following context properties:\n\n**`present`**\nType: `boolean | undefined`\nDescription: Whether the node is present (controlled by the user)\n\n**`onExitComplete`**\nType: `VoidFunction | undefined`\nDescription: Function called when the animation ends in the closed state\n\n**`immediate`**\nType: `boolean | undefined`\nDescription: Whether to synchronize the present change immediately or defer it to the next frame\n\n### Machine API\n\nThe presence `api` exposes the following methods:\n\n**`skip`**\nType: `boolean`\nDescription: Whether the animation should be skipped.\n\n**`present`**\nType: `boolean`\nDescription: Whether the node is present in the DOM.\n\n**`setNode`**\nType: `(node: HTMLElement | null) => void`\nDescription: Function to set the node (as early as possible)\n\n**`unmount`**\nType: `VoidFunction`\nDescription: Function to programmatically unmount the node","package":"@zag-js/presence","editUrl":"https://github.com/chakra-ui/zag/edit/main/website/data/components/presence.mdx"}