Demos

Ever wished you had an easy way to animate when you move an element from one place in the DOM to another?
Ever wanted to move other elements out of the way smoothly when you add a new one?
FlippyJS lets you animate DOM changes in the easiest way possible: give it some elements to animate, then change the DOM however you want, and FlippyJS will figure out the rest.

If you’d like to see how the below demos look without using FlippyJS, simply toggle this checkbox:

Flexbox columns

An element is moved in and out of a flexbox column.

This is about as simple as DOM changes get, but is very difficult to animate without FLIP animations.

1
2
3
4
5
6
7
8
9
<div class="column">
    <div class="module"></div>
    <div class="module"></div>
    <div class="module"></div>
</div>
<div class="column">
    <div id="flexbox-columns-movable" class="module large interactive"></div>
    <div class="module"></div>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
let $elm = document.getElementById("flexbox-columns-movable");
let $parents = [
    ".flexbox-columns",
    ".flexbox-columns .column:nth-child(2)"
].map(elm=>document.querySelector(elm));

$elm.addEventListener("click", ()=>{
    // when the element is clicked, animate the move
    flip(
        ".flexbox-columns .module", // elements to animate
        ()=>{ // function which makes the DOM change
            let $parent = $parents[0];
            if ($elm.parentNode === $parents[0]) {
                $parent = $parents[1];
            }
            $parent.insertBefore(
                $elm,
                $parent.firstChild
            );
        },
        { // options object
            ease: "cubic-bezier(0.4, 2.2, 0.5, 0.7)"
        }
    );
});

Twitch-style minimize

You might have seen this kind of animation on YouTube or Twitch.
A video is moved from its position in the normal flow of the page to a fixed position.

Since FlippyJS uses transforms to animate, the video will continue playing as it’s moved.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<video autoplay loop muted
    id="twitch-minimize-video"
    class="minimizable"
    src="/flippy.js/assets/video/train.mp4">
    Your browser doesn't seem to support videos :(
</video>
<div id="twitch-minimize-video-placeholder" class="placeholder"></div>

<p class="placeholder">
    <span></span>
    <span></span>
    <span></span>
    <span></span>
    <span></span>
    <span></span>
</p>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
.minimizable {
    cursor: pointer;

    &.minimized {
        width: 150px;
        position: fixed;
        bottom: 10px;
        left: 10px;
    }
}

#twitch-minimize-video-placeholder {
    display: none;

    .minimized + & {
        display: block;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// the placeholder makes sure other content on the 
// page isn't moved up when we minimize the video
let $video = document.getElementById("twitch-minimize-video");
let $placeholder = document.getElementById("twitch-minimize-video-placeholder");
$video.addEventListener("loadeddata", ()=>{
    $placeholder.style.width = $video.clientWidth+"px";
    $placeholder.style.height = $video.clientHeight+"px";
});

// toggle minimized when the video is clicked
$video.addEventListener("click", ()=>{
    flip(
        $video,
        ()=>{
            $video.classList.toggle("minimized");
        }
    );
});

Adding elements

If elements are added to the DOM, FlippyJS only animates their size (from 0), not their position.

1
2
3
4
5
6
<div class="column">
    <div class="module"></div>
    <div class="module"></div>
    <div class="module"></div>
    <div class="module"></div>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
let $column = document.querySelector(".adding-elements .column");

setInterval(addModule, 2000);

function addModule() {
    let $module = document.createElement("div");
    $module.classList.add("module");

    flip(
        [$module, ...document.querySelectorAll(".adding-elements .module")],
        ()=>{
            // add our new module to the column
            $column.insertBefore(
                $module,
                $column.firstChild
            );
            // also remove the last module in the column
            $column.removeChild(
                $column.lastElementChild
            );
        },
        {
            duration: 600
        }
    )
}

Listening for animation end

There are two ways to listen for animation end: wait for the returned Promise to resolve, or add the callback property to the options.

1
<div class="module square absolute"></div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
let $module = document.querySelector(".listening-for-animation-end .module");
let index = -1;
let baseState = {
    left: "", top: "",
    right: "", bottom: "",
    transform: ""
};
let states = [
    {
        left: "50px", top: "50px",
        transform: "rotate(45deg)"
    },
    {
        left: "50px", bottom: "50px"
    },
    {
        right: "50px", bottom: "50px",
        transform: "scale(0.5)"
    },
    {
        top: "50px", right: "50px"
    }
];

function animate() {
    if (index === states.length-1) {
        index = -1;
    }

    flip(
        $module,
        ()=>{
            let state = states[++index];
            for (let prop in baseState) {
                if (state.hasOwnProperty(prop)) {
                    $module.style[prop] = state[prop];
                } else {
                    $module.style[prop] = baseState[prop];
                }
            }
        }
    ).then(animate);
}
document.addEventListener("DOMContentLoaded", animate);