shadcn.io is an independent project built on shadcn/ui
Installation
Usage
<script lang="ts">
import React from "react";
import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";
import { Presence } from "@/components/ui/presence";
</script>
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.
API Reference
Presence
data-slot="presence"
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?Snippet<[PropsFn]>
Render your own element: a snippet that gets the part's props to spread on it.
- Type
Snippet<[PropsFn]>