Skip to content
/ flip.js Public

Flip.js is an element for flipping effect for wrapped elements.

License

Notifications You must be signed in to change notification settings

lf2com/flip.js

Repository files navigation

flip.js

Flip.js is a HTML element for flipping child nodes.


Demo

Flip

Sets flip properties of duration, direction, and mode.

Flip

List

Flips items of list, you can arrange, add, and remove items.

List

Canvas

Flips canvas candidates.

Canvas

Get Started

<script defer src="https://unpkg.com/@lf2com/flip.js@latest/dist/flip.min.js"></script>
<!-- or -->
<script defer src="https://cdn.jsdelivr.net/gh/lf2com/flip.js@latest/dist/flip.min.js"></script>

Use flip in HTML:

<flip-pack direction="down" mode="random">
  <div class="candidate">1</div>
  <div class="candidate">2</div>
  <div class="candidate">3</div>
  <div class="candidate">4</div>
  <div class="candidate">5</div>
</flip-pack>

Or in JavaScript code:

const flip = document.createElement('flip-pack');

flip.setAttribute('direction', 'down');
flip.setAttribute('mode', 'random');
// or
flip.direction = 'down';
flip.mode = 'random';

for (let i = 0; i < 5; i += 1) {
  const candidate = document.createElement('div');

  candidate.classList.add('candidate');
  candidate.innerText = `${i + 1}`;
  flip.append(candidate);
}

document.body.append(flip);

As flip.js is an element, we can code in jQuery:

$('<flip-pack>')
  .attr({
    direction: 'down',
    mode: 'random',
  })
  .append(new Array(5)
    .fill(0)
    .map((_, i) => (
      $('<div>')
        .addClass('candidate')
        .html(`${i + 1}`)
    ))
  )
  .appendTo($('body'));

Or in React:

const Flip = () => (
  <flip-pack
    direction="down"
    mode="random"
  >
    {(new Array(5)
      .fill(0)
      .map((_, i) => (
        <div key={i} className="candidate">
          {i + 1}
        </div>
      ))
    )}
  </flip-pack>
);

Styling Child Nodes

⚠️ On flipping, we clone the last and next candidate children for displaying flipping animation. So if the child nodes are styled by CSS, we need to let the cloned nodes styled as the same so that them can be displayed correctly. As a result, there are some rules for preventing from issues of flipping animation.

Specific Selector of Parent

Selectors such as flip-pack > {selector} define those styles directly belong to flip-pack, causing missing the styles of cloned elements. It is recommended to use flip-pack.some-class {selector} instead.

/*
 * [DO NOT USE]: flip-pack > {selector}
 */
flip-pack > .candidate {
  width: 100px;
  height: 150px;
  border-radius: 10px;
  background: #eee;
  font-size: 30px;
  color: #000;
}

/*
 * [BETTER TO USE]: flip-pack {selector}
 */
flip-pack.candidate-set-1 .candidate {
  width: 100px;
  height: 150px;
  border-radius: 10px;
  background: #eee;
  font-size: 30px;
  color: #000;
}
<flip-pack class="candidate-set-1">
  <div class="candidate">A</div>
  <div class="candidate">B</div>
  <div class="candidate">C</div>
  <div class="candidate">D</div>
</flip-pack>

Nth Selector

Selectors specifying the n-th node such as :nth-child() cause the cloned element being applied unexpected styles due to the cloned element would be the last child of flip-pack.

/*
 * [DO NOT USE]: flip-pack :nth-child()
 */
flip-pack .candidate:nth-child(odd) {
  background: #fee;
}

/*
 * [BETTER TO USE]: flip-pack {selector}
 */
flip-pack .candidate.odd {
  background: #fee;
}
<flip-pack id="candidate-pack">
  <div class="candidate" value="a">A</div>
  <div class="candidate" value="b">B</div>
  <div class="candidate" value="c">C</div>
  <div class="candidate" value="d">D</div>
</flip-pack>
document
  .getElementById('candidate-pack')
  .querySelectorAll('.candidate')
  .forEach((candidate, candidateIndex) => {
    if (candidateIndex % 2 === 0) {
      candidate.classList.add('odd');
    }
  });

Build

Build flip.js with the command:

npm run build

And get the built file at ./dist/flip.min.js.

Nodes of Flip.js

Use <flip-pack> to wrap those child nodes for flipping:

<flip-pack>
  <div value="a">A</div>
  <div value="b">B</div>
  <div value="c">C</div>
  <div value="d">D</div>
