Install

npm install shufflejs --save

Shuffle is also available on bower as shufflejs.

Example

Filter:

Sort:

Baseball

photography

Tennis

wallpaper, 3d

iMac

wallpaper, 3d

Master Chief

graphics

Shuffle.js is a package for sorting, filtering, and laying out a group of items. It’s performant, responsive, and fast. Check out the demos!

Eightfold

wallpaper, 3d

Pumpkin

photography

Vestride

wallpaper, 3d

Newegg

graphics

Shuffle.js is a package for sorting, filtering, and laying out a group of items. It’s performant, responsive, and fast. Check out the demos!

Arc

wallpaper

Ground

photography

Grass

wallpaper

Vestride

wallpaper, 3d

Features

  • Fast - Only one forced synchronous layout (aka reflow) on init, sort, or filter.
  • Responsive (try resizing the window!)
  • Filter items by groups
  • Items can have multiple groups and be different sizes
  • Sort items
  • Advanced filtering (like searching)

Options

Settings you can change (these are the defaults).

// Overrideable options
Shuffle.options = {
  group: Shuffle.ALL_ITEMS, // Initial filter group.
  speed: 250, // Transition/animation speed (milliseconds).
  easing: 'ease', // CSS easing function to use.
  itemSelector: '*', // e.g. '.picture-item'.
  sizer: null, // Element or selector string. Use an element to determine the size of columns and gutters.
  gutterWidth: 0, // A static number or function that tells the plugin how wide the gutters between columns are (in pixels).
  columnWidth: 0, // A static number or function that returns a number which tells the plugin how wide the columns are (in pixels).
  delimeter: null, // If your group is not json, and is comma delimeted, you could set delimeter to ','.
  buffer: 0, // Useful for percentage based heights when they might not always be exactly the same (in pixels).
  columnThreshold: 0.01, // Reading the width of elements isn't precise enough and can cause columns to jump between values.
  initialSort: null, // Shuffle can be initialized with a sort object. It is the same object given to the sort method.
  throttle: throttle, // By default, shuffle will throttle resize events. This can be changed or removed.
  throttleTime: 300, // How often shuffle can be called on resize (in milliseconds).
  staggerAmount: 15, // Transition delay offset for each item in milliseconds.
  staggerAmountMax: 250, // Maximum stagger delay in milliseconds.
  useTransforms: true, // Whether to use transforms or absolute positioning.
};

No options need to be specified, but itemSelector should be used. Other common options to change are speed and sizer.

Usage

The HTML Structure

The only real important thing here is the data-groups attribute. It has to be a valid JSON array of strings. Optionally, it can be a string delimeted by a value you provide. See delimeter in the options.

This example is using this site's grid. Each item would be 4 columns at the "sm" breakpoint (768px).

Images

To see why the images are wrapped in .aspect elements, check out the images demo.

<div id="grid" class="row my-shuffle-container">
  <figure class="col-4@sm picture-item" data-groups='["photography"]' data-date-created="2010-09-14" data-title="Baseball">
    <div class="aspect aspect--16x9">
      <div class="aspect__inner">
        <img src="/img/baseball.png" alt="" height="145" width="230">
      </div>
    </div>
    <figcaption>Baseball</figcaption>
  </figure>
  <figure class="col-4@sm picture-item" data-groups='["wallpaper","3d"]' data-date-created="2011-08-14" data-title="Tennis">
    <div class="aspect aspect--16x9">
      <div class="aspect__inner">
        <img src="/img/tennis-ball.png" alt="" height="145" width="230">
      </div>
    </div>
    <figcaption>Tennis</figcaption>
  </figure>
  <figure class="col-4@sm picture-item" data-groups='["wallpaper","3d"]' data-date-created="2009-05-27" data-title="iMac">
    <div class="aspect aspect--16x9">
      <div class="aspect__inner">
        <img src="/img/imac.png" alt="" height="145" width="230">
      </div>
    </div>
    <figcaption>iMac</figcaption>
  </figure>
  <div class="col-1@sm my-sizer-element"></div>
</div>

How column widths work

There are 4 options for defining the width of the columns:

  1. Use a sizer element. This is the easiest way to specify column and gutter widths. Add the sizer element and make it 1 column wide. Shuffle will measure the width and margin-left of this sizer element each time the grid resizes. This is awesome for responsive or fluid grids where the width of a column is a percentage.
  2. Use a function. When a function is used, its first parameter will be the width of the shuffle element. You need to return the column width for shuffle to use (in pixels).
  3. A number. This will explicitly set the column width to your number (in pixels).
  4. By default, shuffle will use the width of the first item to calculate the column width.

