{"slug":"presence","title":"Presence","description":"Supporting exit animations using the presence machine.","contentType":"component","framework":"svelte","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.39.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/svelte\n# or\nyarn add @zag-js/presence @zag-js/svelte\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```svelte\n<script lang=\"ts\">\n  import * as presence from \"@zag-js/presence\"\n  import { normalizeProps, useMachine } from \"@zag-js/svelte\"\n  import type { Snippet } from \"svelte\"\n\n  interface Props {\n    present: boolean\n    unmountOnExit?: boolean\n    onExitComplete?: () => void\n    children?: Snippet\n  }\n\n  let { present, unmountOnExit, onExitComplete, children }: Props = $props()\n\n  const service = useMachine(presence.machine, () => ({\n    present,\n    onExitComplete,\n  }))\n  const api = $derived(presence.connect(service, normalizeProps))\n\n  function setNode(node: HTMLDivElement) {\n    api.setNode(node)\n  }\n\n  const unmount = $derived(!api.present && unmountOnExit)\n</script>\n\n{#if !unmount}\n  <div\n    {@attach setNode}\n    hidden={!api.present}\n    data-state={api.skip ? undefined : present ? \"open\" : \"closed\"}\n  >\n    {@render children?.()}\n  </div>\n{/if}\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`\nDescription: Whether the node is present (controlled by the user)\n\n**`onExitComplete`**\nType: `VoidFunction`\nDescription: Function called when the animation ends in the closed state\n\n**`immediate`**\nType: `boolean`\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) => 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"}