Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/zayne-labs/ui/llms.txt

Use this file to discover all available pages before exploring further.

Overview

The Presence component enables animation of component mount and unmount transitions. It keeps components in the DOM during exit animations and provides hooks for advanced animation control.

Import

import { Presence, usePresence } from "@zayne-labs/ui-react/common/presence";

Presence Component

Props

present
boolean
required
Whether the component should be present in the DOM.
children
React.ReactElement | ((props: RenderPropContext) => React.ReactElement)
required
A single React element with a ref prop, or a render function that receives presence context.
variant
'animation' | 'transition'
default:"'animation'"
The type of CSS animation to use. Use ‘animation’ for CSS animations and ‘transition’ for CSS transitions.
forceMount
boolean
default:"false"
When true, forces the component to always be mounted regardless of the present state.
onExitComplete
() => void
Callback invoked when the exit animation completes.
className
string
Additional CSS class names to apply.

usePresence Hook

function usePresence(options: UsePresenceOptions): UsePresenceResult

Options

present
boolean
required
Whether the component should be present.
variant
'animation' | 'transition'
default:"'animation'"
The type of CSS animation being used.
onExitComplete
() => void
Callback invoked when exit completes.

Returns

isPresent
boolean
Whether the element is currently present in the state machine.
isPresentOrIsTransitionComplete
boolean
Whether the element is present or has completed its transition.
shouldStartTransition
boolean
Whether a transition should start.
ref
React.Ref<HTMLElement>
Ref to attach to the animated element.
propGetters
{ getPresenceProps: (props) => props }
Prop getter function for applying presence attributes.

Type Definitions

type RenderPropContext = {
  isPresent: boolean;
  isPresentOrIsTransitionComplete: boolean;
  shouldStartTransition: boolean;
};

type UsePresenceResult = {
  isPresent: boolean;
  isPresentOrIsTransitionComplete: boolean;
  propGetters: {
    getPresenceProps: (innerProps: InferProps<HTMLElement>) => InferProps<HTMLElement>;
  };
  ref: React.Ref<HTMLElement>;
  shouldStartTransition: boolean;
};

Data Attributes

The component adds these data attributes for styling:
  • data-present: “true” when the element is present
  • data-present-or-transition-complete: “true” when present or transition is complete
  • data-state: Current state (“mounted”, “unmountSuspended”, “unmounted”)
  • data-transition: “active” or “inactive” (only when variant="transition")

Usage Examples

Basic Animation

function AnimatedBox() {
  const [show, setShow] = useState(true);
  
  return (
    <>
      <button onClick={() => setShow(!show)}>Toggle</button>
      <Presence present={show}>
        <div className="box">I will animate!</div>
      </Presence>
    </>
  );
}
.box {
  animation: fadeIn 300ms ease-out;
}

.box[data-state="unmountSuspended"] {
  animation: fadeOut 300ms ease-out;
}

@keyframes fadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

@keyframes fadeOut {
  from { opacity: 1; }
  to { opacity: 0; }
}

CSS Transitions

<Presence present={isOpen} variant="transition">
  <div className="modal">Modal Content</div>
</Presence>
.modal {
  opacity: 0;
  transform: scale(0.95);
  transition: opacity 200ms, transform 200ms;
}

.modal[data-transition="active"] {
  opacity: 1;
  transform: scale(1);
}

Render Function

<Presence present={visible}>
  {({ isPresent, shouldStartTransition }) => (
    <div
      className="alert"
      data-visible={isPresent}
      data-animating={shouldStartTransition}
    >
      Alert message
    </div>
  )}
</Presence>

Exit Callback

<Presence
  present={isShowing}
  onExitComplete={() => {
    console.log('Animation finished!');
    onClose();
  }}
>
  <Notification>Your changes have been saved.</Notification>
</Presence>

Force Mount

<Presence present={isActive} forceMount>
  <div className="overlay" aria-hidden={!isActive}>
    Content always in DOM
  </div>
</Presence>

Using the Hook

function CustomAnimatedComponent({ visible }) {
  const {
    isPresent,
    shouldStartTransition,
    propGetters,
    ref
  } = usePresence({ present: visible });
  
  if (!isPresent) return null;
  
  return (
    <div
      ref={ref}
      {...propGetters.getPresenceProps({
        className: 'custom-component'
      })}
    >
      Content with custom animation logic
    </div>
  );
}

Conditional Content Based on State

<Presence present={isPending} variant="transition">
  {({ shouldStartTransition }) => (
    <LoadingSpinner active={shouldStartTransition} />
  )}
</Presence>

Notes

  • The component uses a state machine internally to manage mount/unmount states
  • For variant="animation", it detects animation name changes to determine when to suspend unmounting
  • For variant="transition", it listens to transitionrun and transitionend events
  • The child element must accept a ref prop
  • Only one child element is allowed (or a render function that returns one element)
  • The component sets animationFillMode: 'forwards' during exit to prevent flashing
  • Based on Radix UI’s Presence implementation

Build docs developers (and LLMs) love