is an element animation orchestrator for React.js ✨
yubaba is as much of a platform as it is an orchestrator.
It comes with prebuilt animations you can drop in and start using immediately,
such as ConcealMove and RevealMove which together can create an awesome user experience!
But even better you can create custom animations! Using the same internals the prebuilt animations use, it comes with a first class customization experience for you to do, well, anything!
npm install yubaba emotion --saveor
yarn add yubaba emotionA list of elements (the parent) transitioning to show more information (the child).
Elements transforming into another.
A range of different scenarios for each animation component. Looking for component API docs?
Transitioning the same element from one place to another.
Helping the focal animation look the best it can be.
We'll build up each step to leave you with an awesome transition. Click each gif to see its codesandbox.
We have two disjointed components that are toggled when clicked (click on Finn!). How can we transition them to each other?
Let's use the Baba and CrossFadeMove components to have them seamlessly transition to the destination. Baba is the brains - it does all of the orchestration. CrossFadeMove is one of many focal animations available - it will cross fade both elements from the starting point to the destination point.
Okay so that looks cool, but Finn's sword is shown immediately! Is there anything we can do to make it show after all animations have finished?
Let's bring in a component BabaManager which will be used to delay showing Finn's sword. You can imagine this as content in a page around the destination element that should be shown after all animations have finished.
Cool, now we're making progress. We can do better though, what if Finn could really sell his preparation that he's about to attack?
Let's bring in a component CircleExpand which will expand to fit the viewport, for Finn it will give him some oomph to really sell the attack.
Really cool! But both the CircleExpand and CrossFadeMove happening at the same time looks kind of weird, what if we could delay CrossFadeMove until after CircleExpand had finished animating?
Let's bring in a component Wait which will delay the next animation from happening until after the previous one has finished!
And there you have it, a masta-peece!
Yubaba comes with the ability for you to make your own animations using the same plumbing the official animations are constructed from. Look in src/animations for example implementations.
Tutorial(s) coming soon.
These components exist to pass data around and orchestrate the animations.
This is the primary component in yubaba.
When rendering it will be given all of the animation data from its children.
When unmounting or flipping the "in" prop from true to false,
it will execute all the animations top to bottom if a matching Baba pair is found within 50ms.
import Baba from 'yubaba';
<Baba name="baba">
{({ ref, style, className }) => <div ref={ref} style={style} className={className} />}
</Baba>;Used to explicitly mark the focal element, only a handful of animations require this component to be used, for example Reveal.
import Baba, { FocalTarget } from 'yubaba';
<Baba name="target">
<FocalTarget>{({ ref }) => <div ref={ref} />}</FocalTarget>
</Baba>;Used as the glue for all animation components, every animation component will use this internally to pass the data to the parent Baba.
import { Collector } from 'yubaba';
<Collector
data={{
action: 'animation',
payload: {
beforeAnimate: this.beforeAnimate,
animate: this.animate,
afterAnimate: this.afterAnimate,
},
}}
>
{children}
</Collector>;Transitioning visually similar elements from one place to another.
Move (example)
Will transition the destination element from the origin element position.
// origin-element.js
import Baba, { Move } from 'yubaba';
<Baba name="move">
<Move>{baba => <div {...baba} />}</Move>
</Baba>;
// destination-element.js
import Baba from 'yubaba';
<Baba name="move">{baba => <div {...baba} />}</Baba>;Will position: absolute move the origin element to the destination element while fading out.
// origin-element.js
import Baba, { FadeMove } from 'yubaba';
<Baba name="fade-move">
<FadeMove>{baba => <div {...baba} />}</FadeMove>
</Baba>;
// destination-element.js
import Baba from 'yubaba';
<Baba name="fade-move">{baba => <div {...baba} />}</Baba>;CrossFadeMove (example)
Composes the Move and FadeMove animations for a cross-fade move.
// origin-element.js
import Baba, { CrossFadeMove } from 'yubaba';
<Baba name="cross-fade">
<CrossFadeMove>{baba => <div {...baba} />}</CrossFadeMove>
</Baba>;
// destination-element.js
import Baba from 'yubaba';
<Baba name="cross-fade">{baba => <div {...baba} />}</Baba>;Reveals the destination element container from the Target component. A limitation at the moment is the destination element must have an animation defined, if you don't want one to happen use the Noop animation. Requires the use of the Target component to specify the focal element.
// origin-element.js
import Baba, { Reveal, Target } from 'yubaba';
<Baba name="reveal">
<Reveal>{baba => <div {...baba} />}</Reveal>
</Baba>;
// destination-element.js
import Baba, { FocalTarget, Noop } from 'yubaba';
<Baba name="reveal">
<Noop>
{baba => (
<div {...baba}>
<FocalTarget>{target => <div {...target} />}</FocalTarget>
</div>
)}
</Noop>
</Baba>;RevealMove (example)
Useful for transitioning from a parent to a child, will expand from the focal element to the container. Requires the use of the Target component to specify the focal element.
// origin-element.js
import Baba, { RevealMove } from 'yubaba';
<Baba name="reveal-move">
<RevealMove>{baba => <div {...baba} />}</RevealMove>
</Baba>;
// destination-element.js
import Baba, { FocalTarget, Noop } from 'yubaba';
<Baba name="reveal-move">
<Noop>
{baba => (
<div {...baba}>
<FocalTarget>{target => <div {...target} />}</FocalTarget>
</div>
)}
</Noop>
</Baba>;ConcealMove (example)
Useful for transitioning from a child to a parent, will shrink from the container to the focal element. Requires the use of the FocalTarget component to specify the focal element.
// origin-element.js
import Baba, { FocalTarget, ConcealMove } from 'yubaba';
<Baba name="conceal-move">
<ConcealMove>
{baba => (
<div {...baba}>
<FocalTarget>{target => <div {...target} />}</FocalTarget>
</div>
)}
</ConcealMove>
</Baba>;
// destination-element.js
import Baba from 'yubaba';
<Baba name="conceal-move">{baba => <div {...baba} />}</Baba>;A no-operation "noop" animation.
// origin-element.js
import Baba, { Noop } from 'yubaba';
<Baba name="noop">
<Noop>{baba => <div {...baba} />}</Noop>
</Baba>;
// destination-element.js
import Baba from 'yubaba';
<Baba name="noop">{baba => <div {...baba} />}</Baba>;Helping the focal animation look the best it can be when transitioning.
BabaManager (example)
Used to hide contents before an animation is complete triggered from a child component. If there is more than one child you can use an optional name prop which should match the appropriate component.
If it is the initial mount it will immediately be shown.
// origin-element.js
import Baba, { Move } from 'yubaba';
<Baba name="expand">
<Move>{baba => <div {...baba} />}</Move>
</Baba>;
// destination-element.js
import Baba, { BabaManager } from 'yubaba';
<BabaManager>{({ style }) => <div style={style}>{<Baba>{/* ... */}</Baba>}</div>}</BabaManager>;Is used to pause the execution of all child animations until all parent children animations have completed.
E.g: CircleExpand will wait until Move has finished before starting.
// origin-element.js
import Baba, { Wait, Move, CircleExpand } from 'yubaba';
<Baba name="wait">
<Move>
<Wait>
<CircleExpand>{baba => <div {...baba} />}</CircleExpand>
</Wait>
</Move>
</Baba>;
// destination-element.js
import Baba from 'yubaba';
<Baba name="wait">{baba => <div {...baba} />}</Baba>;CircleExpand (example)
Will animate a circle from the origin element to cover the entire viewport, and then fade out.
Generally you should use CircleExpand and CricleShrink together to seamlessly transition the background between pages.
// origin-element.js
import Baba, { CircleExpand } from 'yubaba';
<Baba name="expand">
<CircleExpand>{baba => <div {...baba} />}</CircleExpand>
</Baba>;
// destination-element.js
import Baba from 'yubaba';
<Baba name="expand">{baba => <div {...baba} />}</Baba>;CircleShrink (example)
Will animate a circle from the viewport to destination element, and then fade out.
Generally you should use CircleExpand and CricleShrink together to seamlessly transition the background between pages.
// origin-element.js
import Baba, { CircleShrink } from 'yubaba';
<Baba name="shrink">
<CircleShrink>{baba => <div {...baba} />}</CircleShrink>
</Baba>;
// destination-element.js
import Baba from 'yubaba';
<Baba name="shrink">{baba => <div {...baba} />}</Baba>;Swipe (example)
Will animate a square swiping over the viewport.
// origin-element.js
import Baba, { Swipe } from 'yubaba';
<Baba name="swipe">
<Swipe>{baba => <div {...baba} />}</Swipe>
</Baba>;
// destination-element.js
import Baba from 'yubaba';
<Baba name="swipe">{baba => <div {...baba} />}</Baba>;