A basic setup example

If you want functional buttons, check out the js file.

Shuffle uses a UMD definition so that you can use it with globals, AMD, or CommonJS.

var Shuffle = window.shuffle;
var element = document.getElementById('grid');
var sizer = element.querySelector('.my-sizer-element');

var shuffle = new Shuffle(element, {
  itemSelector: '.picture-item',
  sizer: sizer // could also be a selector: '.my-sizer-element'
});

Events

Shuffle emits an event when a layout happens and when elements are removed. The event names are Shuffle.EventType.LAYOUT and Shuffle.EventType.REMOVED.

Shuffle uses the global CustomEvent to create events. A polyfill for IE<=11 is bundled with Shuffle.

Get notified when a layout happens

element.addEventListener(Shuffle.EventType.LAYOUT, function () {
  console.log('Things finished moving!');
});

Do something when an item is removed

element.addEventListener(Shuffle.EventType.REMOVED, function (evt) {
  var detail = evt.detail;
  console.log(this, evt, detail.collection, detail.shuffle);
});

Sorting

You can order the elements with a function you supply. In the demo above, each item has a data-date-created and data-title attribute. When the select option menu changes, a sort object is passed to shuffle.

<figure class="picture-item" data-groups='["photography"]' data-date-created="2010-09-14" data-title="Baseball">…</figure>
<select class="sort-options">
  <option value="">Default</option>
  <option value="title">Title</option>
  <option value="date-created">Date Created</option>
</select>
Demo.prototype.addSorting = function () {
  document.querySelector('.sort-options').addEventListener('change', this._handleSortChange.bind(this));
};

Demo.prototype._handleSortChange = function (evt) {
  var value = evt.target.value;
  var options = {};

  function sortByDate(element) {
    return element.getAttribute('data-created');
  }

  function sortByTitle(element) {
    return element.getAttribute('data-title').toLowerCase();
  }

  if (value === 'date-created') {
    options = {
      reverse: true,
      by: sortByDate,
    };
  } else if (value === 'title') {
    options = {
      by: sortByTitle,
    };
  }

  this.shuffle.sort(options);
};

The options object can contain three properties:

  • reverse: a boolean which will reverse the resulting order.
  • by: a function with an element as the parameter. Above, we’re returning the value of the data-date-created or data-title attribute.
  • randomize: Make the order random.

Returning undefined from the by function will reset the order to DOM order.

Calling sort with an empty object will reset the elements to DOM order.

Advanced Filtering

By passing a function to filter, you can fully customize filtering items. Shuffle will iterate over each item and give your function the element and the shuffle instance. Return true to keep the element or false to hide it.

Example

// Filters elements with a data-title attribute with less than 10 characters
instance.filter(function (element) {
  return element.getAttribute('data-title').length < 10;
});

Searching

// Advanced filtering
Demo.prototype.addSearchFilter = function () {
  document.querySelector('.js-shuffle-search').addEventListener('keyup', this._handleSearchKeyup.bind(this));
};

// Filter the shuffle instance by items with a title that matches the search input.
Demo.prototype._handleSearchKeyup = function (evt) {
  var searchText = evt.target.value.toLowerCase();

  this.shuffle.filter(function (element, shuffle) {
    var titleElement = element.querySelector('.picture-item__title');
    var titleText = titleElement.textContent.toLowerCase().trim();

    return titleText.indexOf(searchText) !== -1;
  });
};

Adding and removing items

You can add and remove elements from shuffle after it has been created. This also works for infinite scrolling.

Adding elements

Wherever you add the element in the DOM is where it will show up in the grid (assuming you’re using the default sort-by-dom-order). With this in mind, you can append, prepend, or insert elements wherever you need to get them to show up in the right order.

/**
 * Create some DOM elements, append them to the shuffle container, then notify
 * shuffle about the new items. You could also insert the HTML as a string.
 */
Demo.prototype.onAppendBoxes = function () {
  var items = this._getArrayOfElementsToAdd();

  items.forEach(function (item) {
    this.shuffle.element.appendChild(item);
  }, this);

  // Tell shuffle items have been appended.
  // It expects an array of elements as the parameter.
  this.shuffle.add(items);
};

Removing elements

Shuffle will animate the element away and then remove it from the DOM once it's finished. It will then emit the Shuffle.EventType.REMOVED custom event with the array of elements in event.detail.collection.

this.shuffle.remove([element1, element2]);

Public Methods