</flip-pack>

Properties

Properties for setting the animation and current status of flip element.

.candidates

Type of value: HTMLElement[]

Returns the candidate elements that we can flip to.

console.log('Candidates:', flip.candidates);

.mode

Type of value: string

Default: 'loop'

Mode of picking the next child element to show:

Name Description
loop Pick the next candidate right after the current one
random Pick candidate randomly
<!-- set mode -->
<flip-pack mode="random">
  <div>A</div>
  <div>B</div>
  <div>C</div>
  <div>D</div>
</flip-pack>
// set mode of picking the next candidate
flip.mode = 'random';
// or
flip.setAttribute('mode', 'random');

// get mode of picking the next candidate
console.log('Mode:', flip.mode);
// or
console.log('Mode:', flip.getAttribute('mode'));

.duration

Type of value: number

Default: 400

Duration of animation flipping per candidate in milliseconds.

<!-- set duration -->
<flip-pack duration="200">
  <div>A</div>
  <div>B</div>
  <div>C</div>
  <div>D</div>
</flip-pack>
// set duration of animation
flip.duration = 200;
// or
flip.setAttribute('duration', '200');

// get duration in number
console.log('Duration:', flip.duration);
// or in string
console.log('Duration:', flip.getAttribute('duration'));

.direction

Type of value: string

Default: 'down'

Direction of flipping candidates:

Name Description
down Flipping down from the top side
up Flipping up from the bottom side
left Flipping left from the right side
right Flipping right from the left side
<!-- set direction -->
<flip-pack direction="left">
  <div>A</div>
  <div>B</div>
  <div>C</div>
  <div>D</div>
</flip-pack>
// set direction
flip.direction = 'left';
// or
flip.setAttribute('direction', 'left');

// get direction
console.log('Direction:', flip.direction);
// or
console.log('Direction:', flip.getAttribute('direction'));

.minFlips/.maxFlips

Type of value: number

Default: 0 for minFlips; Infinity for maxFlips

Minimum or maximum times of flipping candidates on random mode.

<!-- set min/max flips -->
<flip-pack mode="random" min-flips="5" max-flips="8">
  <div>A</div>
  <div>B</div>
  <div>C</div>
  <div>D</div>
</flip-pack>
// set min/max flips
flip.minFlips = 5;
flip.maxFlips = 8;
// or
flip.setAttribute('min-flips', '5');
flip.setAttribute('max-flips', '8');

// get min/max flips in number
console.log('Min flips:', flip.minFlips);
console.log('Max flips:', flip.maxFlips);
// or in string
console.log('Min flips:', flip.getAttribute('minFlips'));
console.log('Max flips:', flip.getAttribute('maxFlips'));

.perspective

Type of value: string

Default: 2 * Math.max({width_of_candidate}, {height_of_candidate})

CSS 3D perspective of flipping animation.

<!-- set perspective -->
<flip-pack perspective="50vmin">
  <div>A</div>
  <div>B</div>
  <div>C</div>
  <div>D</div>
</flip-pack>
// set perspective
flip.perspective = '50vmin';
// or
flip.setAttribute('perspective', '50vmin');

// get perspective
console.log('CSS perspective:', flip.perspective);
// or
console.log('CSS perspective:', flip.getAttribute('perspective'));

.index

Type of value: number

Default: 0 if there is at least 1 candidate. Otherwise -1.

Index of current candidate. Set index to change the current displayed candidate without flipping animation.

⚠️ If we assign both index and value on HTML attributes, we would apply the value of index instead of value.

<!-- initial index -->
<flip-pack index="2">
  <div>A</div>
  <div>B</div>
  <div>C</div>
  <div>D</div>
</flip-pack>
// set index
flip.index = 2;
// or
flip.setAttribute('index', '2');

// get index in number
console.log('Current index:', flip.index);
// or in string
console.log('Current index:', flip.getAttribute('index'));

.value

Type of value: string | null

Value of current candidate. Set value of candidate candidates to change the current displayed candidate without flipping animation.

⚠️ If we assign both index and value on HTML attributes, we would apply the value of index instead of value.

<!-- set value -->
<flip-pack value="c">
  <div value="a">A</div>
  <div value="b">B</div>
  <div value="c">C</div>
  <div value="d">D</div>
</flip-pack>
// set value
flip.value = 'c';
// or
flip.setAttribute('value', 'c');

// get value
console.log('Current value:', flip.value);
// or
console.log('Current value:', flip.getAttribute('value'));

