API Reference
Complete API reference for Kinetic components, hooks, and the chainable factory.
Transition
The core animation primitive. Handles enter/leave lifecycle for a single child element.
import { Transition } from '@vitus-labs/kinetic'
<Transition
show={isVisible}
appear
enterStyle={{ opacity: 0, transform: 'scale(0.95)' }}
enterToStyle={{ opacity: 1, transform: 'scale(1)' }}
enterTransition="all 300ms ease-out"
leaveStyle={{ opacity: 1, transform: 'scale(1)' }}
leaveToStyle={{ opacity: 0, transform: 'scale(0.95)' }}
leaveTransition="all 200ms ease-in"
onEnter={() => console.log('entering')}
onAfterEnter={() => console.log('entered')}
onLeave={() => console.log('leaving')}
onAfterLeave={() => console.log('left')}
>
<div>Animated content</div>
</Transition>Props
| Prop | Type | Default | Description |
|---|---|---|---|
show | boolean | — | Controls visibility. true = enter, false = leave + unmount |
appear | boolean | false | Animate on initial mount |
unmount | boolean | true | Unmount when hidden. If false, keeps with display: none |
timeout | number | 5000 | Safety timeout in ms — completes transition if transitionend never fires |
children | ReactElement | — | Single child element (must accept className, style, and ref) |
Style-Based Animation Props
| Prop | Type | Description |
|---|---|---|
enterStyle | CSSProperties | Inline styles for enter start state |
enterToStyle | CSSProperties | Inline styles for enter end state |
enterTransition | string | CSS transition shorthand for enter (e.g. "all 300ms ease-out") |
leaveStyle | CSSProperties | Inline styles for leave start state |
leaveToStyle | CSSProperties | Inline styles for leave end state |
leaveTransition | string | CSS transition shorthand for leave |
Class-Based Animation Props
| Prop | Type | Description |
|---|---|---|
enter | string | Classes applied during the entire enter phase |
enterFrom | string | Classes applied on first frame, removed on next frame |
enterTo | string | Classes applied on second frame, kept until complete |
leave | string | Classes applied during the entire leave phase |
leaveFrom | string | Classes applied on first frame of leave |
leaveTo | string | Classes applied on second frame, kept until complete |
Lifecycle Callbacks
| Callback | Description |
|---|---|
onEnter | Called immediately when entering begins |
onAfterEnter | Called when enter animation completes |
onLeave | Called immediately when leaving begins |
onAfterLeave | Called when leave animation completes |
How It Works
- Enter: Sets
enterStyle/enterFromclasses on mount, then on the next animation frame appliesenterToStyle/enterToclasses. Listens fortransitionend/animationendto complete. - Leave: Sets
leaveStyle/leaveFrom, then appliesleaveToStyle/leaveTo. After completion, unmounts (or hides). - Safety timeout: If the browser event never fires (no transition defined, element removed), the safety
timeoutcompletes the transition.
Collapse
Height-based expand/collapse with smooth animation. Measures content height automatically.
import { Collapse } from '@vitus-labs/kinetic'
<Collapse
show={isExpanded}
transition="height 300ms ease"
appear
>
<div style={{ padding: 16 }}>
<p>Collapsible content of any height.</p>
<p>Height is measured automatically.</p>
</div>
</Collapse>Props
| Prop | Type | Default | Description |
|---|---|---|---|
show | boolean | — | Controls expanded/collapsed state |
transition | string | "height 300ms ease" | CSS transition for height animation |
appear | boolean | false | Animate on initial mount |
timeout | number | 5000 | Safety timeout in ms |
children | ReactElement | — | Content to collapse |
Plus all lifecycle callbacks.
How It Works
- Wraps children in a
divwithoverflow: hidden - On enter: measures content height via
scrollHeight, animates from0to measured height - On leave: animates from current height to
0 - Respects
prefers-reduced-motion— skips animation and applies changes instantly
Stagger
Sequentially animates a list of children with configurable delay between each.
import { Stagger } from '@vitus-labs/kinetic'
import { slideUp } from '@vitus-labs/kinetic'
<Stagger show={show} interval={60} reverseLeave {...slideUp}>
<div key="a">First</div>
<div key="b">Second</div>
<div key="c">Third</div>
</Stagger>Props
| Prop | Type | Default | Description |
|---|---|---|---|
show | boolean | — | Controls visibility of all children |
interval | number | 50 | Delay in ms between each child's animation start |
reverseLeave | boolean | false | Reverse stagger order on leave (last exits first) |
appear | boolean | false | Animate on initial mount |
timeout | number | 5000 | Safety timeout in ms |
children | ReactElement[] | — | Children to stagger |
Plus all style-based, class-based, and lifecycle callback props.
CSS Variables
Each staggered child receives CSS custom properties:
| Variable | Value |
|---|---|
--stagger-index | The child's stagger index (0-based) |
--stagger-interval | The interval as a CSS time value (e.g. "50ms") |
You can use these in CSS for additional effects:
.stagger-item {
animation-delay: calc(var(--stagger-index) * var(--stagger-interval));
}TransitionGroup
Manages enter/exit animations for dynamic keyed lists. Items animate in when added and out when removed.
import { TransitionGroup } from '@vitus-labs/kinetic'
import { fade } from '@vitus-labs/kinetic'
<TransitionGroup {...fade} appear>
{items.map((item) => (
<div key={item.id}>{item.name}</div>
))}
</TransitionGroup>Props
| Prop | Type | Default | Description |
|---|---|---|---|
appear | boolean | false | Animate children present on initial mount |
timeout | number | 5000 | Safety timeout in ms |
children | ReactElement[] | — | Keyed children (must have unique key props) |
Plus all style-based, class-based, and lifecycle callback props.
How It Works
- Tracks children by
keyacross renders - New keys trigger an enter animation
- Removed keys trigger a leave animation before unmounting
- Reappearing keys cancel the leave and re-enter
- Children present on first render only animate if
appear={true}
kinetic() Factory
Creates reusable animated components with an immutable chaining API. Each chain method returns a new component — the original is never mutated.
import { kinetic } from '@vitus-labs/kinetic'
const component = kinetic('div')Chain Methods
| Method | Signature | Description |
|---|---|---|
.preset(p) | (preset: Preset) => KineticComponent | Apply a preset (style + class config) |
.enter(styles) | (styles: CSSProperties) => KineticComponent | Set enter start styles |
.enterTo(styles) | (styles: CSSProperties) => KineticComponent | Set enter end styles |
.enterTransition(v) | (value: string) => KineticComponent | Set enter CSS transition |
.leave(styles) | (styles: CSSProperties) => KineticComponent | Set leave start styles |
.leaveTo(styles) | (styles: CSSProperties) => KineticComponent | Set leave end styles |
.leaveTransition(v) | (value: string) => KineticComponent | Set leave CSS transition |
.enterClass(opts) | ({ active?, from?, to? }) => KineticComponent | Set enter CSS classes |
.leaveClass(opts) | ({ active?, from?, to? }) => KineticComponent | Set leave CSS classes |
.config(opts) | (opts: ConfigOpts) => KineticComponent | Set mode-specific options (appear, timeout, etc.) |
.on(cbs) | (callbacks: TransitionCallbacks) => KineticComponent | Attach lifecycle callbacks |
.collapse(opts?) | ({ transition? }?) => KineticComponent<'collapse'> | Switch to collapse mode |
.stagger(opts?) | ({ interval?, reverseLeave? }?) => KineticComponent<'stagger'> | Switch to stagger mode |
.group() | () => KineticComponent<'group'> | Switch to group mode |
Mode-Specific Props
The props accepted by the rendered component depend on the mode:
Transition Mode (default)
const FadeDiv = kinetic('div').preset(fade)
<FadeDiv show={true} appear unmount timeout={3000} className="card">
content
</FadeDiv>| Prop | Type | Default | Description |
|---|---|---|---|
show | boolean | — | Required. Controls visibility |
appear | boolean | false | Animate on mount |
unmount | boolean | true | Unmount when hidden |
timeout | number | 5000 | Safety timeout |
Plus all standard HTML attributes for the tag.
Collapse Mode
const Accordion = kinetic('div').collapse({ transition: 'height 400ms ease' })
<Accordion show={true} className="panel">
content
</Accordion>| Prop | Type | Default | Description |
|---|---|---|---|
show | boolean | — | Required. Controls expanded state |
appear | boolean | false | Animate on mount |
timeout | number | 5000 | Safety timeout |
transition | string | "height 300ms ease" | CSS transition |
Stagger Mode
const StaggerList = kinetic('ul').preset(slideUp).stagger({ interval: 60 })
<StaggerList show={true}>
<li key="a">First</li>
<li key="b">Second</li>
</StaggerList>| Prop | Type | Default | Description |
|---|---|---|---|
show | boolean | — | Required. Controls visibility |
appear | boolean | false | Animate on mount |
timeout | number | 5000 | Safety timeout |
interval | number | 50 | Delay between each child |
reverseLeave | boolean | false | Reverse order on leave |
Group Mode
const AnimatedList = kinetic('div').preset(fade).group()
<AnimatedList appear>
{items.map(item => <div key={item.id}>{item.name}</div>)}
</AnimatedList>| Prop | Type | Default | Description |
|---|---|---|---|
appear | boolean | false | Animate initial children |
timeout | number | 5000 | Safety timeout |
useTransitionState
Low-level hook for building custom transition components. Manages the four-stage lifecycle state machine.
import { useTransitionState } from '@vitus-labs/kinetic'
function CustomTransition({ show, children }) {
const { stage, ref, shouldMount, complete } = useTransitionState({
show,
appear: true,
})
if (!shouldMount) return null
return (
<div
ref={ref}
onTransitionEnd={complete}
style={{
opacity: stage === 'entering' || stage === 'entered' ? 1 : 0,
transition: 'opacity 300ms',
}}
>
{children}
</div>
)
}Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
show | boolean | — | Controls visibility |
appear | boolean | false | Run enter animation on initial mount |
Returns
| Property | Type | Description |
|---|---|---|
stage | TransitionStage | Current stage: 'hidden' | 'entering' | 'entered' | 'leaving' |
ref | RefObject<HTMLElement> | Ref to attach to the animating element |
shouldMount | boolean | Whether the element should be rendered (false when hidden) |
complete | () => void | Call when the animation finishes to advance the state machine |
useAnimationEnd
Low-level hook that listens for transitionend and animationend events on an element, with a safety timeout.
import { useAnimationEnd } from '@vitus-labs/kinetic'
useAnimationEnd({
ref: elementRef,
onEnd: () => console.log('animation finished'),
active: isAnimating,
timeout: 5000,
})Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
ref | RefObject<HTMLElement> | — | Ref to the animating element |
onEnd | () => void | — | Called when animation completes (or timeout fires) |
active | boolean | — | Only listens when true |
timeout | number | 5000 | Safety timeout if browser events never fire |
Behavior
- Listens for both
transitionendandanimationend - Ignores events bubbled from child elements (checks
event.target === element) - Calls
onEndexactly once per active cycle - Cleans up listeners on deactivation or unmount
Preset Type
Both @vitus-labs/kinetic and @vitus-labs/kinetic-presets use this type:
type Preset = {
// Style-based
enterStyle?: CSSProperties
enterToStyle?: CSSProperties
enterTransition?: string
leaveStyle?: CSSProperties
leaveToStyle?: CSSProperties
leaveTransition?: string
// Class-based
enter?: string
enterFrom?: string
enterTo?: string
leave?: string
leaveFrom?: string
leaveTo?: string
}Presets are spread onto <Transition> or passed to .preset():
// Spread onto Transition
<Transition show={show} {...myPreset}>
<div>content</div>
</Transition>
// Or use with kinetic factory
const AnimatedDiv = kinetic('div').preset(myPreset)