A simple library that brings together react-animations, styled-components and react-waypoint to give you out-of-the-box animations for your React project.
First, you install the react-bling
library.
npm i react-bling
or yarn install react-bling
Next, you import the default Bling
component along with the animations that you want to use from the react-bling library.
import Bling, { fadeIn, tada} from 'react-bling';
Finally, you wrap some React component(s) or element(s) in a Bling
component and pass it animations and display information via props
.
Animations can either applied one of two ways:
- On the initial render via the
animate
prop - When the
Bling
component enters or exits the viewport via thewaypoint
prop.
This library exposes the animations and merge
function provided by react-animations along with the ability to chain these animations.
I created the following website, which lets you sample all of the animations provided provided by react-animations: https://rad.surge.sh
Here is the most basic example using the animate
prop and fadeIn
animation only:
import React from 'react';
import Bling, { fadeIn } from 'react-bling';
const App = () => (
<Bling animate={{ animation: fadeIn }}>
<p>Go react-bling!</p>
</Bling>
);
export default App;
react-bling accepts the following props: el
, render
, animate
, waypoint
type: string
default: 'div'
The el
prop is used to define the html element type used as the Bling
wrapper component. You can use any element within the limitations of the language. For instance, you cannot use el='p'
and also render a p
tag as a child.
Example:
<Bling el="div" ... />
The render
prop is used to render your wrapped component(s) or element(s) and accepts a function or component. You can also just wrap your component(s) or element(s) in an opening and closing Bling
tag as shown in the example above.
<Bling
animate={{animation: fadeIn}}
render={<p>Go react-bling!</p>}
/>
/* is the same as */
<Bling
animate={{animation: fadeIn}}
render={() => <p>Go react-bling!</p>}
/>
/* is the same as */
<Bling animate={{animation: fadeIn}}>
<p>Go react-bling!</p>
</Bling>
Note- The
animate
andwaypoint
props cannot be used together.
type: object
or array
The animate
prop is used to set animation(s) when the Bling
wrapper component first renders. You can either provide a single animation object or multiple animation objects in an array. If an array is provided, the animations will be applied in the same order as the array.
A single animation
import React from 'react';
import Bling, { fadeIn } from 'react-bling';
const App = () => (
<Bling
animate={{
animation: fadeIn,
duration: 3,
delay: 2,
iterate: 2,
}}
render={<p>Go react-bling!</p>}
/>
);
export default App;
An array of animations
const App = () => (
<Bling
animate={[
{
animation: fadeIn,
duration: 3,
},
{
animation: tada,
duration: 2,
iterate: 2,
},
{
animation: fadeOut,
duration: 4,
},
]}
render={<p>Go react-bling!</p>}
/>
);
export default App;
Properties:
animation
type: object
(required)
You can pass any animation that you import from react-bling. You can also use react-animations' merge
function to make your own unique animations. animation: merge(fadeIn, tada)
duration
type: number
default: 2
This property accepts a number representing the duration of the animation in seconds.
delay
type: number
default: 0
This property accepts a number representing the delay of the animation in seconds.
iterate
type: number | string
default: 1
This property accepts a number representing the number of times the animation should repeat. You can also pass the string 'infinite'
to repeat until the end of time.
direction
type: string
default: 'normal'
This property accepts a number representing the animation-direction property.
accepted values: 'normal' | 'reverse' | 'alternate' | 'alternate-reverse'
type: object
The waypoint
prop is used to set animation(s) when the Bling
wrapper component enters and leaves the viewport.
Properties:
position
type: string
options: 'above' | 'below'
default: 'above'
Places the waypoint
above or below the wrapped component(s) or element(s).
topOffset
type: string || number
examples: 100 | -100 | '100px' | '100%'
default: '0px'
bottomOffset
type: string || number
examples: 100 | -100 | '100px' | '100%'
default: '0px'
The topOffset
and bottomOffset
properties control the top and bottom boundaries of the waypoint
component and can be a little tricky to grasp at first. You can provide a number, which represents pixels. You can also represent pixels, percentages, etc. as strings. (eg. '100%'
)
If you set topOffset:'100px'
, this can be thought of like pushing the top boundary of the page down 100 pixels. This means that if you are scrolling up from the bottom, your leave
animation would be triggered when the waypoint
got to 100 pixels below the top of the screen. And if you are scrolling down from the very top, the enter
animation will not be triggered until it reaches 100 pixels below the top of the screen.
If you set bottomOffset:'100px'
, this can be thought of like pushing the bottom boundary of the page up 100 pixels. This means that if you are scrolling down from the top, your leave
animation would be triggered when the waypoint
got to 100 pixels above the bottom of the screen. And if you are scrolling up from the very bottom, the enter
animation will not be triggered until it reaches 100 pixels above the bottom of the screen.
Hopefully that makes sense. If you are still blurry, you might find this explanation from react-waypoint
useful:
topOffset
can either be a number, in which case its a distance from the top of the container in pixels, or a string value. Valid string values are of the form "20px", which is parsed as pixels, or "20%", which is parsed as a percentage of the height of the containing element. For instance, if you pass "-20%", and the containing element is 100px tall, then the waypoint will be triggered when it has been scrolled 20px beyond the top of the containing element.
enter
type: object || array
(required)
leave
type: object || array
(required)
The enter
and leave
properties are used to define the animations and animation details for when the Bling
component enters and leaves the viewport. These properties have the same structure as the animate
prop and are defined the same way, except as properties on the waypoint
prop object.
onEnter
type: function
onLeave
type: function
Both the onEnter
and onLeave
properties accept a callback that you can provide for when the Bling
component enters or leaves the viewport respectively. The onEnter
and onLeave
callbacks provide you with three values in the following order:
currentPosition
- Either 'inside' or 'outside' (the boundaries)
previousPosition
- Either 'inside' or 'outside' (the boundaries)
event
The bling
component can be styled in a number of different ways:
With inline styles
<Bling
style={{ border: '2px solid firebrick' }}
...
/>
By extending the component with styled-components
const StyledBling = styled(Bling)`
position: fixed;
width: 100%;
text-align: center;
z-index: 9.97999999890000033531123335706e29;
`;
By using the .bling
class
Styles created with the .bling
class will be applied to all Bling
components rendered on the page. Maybe this is what you want. If not, consider the other styling options.
.bling {
position: fixed;
width: 100%;
text-align: center;
z-index: 9.97999999890000033531123335706e29;
}
Using the animate
prop
<Bling
animate={[
{
animation: merge(tada, flip),
duration: 2,
iterate: 2,
direction: 'alternate',
},
{
animation: fadeOut,
duration: 3,
delay: 2,
},
]}
render={<h1>Hello</h1>}
/>
Using the waypoint
prop
<Bling
waypoint={{
onEnter: (currentPosition, previousPosition, event) => {
console.log(currentPosition, previousPosition, event);
},
onLeave: (currentPosition, previousPosition, event) => {
console.log(currentPosition, previousPosition, event);
},
position: 'above',
enter: {
animation: merge(tada, flip),
duration: 2,
},
leave: [
{
animation: tada,
duration: 3,
},
{
animation: fadeOut,
duration: 3,
},
],
}}
render={<h1>Hello</h1>}
/>
bouceOut
bounce
bounceIn
bounceInDown
bounceInLeft
bounceInRight
bounceInUp
bounceOutDown
bounceOutLeft
bounceOutRight
bounceOutUp
fadeIn
fadeInDown
fadeInDownBig
fadeInLeft
fadeInLeftBig
fadeInRight
fadeInRightBig
fadeInUp
fadeInUpBig
fadeOut
fadeOutDown
fadeOutDownBig
fadeOutLeft
fadeOutLeftBig
fadeOutRight
fadeOutRightBig
fadeOutUp
fadeOutUpBig
flash
flip
flipInX
flipInY
flipOutX
flipOutY
headShake
hinge
jello
lightSpeedIn
lightSpeedOut
pulse
rollIn
rollOut
rotateIn
rotateInDownLeft
rotateInDownRight
rotateInUpLeft
rotateInUpRight
rotateOut
rotateOutDownLeft
rotateOutDownRight
rotateOutUpLeft
rotateOutUpRight
rubberBand
shake
slideInDown
slideInLeft
slideInRight
slideInUp
slideOutDown
slideOutLeft
slideOutRight
slideOutUp
swing
tada
wobble
zoomIn
zoomInDown
zoomInLeft
zoomInRight
zoomInUp
zoomOut
zoomOutDown
zoomOutLeft
zoomOutRight
zoomOutUp
From the react-animations README:
react-animations also exports a
merge
function that takes two animations and returns a new animation that combines the transforms from both. This is experimental and wont work (well) with animations that have conflicting transforms, such asfadeIn
andfadeOut
. The merged animation can be used just like any of the imported animations.
While creating this library, I went back and forth between two approaches to handling arrays of animations:
The current (and more verbose) approach:
<Bling
animate={[
{
animation: fadeIn,
duration: 3,
},
{
animation: tada,
duration: 2,
iterate: 2,
},
{
animation: fadeOut,
duration: 4,
},
]}
render={<p>Go react-bling!</p>}
/>
and the more succinct approach:
<Bling
animate={{
animation: [fadeIn, tada, fadeOut],
duration: [3, 2, 4],
delay: [0, 0, 1],
iterate: [1, 2, 1],
}}
render={<p>Go react-bling!</p>}
/>
Ultimately, I decided to go with the more verbose approach as I found it easier to read, understand and work with. Imagine you pass an array of three animations but an array of only two durations. Should the last animation use the previous duration or the default duration value? I find it much easier to explicitly define the properties for each animation with the assumption that the defaults are applied if no value is provided.
Also, if you decide to change the order of animations later, it's much easier when they are grouped together as objects as opposed to each value being a part of a seperate array.
Made with 💚 by a vegan