Pinterest-Like Dynamic Grid Layout In JavaScript - Wookmark

File Size: 1.03 MB
Views Total: 36306
Last Update:
Publish Date:
Official Website: Go to website
License: MIT
Pinterest-Like Dynamic Grid Layout In JavaScript - Wookmark

Wookmark is a jQuery & Vanilla JavaScript Plugin that lays out a series of elements in a dynamic, filterable, multi-column grid layout just as you've seen on Also known as Masonry Layout.

You might also like:

More Examples:


  • Responsive design.
  • Auto-update the layout when the browser window is resized.
  • Endless-scroll support.
  • Grid filter support.
  • Also works as a Vanilla JavaScript (Wookmark 2.0+).
  • Compatible with the imageLoaded library.


$ npm install wookmark --save

How to use it:

1. Include jQuery Library (OPTIONAL) and the wookmark.js library in your website:

<!-- OPTIONAL -->
<script src="/path/to/cdn/jquery.min.js">
<!-- OPTIONAL -->
<script src="/path/to/cdn/imagesloaded.min.js">
<!-- Minified Version -->
<script src="wookmark.min.js"></script>
<!-- Or From A CDN -->
<script src=""></script>
<!-- Or -->
<script src=""></script>

2. Add a list of grid items to the layout.

<ul id="wookmark-example" class="tiles-wrap">
    <img src="1.jpg" alt="Image Alt">
    <p>Image Description</p>
    <img src="2.jpg" alt="Image Alt">
    <p>Image Description</p>
    <img src="3.jpg" alt="Image Alt">
    <p>Image Description</p>
    <img src="4.jpg" alt="Image Alt">
    <p>Image Description</p>
    <img src="5.jpg" alt="Image Alt">
    <p>Image Description</p>

3. Initialize the Wookmark plugin by calling the function on the HTML list.

