Skip to content

shadcn.io is an independent project built on shadcn/ui

Components

Free

Presence for React Aria

Keep an element mounted until its exit animation ends, then remove it. For React, when a popover, panel, or toast should animate out instead of vanishing.

React Aria does not include this primitive, so this page uses the Ark UI component. The visuals match the Ark UI version.

Installation

Sign in to get your install command
Free with an account. It carries your token, so the CLI installs everything in one go.
Use email insteadNo credit card

Usage

import React from "react";
import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";
import { Presence } from "@/components/ui/presence";
const PresenceDemo = () => {
  const [present, setPresent] = React.useState(false);

  return (
    <div className="relative">
      <Button
        clickEffect={false}
        onClick={() => setPresent(!present)}
        variant="outline"
      >
        Toggle
      </Button>
      <Presence asChild present={present}>
        <div
          className={cn(
            "absolute bottom-full left-1/2 mb-2 -translate-x-1/2",
            "px-4 py-2",
            "bg-muted",
            "text-sm",
            "rounded-md border",
            "origin-bottom",
            "data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-[98%] data-[state=closed]:slide-out-to-bottom-5 data-[state=closed]:animate-out",
            "data-[state=open]:fade-in-0 data-[state=open]:zoom-in-[98%] data-[state=open]:slide-in-from-bottom-5 data-[state=open]:animate-in"
          )}
        >
          Content
        </div>
      </Presence>
    </div>
  );
};

Accessibility

Enter
Activate the focused control.
Space
Activate the focused control.

FAQ

What does Presence do?

It keeps an element mounted while its exit animation plays, and removes it when the animation ends. Pass present as true or false, and style the data-state of open and closed with your animation classes.

Does Presence render its children before they are shown?

No. lazyMount and unmountOnExit both default to true here, so the content is not rendered until present is first true, and it is removed after the exit animation. Pass lazyMount={false} or unmountOnExit={false} to keep it in the page.

Which animation does it wait for?

The CSS animation on the element while it is in its closed state (data-state="closed"). If the element has no animation there, it is removed at once. The demo uses animate-out classes for the fade and zoom.

How do I animate my own element?

Pass asChild and give Presence one child. It puts its state on that element instead of adding a wrapper, which keeps absolute positioning and the DOM tree as you wrote them.

Do I need Presence for dialogs and popovers?

No. Those components, such as Popover and Dialog, already handle their own exit. Presence is for your own panels, toasts and banners, where nothing else is doing it.

How do I install Presence in React?

Run the command in the Installation section on this page. It adds the presence file, which wraps Ark UI's Presence, and Ark UI as a dependency.

API Reference

Presence

data-slot="presence"

PropType
hideMode?"display-none" | "activity"

How to hide content when mounted but not present. - display-none: HTML hidden attribute. Effects stay alive. - activity: React 19 <Activity mode="hidden">. Effects pause. Requires React 19+.

Type
"display-none" | "activity"
Default
"display-none"
immediate?boolean

Whether to synchronize the present change immediately or defer it to the next frame.

lazyMount?boolean

Whether to enable lazy mounting. Ark default: false.

Default
true
onEnterComplete?VoidFunction

Function called when the animation ends in the open state.

onExitComplete?VoidFunction

Function called when the animation ends in the closed state.

present?boolean

Whether the node is present (controlled by the user).

skipAnimationOnMount?boolean

Whether to allow the initial presence animation.

Default
false
unmountOnExit?boolean

Whether to unmount on exit. Ark default: false.

Default
true
asChild?boolean

Use the provided child element as the default rendered element, combining their props and behavior.