useMotion
Hook that manages enter/leave animations with CSS class transitions and visibility control.
Usage#
import { useMotion } from '@primereact/core/motion';const ref = React.useRef<HTMLDivElement>(undefined);
const motion = useMotion({
elementRef: ref,
visible: isOpen,
name: 'fade'
});
return <>{motion.state.rendered && <div ref={ref} {...motion.rootProps}></div>}</>;useMotion runs a CSS class-based enter/leave animation lifecycle against a single element, returning rootProps for hidden styles and state.rendered for conditional mounting.
Features#
- CSS class lifecycle — applies
{name}-enter-from,{name}-enter-active,{name}-enter-toon enter and mirrored-leave-*classes on leave - Mount management —
state.renderedcombined withmountOnEnter/unmountOnLeavekeeps the element in the DOM only while needed - Hide strategies — choose how closed content is hidden:
display: none,visibility: hidden, or let CSS animations handle it entirely - Dimension variables —
cssVarPrefixwrites--{prefix}-height/--{prefix}-widthon the element for collapsible transitions - Full lifecycle callbacks — eight hooks covering before/during/after/cancelled for both enter and leave phases
- Imperative control —
enter(),leave(),cancel(), andupdate()for programmatic transitions
Working with callbacks#
Drive animations with a name prefix#
Pick a name and define six CSS classes against that prefix. The hook applies them in order across the enter and leave phases.
const motion = useMotion({ elementRef: ref, visible, name: 'slide' });.slide-enter-from {
opacity: 0;
transform: translateY(-10px);
}
.slide-enter-active {
transition: all 200ms ease-out;
}
.slide-enter-to {
opacity: 1;
transform: translateY(0);
}
.slide-leave-from {
opacity: 1;
transform: translateY(0);
}
.slide-leave-active {
transition: all 200ms ease-in;
}
.slide-leave-to {
opacity: 0;
transform: translateY(-10px);
}Collapsible height transitions#
Set cssVarPrefix so the hook injects scroll-height into a CSS variable you can read from your transitions.
const motion = useMotion({ elementRef: ref, visible, cssVarPrefix: 'panel-content' });.collapsible-enter-active,
.collapsible-leave-active {
transition: max-height 300ms ease;
overflow: hidden;
}
.collapsible-enter-to,
.collapsible-leave-from {
max-height: var(--panel-content-height);
}
.collapsible-enter-from,
.collapsible-leave-to {
max-height: 0;
}Run the enter animation on mount#
Enable appear so the enter lifecycle plays the first time the element becomes visible, instead of jumping straight to its final state.
const motion = useMotion({ elementRef: ref, visible: true, appear: true, name: 'fade' });React to phase transitions#
Use the lifecycle callbacks to coordinate side effects — trigger focus moves after enter, release listeners after leave, or clean up inline styles.
const motion = useMotion({
elementRef: ref,
visible,
name: 'fade',
onBeforeEnter: (e) => e.el.style.setProperty('will-change', 'opacity'),
onAfterEnter: () => inputRef.current?.focus(),
onAfterLeave: () => releaseScrollLock()
});| Callback | Phase |
|---|---|
onBeforeEnter | Before enter transition starts |
onEnter | Enter transition starts |
onAfterEnter | Enter transition ends |
onEnterCancelled | Enter transition cancelled |
onBeforeLeave | Before leave transition starts |
onLeave | Leave transition starts |
onAfterLeave | Leave transition ends |
onLeaveCancelled | Leave transition cancelled |
Imperative control#
Call enter(), leave(), or cancel() to drive the animation from outside a visibility prop, and update() to reconfigure the instance on an existing element.
const motion = useMotion({ elementRef: ref, visible, name: 'fade' });
motion.enter();
motion.leave();
motion.cancel();
motion.update(element, { name: 'slide', duration: 300 });Hide strategy reference#
Switch hideStrategy to match what your CSS expects. display is the default because it removes the element from layout entirely.
| Value | Behavior |
|---|---|
'display' | Applies display: none (default) |
'visibility' | Applies visibility: hidden and max-height: 0 |
'none' | No automatic hiding — CSS animations handle it entirely |
API#
useMotion#
| Name | Type | Default |
|---|---|---|
elementRef | HTMLElement | RefObject<HTMLElement> | — |
| The ref of the element to apply the motion to. | ||
visible | boolean | false |
| Whether the element is visible or not. | ||
mountOnEnter | boolean | true |
| Whether the motion should be applied when the element is mounted. | ||
unmountOnLeave | boolean | true |
| Whether the element should be unmounted when the motion is not applied. | ||
name | string | — |
| The name of the motion. It can be a predefined motion name or a custom one. phases: [name]-enter [name]-enter-active [name]-enter-to [name]-leave [name]-leave-active [name]-leave-to | ||
type | MotionType | — |
| The type of the motion, valid values 'transition' and 'animation'. | ||
disabled | boolean | false |
| Whether the motion is disabled. | ||
appear | boolean | false |
| Whether the motion should appear. | ||
enter | boolean | true |
| Whether the motion should enter. | ||
leave | boolean | true |
| Whether the motion should leave. | ||
duration | MotionDuration | — |
| The duration of the motion. | ||
hideStrategy | "none" | "display" | "visibility" | — |
| The hide strategy of the motion. - `'display'` - hides with `display: none` - `'visibility'` - hides with `visibility: hidden` - `'none'` - no hiding, CSS handles it (e.g. height-based) | ||
cssVarPrefix | string | — |
| CSS variable prefix for motion-related variables (e.g. `'p'` produces `--p-height` ). | ||
enterFromClassName | string | — |
| The enter from class of the motion. | ||
enterToClassName | string | — |
| The enter to class of the motion. | ||
enterActiveClassName | string | — |
| The enter active class of the motion. | ||
leaveFromClassName | string | — |
| The leave from class of the motion. | ||
leaveToClassName | string | — |
| The leave to class of the motion. | ||
leaveActiveClassName | string | — |
| The leave active class of the motion. | ||
onBeforeEnter | (event?: MotionEvent) => void | — |
| Callback fired before the enter transition/animation starts. | ||
onEnter | (event?: MotionEvent) => void | — |
| Callback fired when the enter transition/animation starts. | ||
onAfterEnter | (event?: MotionEvent) => void | — |
| Callback fired after the enter transition/animation ends. | ||
onEnterCancelled | (event?: MotionEvent) => void | — |
| Callback fired when the enter transition/animation is cancelled. | ||
onBeforeLeave | (event?: MotionEvent) => void | — |
| Callback fired before the leave transition/animation starts. | ||
onLeave | (event?: MotionEvent) => void | — |
| Callback fired when the leave transition/animation starts. | ||
onAfterLeave | (event?: MotionEvent) => void | — |
| Callback fired after the leave transition/animation ends. | ||
onLeaveCancelled | (event?: MotionEvent) => void | — |
| Callback fired when the leave transition/animation is cancelled. | ||
Accessibility#
No keyboard behavior — a primitive for animation that does not affect accessibility. See Primitive for full WAI-ARIA compliance details.