// As A Vanilla JavaScript Plugin
window.onload = function () {
  var myWookmark = new Wookmark('#wookmark-example', {
      // options here

// As A jQuery Plugin
    // options here

4. The example CSS for the layout & grid items.

 * Grid container
.tiles-wrap {
  position: relative; /** Needed to ensure items are laid out relative to this container **/
  margin: 10px 0;
  padding: 0;
  list-style-type: none;
  display: none;

 * Grid items
.tiles-wrap li {
  display: block;
  opacity: 0;
  text-align: center;
  list-style-type: none;
  background-color: #fff;
  float: left;
  cursor: pointer;
  width: 200px;
  padding: 4px;
  border: 1px solid #dedede;
  -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
     -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
          box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
  -webkit-border-radius: 2px;
     -moz-border-radius: 2px;
          border-radius: 2px;
.tiles-wrap.wookmark-initialised.animated li {
  -webkit-transition: all 0.3s ease-out;
     -moz-transition: all 0.3s ease-out;
       -o-transition: all 0.3s ease-out;
          transition: all 0.3s ease-out;

.tiles-wrap.wookmark-initialised li {
  opacity: 1;

.tiles-wrap li.wookmark-inactive {
  visibility: hidden;
  opacity: 0;

.tiles-wrap li:hover {
  background-color: #fafafa;

.tiles-wrap img {
  display: block;

.tiles-wrap a {
  color: #555;
  text-align: center;
  /* display: table-cell; */
  width: 200px;
  height: 200px;
  font-size: 2em;
  font-weight: bold;
  text-decoration: none;

.tile-loading:after {
  display: block;
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  background-color: #ddd;
  content: "Loading\2026";
  padding-top: 20px;
  color: #999;

5. To create a filterable grid layout, you need to categorize your grid items using the data-filter-class attribute and then create filter controls in the document like these:

<ol id="filters">
  <li data-filter="cat1">Category 1</li>
  <li data-filter="cat2">Category 2</li>
  <li data-filter="cat3">Category 3</li>

<ul id="wookmark-example" class="tiles-wrap">
  <li data-filter-class='["cat1", "cat2"]'>
    <img src="1.jpg" alt="Image Alt">
    <p>Image Description</p>
  <lidata-filter-class='["cat2", "cat3"]'>
    <img src="2.jpg" alt="Image Alt">
    <p>Image Description</p>
  <lidata-filter-class='["cat1", "cat3"]'>
    <img src="3.jpg" alt="Image Alt">
    <p>Image Description</p>
    <img src="4.jpg" alt="Image Alt">
    <p>Image Description</p>
  <li data-filter-class='["cat2"]'>
    <img src="5.jpg" alt="Image Alt">
    <p>Image Description</p>
wookmark = new Wookmark('#container', {
  fillEmptySpace: true // Optional, fill the bottom of each column with widths of flexible height

// Setup filter buttons when jQuery is available
var $filters = $('#filters li');

 * When a filter is clicked, toggle it's active state and refresh.
function onClickFilter(e) {
  var $item = $(e.currentTarget),
      activeFilters = [],
      filterType = $'filter');
  if (filterType === 'all') {
  } else {
    // Collect active filter strings
    $filters.filter('.active').each(function() {
  wookmark.filter(activeFilters, 'and');

// Capture filter click events.
$('#filters').on('click.wookmark-filter', 'li', onClickFilter);

6. Plugin's default options to customize the grid layout.

  // Calculate the offset based on the alignment of columns to the parent container
  // 'center', 'left', or 'right'
  align: 'center',

  // Listen to resize event of the browser if enabled
  autoResize: true,

  // Provide a custom comparator function which the plugin will use to sort the tiles
  comparator: null,

  // Set the direction for positioning
  direction: undefined,

  // Ignore inactive grid items
  // When set to false inactive items will still be shown when filtered
  ignoreInactiveItems: true,

  // Inactive CSS class
  inactiveClass: 'wookmark-inactive',

  // Item selector
  itemSelector: undefined,

  // You can also provide a function which should return either a number or a percentage string
  itemWidth: 0,
  flexibleWidth: 0,

  // Create placeholders at the bottom of each column to create an even layout
  fillEmptySpace: false,
  // Offset in pixels
  offset: 5,
  outerOffset: 0,
  verticalOffset: undefined

  // Callback
  onLayoutChanged: undefined,

  // Placeholder CSS class
  placeholderClass: 'wookmark-placeholder',

  // Possible filters
  possibleFilters: [],

  // Resize delay in ms
  resizeDelay: 50

7. More API methods.

/* refreshe the grid layout
   useful for infinite scroll
document.getElementById('wookmark-example').dispatchEvent(new Event('refreshWookmark'));

/* Resize the grid layout
window.dispatchEvent(new Event('resize'));


v2.2.0 (2019-11-25)

  • FIX: Mainly a release to make npm load the latest version including changes from 2.1.3
  • FIX: Add docco as dependency to make grunt build task work properly
  • CHG: Updated some dependencies and removed bower

v2.1.2 (2017-01-11)

  • FIX: Resize and refresh events were not triggered correctly
  • Use own $ variable, make sure Jquery can be loaded

v2.1.1 (2016-04-15)

  • FIX: Layout on hidden containers couldn't be forced
  • FIX: Items were not rendered when ignoreActiveItems was set

v2.1.0 (2016-03-10)

  • FIX: Simple example didn't work properly
  • FIX: Reduce flickering on loading
  • FIX: Only enable transition after wookmark has initialized
  • FIX: Defined dev only scripts in package.json
  • FIX: layout call didn't trigger item height recomputation
  • ADD: Add initialised state after first layout
  • CHG: Updated readme

v2.0.1 (2015-06-16)

  • bugfix.

v2.0.0 (2015-02-16)

  • Rewrite of plugin to work without jQuery
  • New initialization code (see the readme)
  • jQuery and imagesloaded plugins are now installed with bower
  • Source is now lint-free and much more optimized for speed
  • Ignoring most files when installing with bower
  • itemWidth and flexibleWidth can now be functions returning a number or percentage

v1.4.8 (2014-07-09)

  • FIX: In jquery amd dependency. Patch by Guido Contreras Woda. Thanks!
  • ADD: badge. Will check out if it's cool to manage issues there.
  • CHG: Using MagnificPopup instead of Colorbox in examples. Works better with endless scroll and filtering.

v1.4.7 (2014-05-19)

  • ADD: example-api now has an additional example for a custom php based server app
  • FIX: Example amd was missing required shim so imagesLoaded plugin attaches itself to jQuery
  • ADD: "Mentioned or used by others" section to readme
  • ADD: dryRun feature for filtering and the filter call will return the list resulting list of items as jQuery object
  • CHG: Small optimization for window object
  • CHG: Starting opacity for list items in examples is now 1 so opacity animations have a starting point

v1.4.6 (2014-01-14)

  • New option 'verticalOffset'. Old option 'offset' still defines the horizontal offset between tiles.
  • Added 'Reset filters' button to filter examples.
  • 'flexibleWidth' will now be handled a bit differently. When set the plugin will try to fit as many columns into the container as possible. itemWidth is then the minimum width of those columns.

v1.4.5 (2013-11-22)

  • Fix for placeholders in non-chrome browsers.
  • The clear method of the wookmark instance will remove the instance itself.
  • New introduction page with links to examples. Will work on that further on the way to 1.5.0.
  • Fixed bug in example-amd with requirejs.
  • CSS changes will be executed as bulk with requestAnimationFrame when available.
  • Added progressbar to imagesloaded example.
  • Filterclasses can be updated via the wookmarkInstance of the handler.

v1.4.4 (2013-10-17)

  • Wookmark layouting won't break when container isn't visible at the start. But you should call 'refreshWookmark' after making it visible.
  • Added 'possibleFilters' option. With this you can have filter even when no items fit. Patch by Aakash Goel.
  • Fix when filtering and no items match. Patch by Gabriel Kaam. 

v1.4.2 (2013-08-12)

  • 'flexibleWidth' now works as expected when it's greater than 50% or more than half of the containers width in pixels.

v1.4.0 (2013-08-02)

  • Added sort example. 
  • Fixed column counter.
  • Fixed offset when alignment is used.

This awesome jQuery plugin is developed by germanysbestkeptsecr. For more Advanced Usages, please check the demo page or visit the official website.