A list of the methods available to you and what they do.

  • filter(category, sortObject) - Filters all the shuffle items and then sorts them. category can be a string, array of strings, or a function. The sort object is optional and will use the last-used sort object.
  • sort(sortObject) - Sorts the currently filtered shuffle items.
  • update() - Repositions everything. Useful for when dimensions (like the window size) change.
  • layout() - Use this instead of update() if you don't need the columns and gutters updated. Maybe an image loaded and now has a height.
  • add(newItems) - New items have been appended to the shuffle container. newItems is an array of elements.
  • disable() - Disables Shuffle from updating dimensions and layout on resize.
  • enable() - Enables Shuffle again.
  • remove() - Remove one or more shuffle items.
  • getItemByElement(element) - Retrieve a ShuffleItem by its element.
  • destroy() - Destroys Shuffle, removes events, styles, classes, and references.

Customizing Styles

You can customize the default styles which are applied to Shuffle items upon initialization, before layout, after layout, before hiding, and after hidden.

Here are the defaults:

ShuffleItem.Css = {
  INITIAL: {
    position: 'absolute',
    top: 0,
    left: 0,
    visibility: 'visible',
    'will-change': 'transform',
  },
  VISIBLE: {
    before: {
      opacity: 1,
      visibility: 'visible',
    },
    after: {},
  },
  HIDDEN: {
    before: {
      opacity: 0,
    },
    after: {
      visibility: 'hidden',
    },
  },
};

ShuffleItem.Scale = {
  VISIBLE: 1,
  HIDDEN: 0.001,
};

If you wanted to add a 50% red background to every item when they initialize, you could do this:

Shuffle.ShuffleItem.Css.INITIAL.backgroundColor = 'rgba(255, 0, 0, 0.5)';

To set the text color to teal after the item has finished moving:

Shuffle.ShuffleItem.Css.VISIBLE.after.color = 'teal';

You can also customize the scaling effect with visible or hidden items, however, the VISIBLE and HIDDEN values cannot be the exact same.

Shuffle.ShuffleItem.Scale.HIDDEN = 0.5;

Extra Features

Shuffle likely will not grow much farther than the current feature set. If you need something with drag and drop, filling in gaps, more layout modes, etc., I suggest looking into packery or isotope.

Dependencies

Shuffle's dependencies are bundled with the dist file.

Supported Browsers

  • Chrome
  • Firefox
  • Edge
  • IE 11
  • Safari

Support for other browsers may be added with polyfills for ES5 features. If you require broader browser support, use the most recent v3 release of Shuffle.

Be Social

Changes

  • v4.0.2 9/15/16 - Update custom-event-polyfill dependency.
  • v4.0.1 7/30/16 - Fix delimeter option.
  • v4.0.0 4/20/16 - Rewrite in ES6 with babel. Remove jQuery and Modernizr dependencies. Remove support for IE<11. Docs improvements. Switch to gulp build system with webpack.
  • v3.1.0 3/23/15 - Allow zero speed option (#64) and cancel previous animations instead of ignoring new ones (#69). Handle non-integer columns better (#46)
  • v3.0.4 2/16/15 - Publish to NPM.
  • v3.0.2 1/21/15 - Remove from jQuery plugins directory.
  • v3.0.1 12/29/14 - Add CommonJS support.
  • v3.0.0 10/6/14 - Refactored with improvements, added unit tests, more documentation. Removed some triggered events.
  • v2.1.2 6/1/14 - Use window.jQuery instead of window.$ to work better with noConflict. Fixed #25.
  • v2.1.1 4/16/14 - Fix items with zero opacity overlapping visible ones in IE<10.
  • v2.1.0 4/12/14 - Register with bower as shufflejs.
  • 4/10/14 - Add AMD support.
  • 4/8/14 - Separate Modernizr into its own file and custom Shuffle build.
  • 3/8/14 - Add Bootstrap 3 demo. Fixed issue with percentage width items.
  • 10/4/13 - Moved some Shuffle instance properties to constants. Converted from 4 to 2 space indentation. Added events enum and pulled out some strings to constants.
  • 8/30/13 - Added animate-in demo.
  • v2.0.0 7/5/13 - Shuffle 2.0 with masonry, adding and removing, and more.
  • 11/3/12 - Replaced layout system with masonry. Items can now be different sizes! Added addtional examples.
  • 10/24/12 - Better handling of grid item dimensions. Added a minimal markup page.
  • 9/20/12 - Added destroy method
  • 9/18/12 - Added sorting ability and made plugin responsive. Updated to Modernizr 2.6.2
  • 7/21/12 - Rewrote plugin in more object oriented structure. Added custom events. Updated to Modernizr 2.6.1
  • 7/3/12 - Removed dependency on the css file and now apply the css with javascript