.candidate

Type of value: HTMLElement | null

Current displayed candidate. Set an candidate element to change the current displayed candidate without flipping.

<flip-pack>
  <div value="a">A</div>
  <div value="b">B</div>
  <div value="c">C</div>
  <div value="d">D</div>
</flip-pack>
// set candidate
flip.candidate = flip.querySelector('[value="d"]');

// get candidate
console.log('Current candidate:', flip.candidate);

Methods

Flip methods deal with those related to flip.

Static

Flip.getCandidateValue(candidate)

Argument Type Description
candidate HTMLElement Candidate element

Returns the value of candidate element. The value is the same as the attribute value of value.

<flip-pack>
  <div value="a">A</div>
  <div value="b">B</div>
  <div value="c">C</div>
  <div value="d">D</div>
</flip-pack>
// get candidate value: 'a'
console.log('Value:', Flip.getCandidateValue(flip.firstElementChild()));

.flipAnimation(options)

Applies flipping animation based on options.

Properties of options:

Name Type Description
direction Direction Direction of flipping animation
duration number Duration of flipping per candidate
minFlips number Minimum times of flipping passed candidates
maxFlips number Maximum times of flipping passed candidates
perspective string CSS 3D perspective value for flipping animation
lastCandidateInfo CandidateInfo Object of current candidate info
nextCandidateInfo CandidateInfo Object of target candidate info
tempCandidateNode HTMLElement Temporary element for handling flipping animation

Instance

.getCandidateNode(source)

Returns the candidate element by any of the following types:

Type Description
number Index of candidate
string Value of candidate

.getCandidateIndex(source)

Returns the candidate index by any of the following types:

Type Description
string Value of candidate
HTMLElement Element of candidate

.getCandidateValue(source)

Returns the candidate value by any of the following types:

Type Description
number Index of candidate
HTMLElement Element of candidate

.getCandidateInfo(source)

Returns the object of candidate info by any of the following types:

Type Description
number Index of candidate
string Value of candidate
HTMLElement Element of candidate

Properties of candidate info:

Argument Type Description
index number Index of candidate
value string | null Value of candidate
node HTMLElement | null Element of candidate

.getNextCandidateIndex(options?)

Returns the next candidate index with options:

Name Type Description
mode? Mode Mode of picking candidate

.getNextCandidateNode(options?)

Returns the next candidate element with options. The properties of options are the same as .getNextCandidateIndex.

.getNextCandidateValue(options?)

Returns the next candidate value with options. The properties of options are the same as .getNextCandidateIndex.

.getNextCandidateInfo(options?)

Returns the object of next candidate info with options. The properties of options are the same as .getNextCandidateIndex.

.flip(source?, options?)

Flips to the specific candidate by any of the following types:

Type Description
number Index of candidate
string Value of candidate
HTMLElement Element of candidate

Properties of options extend that of .getNextCandidateIndex:

Name Type Description
direction? Direction Direction of flipping animation
duration? number Duration of flipping per candidate
minFlips? number Minimum times of flipping passed candidates
maxFlips? number Maximum times of flipping passed candidates
perspective? string CSS 3D perspective value for flipping animation
// use await to wait until flipping animation ends
await flip.flip({
  maxFlips: 0,
});

.flip(options?)

Flips to the defaul next candidate with the same options as .flip.

Events

Events for flip elements:

flipstart

Cancelable: true

Would not switch to target candidate if the event is canceled.

Dispatches on starting of switching candidate.

Values of event.detail:

Name Type Description
mode Mode Mode of flipping
direction Direction Direction of flipping animation
duration number Duration of flipping per candidate
minFlips number Minimum times of flipping passed candidates
maxFlips number Maximum times of flipping passed candidates
perspective string CSS 3D perspective value for flipping animation
lastCandidateInfo CandidateInfo Object of current candidate info
targetCandidateInfo CandidateInfo Object of target candidate info

flipend

Cancelable: false

Dispatches on the end of switching candidate.

Properties of event.detail is the same as flipstart.

flipcandidatestart

Cancelable: true

Would not display flipping animation if the event is canceled.

Dispatches on starting of flipping animation.

Properties of event.detail extend that of flipstart:

Name Type Description
tempCandidateNode HTMLElement Temporary element for handleing animation of flipping

flipcandidateend

Cancelable: false

Dispatchse on the end of flipping animation.

Properties of event.detail is the same as flipcandidatestart.

License

Flip.js is MIT licensed.