Muuri is a JavaScript layout engine that allows you to build all kinds of layouts and make them responsive, sortable, filterable, draggable and/or animated. Comparing to what's out there Muuri is a combination of Packery, Masonry, Isotope and Sortable. Wanna see it in action? Check out the demo on the website.
Muuri's default "First Fit" bin packing layout algorithm generates layouts similar to Packery and Masonry. The implementation is heavily based on the "maxrects" approach as described by Jukka Jylänki in his research A Thousand Ways to Pack the Bin. If that's not your cup of tea you can always provide your own layout algorithm to position the items as you wish.
Muuri uses Web Animations for animations and has an internal mechanism to handle dragging. And if you're wondering about the name of the library "muuri" is Finnish meaning a wall.
Features
- Fully customizable layout
- Drag & drop (even between grids)
- Nested grids
- Fast animations
- Filtering
- Sorting
Install via npm:
npm install muuri
Or download:
- muuri.js - for development (not minified, with comments).
- muuri.min.js - for production (minified, no comments).
Or link directly:
<script src="https://unpkg.com/[email protected]/dist/muuri.min.js"></script>
Muuri uses Web Animations to handle all the animations by default. If you need to use Muuri on a browser that does not support Web Animations you need to use a polyfill.
npm install web-animations-js
Add Muuri on your site and make sure to include the Web Animations Polyfill before Muuri (if needed).
<script src="https://unpkg.com/[email protected]/web-animations.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/muuri.min.js"></script>
- Every grid must have a container element.
- Grid items must always consist of at least two elements. The outer element is used for positioning the item and the inner element (first direct child) is used for animating the item's visibility (show/hide methods). You can insert any markup you wish inside the inner item element.
<div class="grid">
<div class="item">
<div class="item-content">
<!-- Safe zone, enter your custom markup -->
This can be anything.
<!-- Safe zone ends -->
</div>
</div>
<div class="item">
<div class="item-content">
<!-- Safe zone, enter your custom markup -->
<div class="my-custom-content">
Yippee!
</div>
<!-- Safe zone ends -->
</div>
</div>
</div>
- The container element must be "positioned" meaning that it's CSS position property must be set to relative, absolute or fixed. Also note that Muuri automatically resizes the container element's width/height depending on the area the items cover and the layout algorithm configuration.
- The item elements must have their CSS position set to absolute and their display property set to block. Muuri actually enforces the
display:block;
rule and adds it as an inline style to all item elements, just in case. - The item elements must not have any CSS transitions or animations applied to them, because they might conflict with Muuri's internal animation engine. However, the container element can have transitions applied to it if you want it to animate when it's size changes after the layout operation.
- You can control the gaps between the items by giving some margin to the item elements.
- One last thing: never ever set
overflow: auto;
oroverflow: scroll;
to the container element. Muuri's calculation logic does not account for that and you will see some item jumps when dragging starts. Always use a wrapper element for the container where you set theauto
/scroll
overflow values.
.grid {
position: relative;
}
.item {
display: block;
position: absolute;
width: 100px;
height: 100px;
margin: 5px;
z-index: 1;
background: #000;
color: #fff;
}
.item.muuri-item-dragging {
z-index: 3;
}
.item.muuri-item-releasing {
z-index: 2;
}
.item.muuri-item-hidden {
z-index: 0;
}
.item-content {
position: relative;
width: 100%;
height: 100%;
}
The bare minimum configuration is demonstrated below. You must always provide the container element (or a selector so Muuri can fetch the element for you), everything else is optional.
var grid = new Muuri('.grid');
You can view this little tutorial demo here. After that you might want to check some other demos as well.
Muuri
is a constructor function and should be always instantiated with the new
keyword. For the sake of clarity, we refer to a Muuri instance as grid throughout the documentation.
Syntax
Muuri( element, [options] )
Parameters
- element — element / string
- Default value:
null
. - You can provide the element directly or use a selector (string) which uses querySelector() internally.
- Default value:
- options — object
- Optional. Check out the detailed options reference.
Default options
The default options are stored in Muuri.defaultOptions
object, which in it's default state contains the following configuration:
{
// Item elements
items: '*',
// Default show animation
showDuration: 300,
showEasing: 'ease',
// Default hide animation
hideDuration: 300,
hideEasing: 'ease',
// Item's visible/hidden state styles
visibleStyles: {
opacity: '1',
transform: 'scale(1)'
},
hiddenStyles: {
opacity: '0',
transform: 'scale(0.5)'
},
// Layout
layout: {
fillGaps: false,
horizontal: false,
alignRight: false,
alignBottom: false,
rounding: true
},
layoutOnResize: 100,
layoutOnInit: true,
layoutDuration: 300,
layoutEasing: 'ease',
// Sorting
sortData: null,
// Drag & Drop
dragEnabled: false,
dragContainer: null,
dragStartPredicate: {
distance: 0,
delay: 0,
handle: false
},
dragAxis: null,
dragSort: true,
dragSortHeuristics: {
sortInterval: 100,
minDragDistance: 10,
minBounceBackAngle: 1
},
dragSortPredicate: {
threshold: 50,
action: actionMove
},
dragReleaseDuration: 300,
dragReleaseEasing: 'ease',
dragCssProps: {
touchAction: 'none',
userSelect: 'none',
userDrag: 'none',
tapHighlightColor: 'rgba(0, 0, 0, 0)',
touchCallout: 'none',
contentZooming: 'none'
},
dragPlaceholder: {
enabled: false,
duration: 300,
easing: 'ease',
createElement: null,
onCreate: null,
onRemove: null
},
// Classnames
containerClass: 'muuri',
itemClass: 'muuri-item',
itemVisibleClass: 'muuri-item-shown',
itemHiddenClass: 'muuri-item-hidden',
itemPositioningClass: 'muuri-item-positioning',
itemDraggingClass: 'muuri-item-dragging',
itemReleasingClass: 'muuri-item-releasing',
itemPlaceholderClass: 'muuri-item-placeholder'
}
You can modify the default options easily:
Muuri.defaultOptions.showDuration = 400;
Muuri.defaultOptions.dragSortPredicate.action = 'swap';
This is how you would use the options:
// Minimum configuration.
var gridA = new Muuri('.grid-a');
// Providing some options.
var gridB = new Muuri('.grid-b', {
items: '.item'
});
- items
- showDuration
- showEasing
- hideDuration
- hideEasing
- visibleStyles
- hiddenStyles
- layout
- layoutOnResize
- layoutOnInit
- layoutDuration
- layoutEasing
- sortData
- dragEnabled
- dragContainer
- dragStartPredicate
- dragAxis
- dragSort
- dragSortHeuristics
- dragSortPredicate
- dragReleaseDuration
- dragReleaseEasing
- dragCssProps
- dragPlaceholder
- containerClass
- itemClass
- itemVisibleClass
- itemHiddenClass
- itemPositioningClass
- itemDraggingClass
- itemReleasingClass
- itemPlaceholderClass
The initial item elements, which should be children of the container element. All elements that are not children of the container will be appended to the container. You can provide an array of elements, a node list or a selector (string). If you provide a selector Muuri uses it to filter the current child elements of the container element and sets them as initial items. By default all current child elements of the provided container element are used as initial items.
- Default value:
'*'
. - Accepted types: array (of elements), node list, string, null.
// Use specific items.
var grid = new Muuri(elem, {
items: [elemA, elemB, elemC]
});
// Use node list.
var grid = new Muuri(elem, {
items: elem.querySelectorAll('.item')
});
// Use selector.
var grid = new Muuri(elem, {
items: '.item'
});
Show animation duration in milliseconds. Set to 0
to disable show animation.
- Default value:
300
. - Accepted types: number.
var grid = new Muuri(elem, {
showDuration: 600
});
Show animation easing. Accepts any valid Animation easing value.
- Default value:
'ease'
. - Accepted types: string.
var grid = new Muuri(elem, {
showEasing: 'cubic-bezier(0.215, 0.61, 0.355, 1)'
});
Hide animation duration in milliseconds. Set to 0
to disable hide animation.
- Default value:
300
. - Accepted types: number.
var grid = new Muuri(elem, {
hideDuration: 600
});
Hide animation easing. Accepts any valid Animation easing value.
- Default value:
'ease'
. - Accepted types: string.
var grid = new Muuri(elem, {
hideEasing: 'cubic-bezier(0.215, 0.61, 0.355, 1)'
});
The styles that will be applied to all visible items. These styles are also used for the show/hide animations which means that you have to have the same style properties in visibleStyles and hiddenStyles options. Be sure to define all style properties camel cased.
- Default value:
{opacity: 1, transform: 'scale(1)'}
. - Accepted types: object.
var grid = new Muuri(elem, {
visibleStyles: {
opacity: 1,
transform: 'rotate(45deg)'
},
hiddenStyles: {
opacity: 0,
transform: 'rotate(-45deg)'
}
});
hiddenStyles
The styles that will be applied to all hidden items. These styles are also used for the show/hide animations which means that you have to have the same style properties in visibleStyles and hiddenStyles options. Be sure to define all style properties camel cased.
- Default value:
{opacity: 0, transform: 'scale(0.5)'}
. - Accepted types: object.
var grid = new Muuri(elem, {
visibleStyles: {
opacity: 1,
transform: 'rotate(45deg)'
},
hiddenStyles: {
opacity: 0,
transform: 'rotate(-45deg)'
}
});
Define how the items will be laid out. Muuri ships with a configurable layout algorithm which is used by default. It's pretty flexible and suitable for most common situations (lists, grids and even bin packed grids). If that does not fit the bill you can always provide your own layout algorithm (it's not as scary as it sounds).
- Default value:
{fillGaps: false, horizontal: false, alignRight: false, alignBottom: false}
. - Accepted types: function, object.
Provide an object to configure the default layout algorithm with the following properties
- fillGaps — boolean
- Default value:
false
. - When
true
the algorithm goes through every item in order and places each item to the first available free slot, even if the slot happens to be visually before the previous element's slot. Practically this means that the items might not end up visually in order, but there will be less gaps in the grid. By default this option isfalse
which basically means that the following condition will be always true when calculating the layout (assumingalignRight
andalignBottom
arefalse
):nextItem.top > prevItem.top || (nextItem.top === prevItem.top && nextItem.left > prevItem.left)
. This also means that the items will be visually in order.
- Default value:
- horizontal — boolean
- Default value:
false
. - When
true
the grid works in landscape mode (grid expands to the right). Use for horizontally scrolling sites. Whenfalse
the grid works in "portrait" mode and expands downwards.
- Default value:
- alignRight — boolean
- Default value:
false
. - When
true
the items are aligned from right to left.
- Default value:
- alignBottom — boolean
- Default value:
false
. - When
true
the items are aligned from the bottom up.
- Default value:
- rounding — boolean
- Default value:
true
. - When
true
the dimensions of the items will be automatically rounded for the layout calculations usingMath.round()
. Set tofalse
to use accurate dimensions. In practice you would want disable this if you are using relative dimension values for items (%, em, rem, etc.). If you have defined item dimensions with pixel values (px) it is recommended that you leave this on.
- Default value:
// Customize the default layout algorithm.
var grid = new Muuri(elem, {
layout: {
fillGaps: true,
horizontal: true,
alignRight: true,
alignBottom: true,
rounding: false
}
});
Provide a function to use a custom layout algorithm
When you provide a custom layout function Muuri calls it whenever calculation of layout is necessary. Before calling the layout function Muuri always calculates the current width and height of the grid's container element and also creates an array of all the items that are part of the layout currently (all active items).
customLayout( items, gridWidth, gridHeight )
- items — array
- Array of
Muuri.Item
instances.
- Array of
- gridWidth — number
- Current width of the grid's container element.
- gridHeight — number
- Current height of the grid's container element.
- items — array
The layout function's job is using this data, which is provided to the layout function as arguments (as detailed above), and calculating position for each item in the array.
The layout function should always return an object with following properties:
- slots — array
- Array of the item positions (numbers). E.g. if the items were
[a, b]
this should be[aLeft, aTop, bLeft, bTop]
. You have to calculate theleft
andtop
position for each item in the provided items array in the same order the items are provided.
- Array of the item positions (numbers). E.g. if the items were
- width — number
- The width of the grid.
- height — number
- The height of the grid.
- setWidth — boolean
- Should Muuri set the provided width as the grid element's width?
- setHeight — boolean
- Should Muuri set the provided height as the grid element's height?
// Build your own layout algorithm.
var grid = new Muuri(elem, {
layout: function (items, gridWidth, gridHeight) {
// The layout data object. Muuri will read this data and position the items
// based on it.
var layout = {
// The layout's item slots (left/top coordinates).
slots: [],
// The layout's total width.
width: 0,
// The layout's total height.
height: 0,
// Should Muuri set the grid's width after layout?
setWidth: true,
// Should Muuri set the grid's height after layout?
setHeight: true
};
// Calculate the slots.
var item;
var m;
var x = 0;
var y = 0;
var w = 0;
var h = 0;
for (var i = 0; i < items.length; i++) {
item = items[i];
x += w;
y += h;
m = item.getMargin();
w = item.getWidth() + m.left + m.right;
h = item.getHeight() + m.top + m.bottom;
layout.slots.push(x, y);
}
// Calculate the layout's total width and height.
layout.width = x + w;
layout.height = y + h;
return layout;
}
});
Should Muuri automatically trigger layout
method on window resize? Set to false
to disable. When a number or true
is provided Muuri will automatically lay out the items every time window is resized. The provided number (true
is transformed to 0
) equals to the amount of time (in milliseconds) that is waited before items are laid out after each window resize event.
- Default value:
100
. - Accepted types: boolean, number.
// No layout on resize.
var grid = new Muuri(elem, {
layoutOnResize: false
});
// Layout on resize (instantly).
var grid = new Muuri(elem, {
layoutOnResize: true
});
// Layout on resize (with 200ms debounce).
var grid = new Muuri(elem, {
layoutOnResize: 200
});
Should Muuri trigger layout
method automatically on init?
- Default value:
true
. - Accepted types: boolean.
var grid = new Muuri(elem, {
layoutOnInit: false
});
The duration for item's layout animation in milliseconds. Set to 0
to disable.
- Default value:
300
. - Accepted types: number.
var grid = new Muuri(elem, {
layoutDuration: 600
});
The easing for item's layout animation. Accepts any valid Animation easing value.
- Default value:
'ease'
. - Accepted types: string.
var grid = new Muuri(elem, {
layoutEasing: 'cubic-bezier(0.215, 0.61, 0.355, 1)'
});
The sort data getter functions. Provide an object where the key is the name of the sortable attribute and the function returns a value (from the item) by which the items can be sorted.
- Default value:
null
. - Accepted types: object, null.
var grid = new Muuri(elem, {
sortData: {
foo: function (item, element) {
return parseFloat(element.getAttribute('data-foo'));
},
bar: function (item, element) {
return element.getAttribute('data-bar').toUpperCase();
}
}
});
// Refresh sort data whenever an item's data-foo or data-bar changes
grid.refreshSortData();
// Sort the grid by foo and bar.
grid.sort('foo bar');
Should items be draggable?
- Default value:
false
. - Accepted types: boolean.
var grid = new Muuri(elem, {
dragEnabled: true
});
The element the dragged item should be appended to for the duration of the drag. If set to null
(which is also the default value) the grid's container element will be used.
- Default value:
null
. - Accepted types: element, null.
var grid = new Muuri(elem, {
dragContainer: document.body
});
A function that determines when the item should start to move when the item is being dragged. By default uses the built-in predicate which has some configurable options.
- Default value:
{distance: 0, delay: 0, handle: false}
. - Accepted types: function, object.
If an object is provided the default sort predicate handler will be used. You can define the following properties:
- distance — number
- Default value:
0
. - How many pixels must be dragged before the dragging starts.
- Default value:
- delay — number
- Default value:
0
. - How long (in milliseconds) the user must drag before the dragging starts.
- Default value:
- handle — string / boolean
- Default value:
false
. - The selector(s) which much match the event target element for the dragging to start. Note that if the event target element is a descendant of the handle element(s) it is also considered a match, which should be pretty useful in most scenarios.
- Default value:
If you provide a function you can totally customize the drag start logic. When the user starts to drag an item this predicate function will be called until you return true
or false
. If you return true
the item will begin to move whenever the item is dragged. If you return false
the item will not be moved at all. Note that after you have returned true
or false
this function will not be called until the item is released and dragged again.
The predicate function receives two arguments:
- item — Muuri.Item
- The item that's being dragged.
- event — object
- The drag event (Muuri.Dragger event).
// Configure the default predicate
var grid = new Muuri(elem, {
dragStartPredicate: {
distance: 10,
delay: 100,
handle: '.foo, .bar'
}
});
// Provide your own predicate
var grid = new Muuri(elem, {
dragStartPredicate: function (item, e) {
// Start moving the item after the item has been dragged for one second.
if (e.deltaTime > 1000) {
return true;
}
}
});
// Pro tip: provide your own predicate and fall back to the default predicate.
var grid = new Muuri(elem, {
dragStartPredicate: function (item, e) {
// If this is final event in the drag process, let's prepare the predicate
// for the next round (do some resetting/teardown). The default predicate
// always needs to be called during the final event if there's a chance it
// has been triggered during the drag process because it does some necessary
// state resetting.
if (e.isFinal) {
Muuri.ItemDrag.defaultStartPredicate(item, e);
return;
}
// Prevent first item from being dragged.
if (grid.getItems().indexOf(item) === 0) {
return false;
}
// For other items use the default drag start predicate.
return Muuri.ItemDrag.defaultStartPredicate(item, e);
}
});
Force items to be moved only vertically or horizontally when dragged. Set to 'x'
for horizontal movement and to 'y'
for vertical movement. By default items can be dragged both vertically and horizontally.
- Default value:
null
. - Accepted types: string.
- Allowed values:
'x'
,'y'
.
// Move items only horizontally when dragged.
var grid = new Muuri(elem, {
dragAxis: 'x'
});
// Move items only vertically when dragged.
var grid = new Muuri(elem, {
dragAxis: 'y'
});
Should the items be sorted during drag? A simple boolean will do just fine here.
Alternatively you can do some advanced stuff and control within which grids a specific item can be sorted and dragged into. To do that you need to provide a function which receives the dragged item as its first argument and should return an array of grid instances. An important thing to note here is that you need to return all the grid instances you want the dragged item to sort within, even the current grid instance. If you return an empty array the dragged item will not cause sorting at all.
- Default value:
true
. - Accepted types: boolean, function.
// Disable drag sorting.
var grid = new Muuri(elem, {
dragSort: false
});
// Multigrid drag sorting.
var gridA = new Muuri(elemA, {dragSort: getAllGrids});
var gridB = new Muuri(elemB, {dragSort: getAllGrids});
var gridC = new Muuri(elemC, {dragSort: getAllGrids});
function getAllGrids(item) {
return [gridA, gridB, gridC];
}
Defines various heuristics so that sorting during drag would be smoother and faster.
- Default value:
{sortInterval: 100, minDragDistance: 10, minBounceBackAngle: 1}
. - Accepted types: object.
You can define the following properties:
- sortInterval — number
- Default value:
100
. - Defines the amount of time the dragged item must be still before
dragSortPredicate
function is called.
- Default value:
- minDragDistance — number
- Default value:
10
. - Defines how much (in pixels) the item must be dragged before
dragSortPredicate
can be called.
- Default value:
- minBounceBackAngle — number
- Default value:
1
. - Defines the minimum angle (in radians) of the delta vector between the last movement vector and the current movement vector that is required for the dragged item to be allowed to be sorted to it's previous index. The problem this heuristic is trying to solve is the scenario where you drag an item over a much bigger item and the bigger item moves, but it's still overlapping the dragged item after repositioning. Now when you move the dragged item again another sort is triggered and the bigger item moves back to it's previous position. This bouncing back and forth can go on for quite a while and it looks quite erratic. The fix we do here is that, by default, we disallow an item to be moved back to it's previous position, unless it's drag direction changes enough. And what is enough? That's what you can define here. Note that this option works in tandem with
minDragDistance
and needs it to be set to3
at minimum to be enabled at all.
- Default value:
var grid = new Muuri(elem, {
dragEnabled: true,
dragSortHeuristics: {
sortInterval: 10,
minDragDistance: 5,
minBounceBackAngle: Math.PI / 2
}
});
Defines the logic for the sort procedure during dragging an item.
- Default value:
{action: 'move', threshold: 50}
. - Accepted types: function, object.
If an object is provided the default sort predicate handler will be used. You can define the following properties:
- action — string
- Default value:
'move'
. - Allowed values:
'move'
,'swap'
. - Should the dragged item be moved to the new position or should it swap places with the item it overlaps?
- Default value:
- threshold — number
- Default value:
50
. - Allowed values:
1
-100
. - How many percent the intersection area between the dragged item and the compared item should be from the maximum potential intersection area between the items before sorting is triggered.
- Default value:
Alternatively you can provide your own callback function where you can define your own custom sort logic. The callback function receives two arguments:
- item — Muuri.Item
- The item that's being dragged.
- event — object
- The drag event (Muuri.Dragger event).
The callback should return a falsy value if sorting should not occur. If, however, sorting should occur the callback should return an object containing the following properties:
- index — number
- The index where the item should be moved to.
- grid — Muuri
- The grid where the item should be moved to.
- Defaults to the item's current grid.
- Optional.
- action — string
- The movement method.
- Default value:
'move'
. - Allowed values:
'move'
or'swap'
. - Optional.
// Customize the default predicate.
var grid = new Muuri(elem, {
dragSortPredicate: {
threshold: 90,
action: 'swap'
}
});
// Provide your own predicate.
var grid = new Muuri(elem, {
dragSortPredicate: function (item, e) {
if (e.deltaTime < 1000) return false;
return {
index: Math.round(e.deltaTime / 1000) % 2 === 0 ? -1 : 0,
action: 'swap'
};
}
});
// Pro tip: use the default predicate as fallback in your custom predicate.
var grid = new Muuri(elem, {
dragSortPredicate: function (item, e) {
if (item.classList.contains('no-sort')) return false;
return Muuri.ItemDrag.defaultSortPredicate(item, {
action: 'swap',
threshold: 75
});
}
});
The duration for item's drag release animation. Set to 0
to disable.
- Default value:
300
. - Accepted types: number.
var grid = new Muuri(elem, {
dragReleaseDuration: 600
});
The easing for item's drag release animation. Accepts any valid Animation easing value.
- Default value:
'ease'
. - Accepted types: string.
var grid = new Muuri(elem, {
dragReleaseEasing: 'ease-out'
});
Drag specific CSS properties that Muuri sets to the draggable item elements. Muuri automatically prefixes the properties before applying them to the element. touchAction
property is required to be always defined, but the other properties are optional and can be omitted by setting their value to an empty string if you want to e.g. define them via CSS only.
- Default value:
{touchAction: 'none', userSelect: 'none', userDrag: 'none', tapHighlightColor: 'rgba(0, 0, 0, 0)', touchCallout: 'none', contentZooming: 'none'}
. - Accepted types: object.
You can define the following properties:
- touchAction — string
- Default value:
'none'
. - https://developer.mozilla.org/en-US/docs/Web/CSS/touch-action
- Default value:
- userSelect — string
- Default value:
'none'
. - https://developer.mozilla.org/en-US/docs/Web/CSS/user-select
- Optional.
- Default value:
- userDrag — string
- Default value:
'none'
. - http://help.dottoro.com/lcbixvwm.php
- Optional.
- Default value:
- tapHighlightColor — string
- Default value:
'rgba(0, 0, 0, 0)'
. - https://developer.mozilla.org/en-US/docs/Web/CSS/-webkit-tap-highlight-color
- Optional.
- Default value:
- touchCallout — string
- Default value:
'none'
. - https://developer.mozilla.org/en-US/docs/Web/CSS/-webkit-touch-callout
- Optional.
- Default value:
- contentZooming — string
- Default value:
'none'
. - https://developer.mozilla.org/en-US/docs/Web/CSS/-ms-content-zooming
- Optional.
- Default value:
// Only set the required touch-action CSS property via the options if you for
// example want to set the other props via CSS instead.
var grid = new Muuri(elem, {
dragEnabled: true,
dragCssProps: {
touchAction: 'pan-y',
userSelect: '',
userDrag: '',
tapHighlightColor: '',
touchCallout: '',
contentZooming: ''
}
});
If you want a placeholder item to appear for the duration of an item's drag & drop procedure you can enable and configure it here.
- Default value:
{enabled: false, duration: 300, easing: 'ease', createElement: null, onCreate: null, onRemove: null}
. - Accepted types: object.
You can define the following properties:
- enabled — boolean
- Default value:
false
. - Is the placeholder enabled?
- Default value:
- duration — number
- Default value:
300
. - The duration for placeholder's positioning animation. Set to
0
to disable.
- Default value:
- easing — string
- Default value:
'ease'
. - The easing for placeholder's positioning animation. Accepts any valid Animation easing value.
- Default value:
- createElement — function / null
- Default value:
null
. - If defined, this method will be used to create the DOM element that is used for the placeholder. By default a new
div
element is created when a placeholder is summoned.
- Default value:
- onCreate — function / null
- Default value:
null
. - An optional callback that will be called after a placeholder is created for an item.
- Default value:
- onRemove — function / null
- Default value:
null
. - An optional callback that will be called after a placeholder is removed from the grid.
- Default value:
// This example showcases how to pool placeholder elements
// for better performance and memory efficiency.
var phPool = [];
var phElem = document.createElement('div');
var grid = new Muuri(elem, {
dragEnabled: true,
dragPlaceholder: {
enabled: true,
duration: 400,
easing: 'ease-out',
createElement(item) {
return phPool.pop() || phElem.cloneNode();
},
onCreate(item, element) {
// If you want to do something after the
// placeholder is fully created, here's
// the place to do it.
},
onRemove (item, element) {
phPool.push(element);
}
}
});
Container element's class name.
- Default value:
'muuri'
. - Accepted types: string.
var grid = new Muuri(elem, {
containerClass: 'foo'
});
Item element's class name.
- Default value:
'muuri-item'
. - Accepted types: string.
var grid = new Muuri(elem, {
itemClass: 'foo-item'
});
Visible item's class name.
- Default value:
'muuri-item-shown'
. - Accepted types: string.
var grid = new Muuri(elem, {
itemVisibleClass: 'foo-item-shown'
});
itemHiddenClass
Hidden item's class name.
- Default value:
'muuri-item-hidden'
. - Accepted types: string.
var grid = new Muuri(elem, {
itemHiddenClass: 'foo-item-hidden'
});
This class name will be added to the item element for the duration of positioning.
- Default value:
'muuri-item-positioning'
. - Accepted types: string.
var grid = new Muuri(elem, {
itemPositioningClass: 'foo-item-positioning'
});
This class name will be added to the item element for the duration of drag.
- Default value:
'muuri-item-dragging'
. - Accepted types: string.
var grid = new Muuri(elem, {
itemDraggingClass: 'foo-item-dragging'
});
This class name will be added to the item element for the duration of release.
- Default value:
'muuri-item-releasing'
. - Accepted types: string.
var grid = new Muuri(elem, {
itemReleasingClass: 'foo-item-releasing'
});
This class name will be added to the drag placeholder element.
- Default value:
'muuri-item-placeholder'
. - Accepted types: string.
var grid = new Muuri(elem, {
itemPlaceholderClass: 'foo-item-placeholder'
});
- grid.getElement()
- grid.getItems( [targets] )
- grid.refreshItems( [items] )
- grid.refreshSortData( [items] )
- grid.synchronize()
- grid.layout( [instant], [callback] )
- grid.add( elements, [options] )
- grid.remove( items, [options] )
- grid.show( items, [options] )
- grid.hide( items, [options] )
- grid.filter( predicate, [options] )
- grid.sort( comparer, [options] )
- grid.move( item, position, [options] )
- grid.send( item, grid, position, [options] )
- grid.on( event, listener )
- grid.off( event, listener )
- grid.destroy( [removeElements] )
Get the instance element.
Returns — element
var elem = grid.getElement();
Get all items in the grid. Optionally you can provide specific targets (indices or elements).
Parameters
- targets — array / element / Muuri.Item / number
- An array of item instances/elements/indices.
- Optional.
Returns — array
Returns the queried items.
// Get all items, both active and inactive.
var allItems = grid.getItems();
// Get all active items.
var activeItems = grid.getItems().filter(function (item) {
return item.isActive();
});
// Get all positioning items.
var positioningItems = grid.getItems().filter(function (item) {
return item.isPositioning();
});
// Get the first item.
var firstItem = grid.getItems(0)[0];
// Get specific items by their elements.
var items = grid.getItems([elemA, elemB]);
Refresh the cached dimensions of the grid's items. When called without any arguments all active items are refreshed. Optionally you can provide specific the items which you want to refresh as the first argument.
Parameters
- items — array / element / Muuri.Item / number / string
- To target specific items provide an array of item instances/elements/indices. By default all active items are targeted.
- Optional.
// Refresh dimensions of all active item elements.
grid.refreshItems();
// Refresh dimensions of specific item elements.
grid.refreshItems([0, someElem, someItem]);
Refresh the sort data of the instance's items.
Parameters
- items — array / element / Muuri.Item / number
- To target specific items provide an array of item instances/elements/indices. By default all items are targeted.
- Optional.
// Refresh the sort data for every item.
grid.refreshSortData();
// Refresh the sort data for specific items.
grid.refreshSortData([0, someElem, someItem]);
Synchronize the item elements to match the order of the items in the DOM. This comes handy if you need to keep the DOM structure matched with the order of the items. Note that if an item's element is not currently a child of the container element (if it is dragged for example) it is ignored and left untouched.
// Let's say we have to move the first item in the grid as the last.
grid.move(0, -1);
// Now the DOM order of the items is not in sync anymore with the
// order of the items. We can sync the DOM with synchronize method.
grid.synchronize();
Calculate item positions and move items to their calculated positions, unless they are already positioned correctly. The grid's height/width (depends on the layout algorithm) is also adjusted according to the position of the items.
Parameters
- instant — boolean
- Should the items be positioned instantly without any possible animation?
- Default value:
false
. - Optional.
- callback — function
- A callback function that is called after the items have positioned. Receives one argument: an array of all the items that were successfully positioned without interruptions.
- Optional.
// Layout items.
grid.layout();
// Layout items instantly (without animations).
grid.layout(true);
// Layout all items and define a callback that will be called
// after all items have been animated to their positions.
grid.layout(function (items) {
console.log('layout done!');
});
Add new items by providing the elements you wish to add to the instance and optionally provide the index where you want the items to be inserted into. All elements that are not already children of the container element will be automatically appended to the container element. If an element has it's CSS display property set to none it will be marked as inactive during the initiation process. As long as the item is inactive it will not be part of the layout, but it will retain it's index. You can activate items at any point with grid.show()
method. This method will automatically call grid.layout()
if one or more of the added elements are visible. If only hidden items are added no layout will be called. All the new visible items are positioned without animation during their first layout.
Parameters
- elements — array / element
- An array of DOM elements.
- options.index — number
- The index where you want the items to be inserted in. A value of
-1
will insert the items to the end of the list while0
will insert the items to the beginning. Note that the DOM elements are always just appended to the instance container regardless of the index value. You can use thegrid.synchronize()
method to arrange the DOM elements to the same order as the items. - Default value:
-1
. - Optional.
- The index where you want the items to be inserted in. A value of
- options.layout — boolean / function / string
- By default
grid.layout()
is called at the end of this method. With this argument you can control the layout call. You can disable the layout completely withfalse
, or provide a callback function for the layout method, or provide the string'instant'
to make the layout happen instantly without any animations. - Default value:
true
. - Optional.
- By default
Returns — array
Returns the added items.
// Add two new items to the end.
grid.add([elemA, elemB]);
// Add two new items to the beginning.
grid.add([elemA, elemB], {index: 0});
// Skip the automatic layout.
grid.add([elemA, elemB], {layout: false});
Remove items from the instance.
Parameters
- items — array / element / Muuri.Item / number
- An array of item instances/elements/indices.
- options.removeElements — boolean
- Should the associated DOM element be removed from the DOM?
- Default value:
false
. - Optional.
- options.layout — boolean / function / string
- By default
grid.layout()
is called at the end of this method. With this argument you can control the layout call. You can disable the layout completely withfalse
, or provide a callback function for the layout method, or provide the string'instant'
to make the layout happen instantly without any animations. - Default value:
true
. - Optional.
- By default
Returns — array
Returns the destroyed items.
// Remove the first item, but keep the element in the DOM.
grid.remove(0);
// Remove items and the associated elements.
grid.remove([elemA, elemB], {removeElements: true});
// Skip the layout.
grid.remove([elemA, elemB], {layout: false});
Show the targeted items.
Parameters
- items — array / element / Muuri.Item / number
- An array of item instances/elements/indices.
- options.instant — boolean
- Should the items be shown instantly without any possible animation?
- Default value:
false
. - Optional.
- options.onFinish — function
- A callback function that is called after the items are shown.
- Optional.
- options.layout — boolean / function / string
- By default
grid.layout()
is called at the end of this method. With this argument you can control the layout call. You can disable the layout completely withfalse
, or provide a callback function for the layout method, or provide the string'instant'
to make the layout happen instantly without any animations. - Default value:
true
. - Optional.
- By default
// Show items with animation (if any).
grid.show([elemA, elemB]);
// Show items instantly without animations.
grid.show([elemA, elemB], {instant: true});
// Show items with callback (and with animations if any).
grid.show([elemA, elemB], {onFinish: function (items) {
console.log('items shown!');
}});
Hide the targeted items.
Parameters
- items — array / element / Muuri.Item / number
- An array of item instances/elements/indices.
- options.instant — boolean
- Should the items be hidden instantly without any possible animation?
- Default value:
false
. - Optional.
- options.onFinish — function
- A callback function that is called after the items are hidden.
- Optional.
- options.layout — boolean / function / string
- By default
grid.layout()
is called at the end of this method. With this argument you can control the layout call. You can disable the layout completely withfalse
, or provide a callback function for the layout method, or provide the string'instant'
to make the layout happen instantly without any animations. - Default value:
true
. - Optional.
- By default
// Hide items with animation.
grid.hide([elemA, elemB]);
// Hide items instantly without animations.
grid.hide([elemA, elemB], {instant: true});
// Hide items and call the callback function after
// all items are hidden.
grid.hide([elemA, elemB], {onFinish: function (items) {
console.log('items hidden!');
}});
Filter items. Expects at least one argument, a predicate, which should be either a function or a string. The predicate callback is executed for every item in the instance. If the return value of the predicate is truthy the item in question will be shown and otherwise hidden. The predicate callback receives the item instance as it's argument. If the predicate is a string it is considered to be a selector and it is checked against every item element in the instance with the native element.matches() method. All the matching items will be shown and others hidden.
Parameters
- predicate — function / string
- A predicate callback or a selector.
- options.instant — boolean
- Should the items be shown/hidden instantly without any possible animation?
- Default value:
false
. - Optional.
- options.onFinish — function
- An optional callback function that is called after all the items are shown/hidden.
- Optional.
- options.layout — boolean / function / string
- By default
grid.layout()
is called at the end of this method. With this argument you can control the layout call. You can disable the layout completely withfalse
, or provide a callback function for the layout method, or provide the string'instant'
to make the layout happen instantly without any animations. - Default value:
true
. - Optional.
- By default
// Show all items that have the attribute "data-foo".
grid.filter(function (item) {
return item.getElement().hasAttribute('data-foo');
});
// Or simply just...
grid.filter('[data-foo]');
// Show all items that have a class foo.
grid.filter('.foo');
Sort items. There are three ways to sort the items. The first is simply by providing a function as the comparer which works almost identically to native array sort. The only difference is that the sort is always stable. Alternatively you can sort by the sort data you have provided in the instance's options. Just provide the sort data key(s) as a string (separated by space) and the items will be sorted based on the provided sort data keys. Lastly you have the opportunity to provide a presorted array of items which will be used to sync the internal items array in the same order.
Parameters
- comparer — array / function / string
- Provide a comparer function, sort data keys as a string (separated with space) or a presorted array of items. It is recommended to use the sort data feature, because it allows you to cache the sort data and make the sorting faster.
- options.descending — boolean
- By default the items are sorted in ascending order. If you want to sort them in descending order set this to
true
. - Default value:
false
. - Optional.
- By default the items are sorted in ascending order. If you want to sort them in descending order set this to
- options.layout — boolean / function / string
- By default
grid.layout()
is called at the end of this method. With this argument you can control the layout call. You can disable the layout completely withfalse
, or provide a callback function for the layout method, or provide the string'instant'
to make the layout happen instantly without any animations. - Default value:
true
. - Optional.
- By default
// Sort items by data-id attribute value (ascending).
grid.sort(function (itemA, itemB) {
var aId = parseInt(itemA.getElement().getAttribute('data-id'));
var bId = parseInt(itemB.getElement().getAttribute('data-id'));
return aId - bId;
});
// Sort items with a presorted array of items.
grid.sort(presortedItems);
// Sort items using the sort data keys (ascending).
grid.sort('foo bar');
// Sort items using the sort data keys (descending).
grid.sort('foo bar', {descending: true});
// Sort items using the sort data keys. Sort some keys
// ascending and some keys descending.
grid.sort('foo bar:desc');
Move an item to another position in the grid.
Parameters
- item — element / Muuri.Item / number
- Item instance, element or index.
- position — element / Muuri.Item / number
- Item instance, element or index.
- options.action — string
- Accepts the following values:
'move'
: moves item in place of another item.'swap'
: swaps position of items.
- Default value:
'move'
. - Optional.
- Accepts the following values:
- options.layout — boolean / function / string
- By default
grid.layout()
is called at the end of this method. With this argument you can control the layout call. You can disable the layout completely withfalse
, or provide a callback function for the layout method, or provide the string'instant'
to make the layout happen instantly without any animations. - Default value:
true
. - Optional.
- By default
// Move elemA to the index of elemB.
grid.move(elemA, elemB);
// Move the first item in the grid as the last.
grid.move(0, -1);
// Swap positions of elemA and elemB.
grid.move(elemA, elemB, {action: 'swap'});
// Swap positions of the first and the last item.
grid.move(0, -1, {action: 'swap'});
Move an item into another grid.
Parameters
- item — element / Muuri.Item / number
- The item that should be moved. You can define the item with an item instance, element or index.
- grid — Muuri
- The grid where the item should be moved to.
- position — element / Muuri.Item / number
- To which position should the item be placed to in the new grid? You can define the position with an item instance, element or index.
- options.appendTo — element
- Which element the item element should be appended to for the duration of the layout animation?
- Default value:
document.body
.
- options.layoutSender — boolean / function / string
- By default
grid.layout()
is called for the sending grid at the end of this method. With this argument you can control the layout call. You can disable the layout completely withfalse
, or provide a callback function for the layout method, or provide the string'instant'
to make the layout happen instantly without any animations. - Default value:
true
. - Optional.
- By default
- options.layoutReceiver — boolean / function / string
- By default
grid.layout()
is called for the receiving grid at the end of this method. With this argument you can control the layout call. You can disable the layout completely withfalse
, or provide a callback function for the layout method, or provide the string'instant'
to make the layout happen instantly without any animations. - Default value:
true
. - Optional.
- By default
// Move the first item of gridA as the last item of gridB.
// The sent item will be appended to document.body.
gridA.send(0, gridB, -1);
// Move the first item of gridA as the last item of gridB.
// The sent item will be appended to someElem.
gridA.send(0, gridB, -1, {
appendTo: someElem
});
// Do something after the item has been sent and the layout
// processes have finished.
gridA.send(0, gridB, -1, {
layoutSender: function (isAborted, items) {
// Do your thing here...
},
layoutReceiver: function (isAborted, items) {
// Do your other thing here...
}
});
Bind an event listener.
Parameters
- event — string
- listener — function
Returns — object
Returns the instance.
grid.on('layoutEnd', function (items) {
console.log(items);
});
Unbind an event listener.
Parameters
- event — string
- listener — function
Returns — object
Returns the instance.
var listener = function (items) {
console.log(items);
};
muuri
.on('layoutEnd', listener)
.off('layoutEnd', listener);
Destroy the grid instance.
Parameters
- removeElements — boolean
- Should the item elements be removed or not?
- Default value:
false
. - Optional.
Returns — object
Returns the instance.
// Destroy the instance.
grid.destroy();
// Destroy the instance and remove item elements.
grid.destroy(true);
- synchronize
- layoutStart
- layoutEnd
- add
- remove
- showStart
- showEnd
- hideStart
- hideEnd
- filter
- sort
- move
- send
- beforeSend
- receive
- beforeReceive
- dragInit
- dragStart
- dragMove
- dragScroll
- dragEnd
- dragReleaseStart
- dragReleaseEnd
- destroy
Triggered after grid.synchronize()
is called.
grid.on('synchronize', function () {
console.log('Synced!');
});
Triggered after grid.layout()
is called, just before the items are positioned.
Arguments
- items — array
- The items that are about to be positioned.
grid.on('layoutStart', function (items) {
console.log(items);
});
Triggered after grid.layout()
is called, after the items have positioned. Note that if grid.layout()
is called during an ongoing layout animation the ongoing layout process will be aborted and it's layoutEnd event will never be triggered.
Arguments
- items — array
- The items that were intended to be positioned. Note that these items are always identical to what the layoutStart event's callback receives as it's argument. So if, for example, you destroy an item during the layout animation and don't do call another layout the destroyed item will still be included in this array of items. The original intention was to filter these items so that all items that were "interrupted" somehow during the layout process would be omitted from the results, but that solution was much more prone to errors and much more harder to explain/understand.
grid.on('layoutEnd', function (items) {
console.log(items);
});
Triggered after grid.add()
is called.
Arguments
- items — array
- The items that were successfully added.
grid.on('add', function (items) {
console.log(items);
});
Triggered after grid.remove()
is called.
Arguments
- items — array
- The items that were successfully removed.
- indices — array
- Indices of the items that were successfully removed.
grid.on('remove', function (items, indices) {
console.log(items, indices);
});
Triggered after grid.show()
is called, just before the items are shown.
Arguments
- items — array
- The items that are about to be shown.
grid.on('showStart', function (items) {
console.log(items);
});
Triggered after grid.show()
is called, after the items are shown.
Arguments
- items — array
- The items that were successfully shown without interruptions. If you, for example, call
grid.hide()
to some of the items that are currently being shown, those items will be omitted from this argument.
- The items that were successfully shown without interruptions. If you, for example, call
grid.on('showEnd', function (items) {
console.log(items);
});
Triggered after grid.hide()
is called, just before the items are hidden.
Arguments
- items — array
- The items that are about to be hidden.
grid.on('hideStart', function (items) {
console.log(items);
});
Triggered after grid.hide()
is called, after the items are hidden.
Arguments
- items — array
- The items that were successfully hidden without interruptions. If you, for example, call
grid.show()
to some of the items that are currently being hidden, those items will be omitted from this argument.
- The items that were successfully hidden without interruptions. If you, for example, call
grid.on('hideEnd', function (items) {
console.log(items);
});
Triggered after grid.filter()
is called.
Arguments
- shownItems — array
- The items that are shown.
- hiddenItems — array
- The items that are hidden.
grid.on('filter', function (shownItems, hiddenItems) {
console.log(shownItems);
console.log(hiddenItems);
});
Triggered after grid.sort()
is called.
Arguments
- currentOrder — array
- All items in their current order.
- previousOrder — array
- All items in their previous order.
grid.on('sort', function (currentOrder, previousOrder) {
console.log(currentOrder);
console.log(previousOrder);
});
Triggered after grid.move()
is called or when the grid is sorted during drag. Note that this is event not triggered when an item is dragged into another grid.
Arguments
- data — object
- data.item — Muuri.Item
- The item that was moved.
- data.fromIndex — number
- The index the item was moved from.
- data.toIndex — number
- The index the item was moved to.
- data.action — string
- "move" or "swap".
- data.item — Muuri.Item
grid.on('move', function (data) {
console.log(data);
});
Triggered for the originating grid in the end of the send process (after grid.send()
is called or when an item is dragged into another grid). Note that this event is called before the item's layout starts.
Arguments
- data — object
- data.item — Muuri.Item
- The item that was sent.
- data.fromGrid — Muuri
- The grid the item was sent from.
- data.fromIndex — number
- The index the item was moved from.
- data.toGrid — Muuri
- The grid the item was sent to.
- data.toIndex — number
- The index the item was moved to.
- data.item — Muuri.Item
grid.on('send', function (data) {
console.log(data);
});
Triggered for the originating grid in the beginning of the send process (after grid.send()
is called or when an item is dragged into another grid). This event is highly useful in situations where you need to manipulate the sent item (freeze it's dimensions for example) before it is appended to it's temporary layout container as defined in send method options.
Arguments
- data — object
- data.item — Muuri.Item
- The item that was sent.
- data.fromGrid — Muuri
- The grid the item was sent from.
- data.fromIndex — number
- The index the item was moved from.
- data.toGrid — Muuri
- The grid the item was sent to.
- data.toIndex — number
- The index the item was moved to.
- data.item — Muuri.Item
grid.on('beforeSend', function (data) {
console.log(data);
});
Triggered for the receiving grid in the end of the send process (after grid.send()
is called or when an item is dragged into another grid). Note that this event is called before the item's layout starts.
Arguments
- data — object
- data.item — Muuri.Item
- The item that was sent.
- data.fromGrid — Muuri
- The grid the item was sent from.
- data.fromIndex — number
- The index the item was moved from.
- data.toGrid — Muuri
- The grid the item was sent to.
- data.toIndex — number
- The index the item was moved to.
- data.item — Muuri.Item
grid.on('receive', function (data) {
console.log(data);
});
Triggered for the receiving grid in the beginning of the send process (after grid.send()
is called or when an item is dragged into another grid). This event is highly useful in situations where you need to manipulate the received item (freeze it's dimensions for example) before it is appended to it's temporary layout container as defined in send method options.
Arguments
- data — object
- data.item — Muuri.Item
- The item that was sent.
- data.fromGrid — Muuri
- The grid the item was sent from.
- data.fromIndex — number
- The index the item was moved from.
- data.toGrid — Muuri
- The grid the item was sent to.
- data.toIndex — number
- The index the item was moved to.
- data.item — Muuri.Item
grid.on('beforeReceive', function (data) {
console.log(data);
});
Triggered in the beginning of the drag start process when dragging of an item begins. This event is highly useful in situations where you need to manipulate the dragged item (freeze it's dimensions for example) before it is appended to the dragContainer.
Arguments
- item — Muuri.Item
- The dragged item.
- event — object
- Muuri.Dragger event data.
grid.on('dragInit', function (item, event) {
console.log(event);
console.log(item);
});
Triggered in the end of the drag start process when dragging of an item begins.
Arguments
- item — Muuri.Item
- The dragged item.
- event — object
- Muuri.Dragger event data.
grid.on('dragStart', function (item, event) {
console.log(event);
console.log(item);
});
Triggered when an item is dragged after the drag start process.
Arguments
- item — Muuri.Item
- The dragged item.
- event — object
- Muuri.Dragger event data.
grid.on('dragMove', function (item, event) {
console.log(event);
console.log(item);
});
Triggered when any of the scroll parents of a dragged item is scrolled.
Arguments
- item — Muuri.Item
- The dragged item.
- event — object
- The scroll event data.
grid.on('dragScroll', function (item, event) {
console.log(event);
console.log(item);
});
Triggered when dragging of an item ends.
Arguments
- item — Muuri.Item
- The dragged item.
- event — object
- Muuri.Dragger event data.
grid.on('dragEnd', function (item, event) {
console.log(event);
console.log(item);
});
Triggered when a dragged item is released.
Arguments
- item — Muuri.Item
- The released item.
grid.on('dragReleaseStart', function (item) {
console.log(item);
});
Triggered after released item has been animated to position.
Arguments
- item — Muuri.Item
- The released item.
grid.on('dragReleaseEnd', function (item) {
console.log(item);
});
Triggered after grid.destroy()
is called.
grid.on('destroy', function () {
console.log('Muuri is no more...');
});
- item.getGrid()
- item.getElement()
- item.getWidth()
- item.getHeight()
- item.getMargin()
- item.getPosition()
- item.isActive()
- item.isVisible()
- item.isShowing()
- item.isHiding()
- item.isPositioning()
- item.isDragging()
- item.isReleasing()
- item.isDestroyed()
Get the instance's grid instance.
Returns — Muuri
var grid = item.getGrid();
Get the instance element.
Returns — element
var elem = item.getElement();
Get instance element's cached width. The returned value includes the element's paddings and borders.
Returns — number
var width = item.getWidth();
Get instance element's cached height. The returned value includes the element's paddings and borders.
Returns — number
var height = item.getHeight();
Get instance element's cached margins.
Returns — object
- obj.left — number
- obj.right — number
- obj.top — number
- obj.bottom — number
var margin = item.getMargin();
Get instance element's cached position (relative to the container element).
Returns — object
- obj.left — number
- obj.top — number
var position = item.getPosition();
Check if the item is currently active. Only active items are considered to be part of the layout.
Returns — boolean
var isActive = item.isActive();
Check if the item is currently visible.
Returns — boolean
var isVisible = item.isVisible();
Check if the item is currently animating to visible.
Returns — boolean
var isShowing = item.isShowing();
Check if the item is currently animating to hidden.
Returns — boolean
var isHiding = item.isHiding();
Check if the item is currently being positioned.
Returns — boolean
var isPositioning = item.isPositioning();
Check if the item is currently being dragged.
Returns — boolean
var isDragging = item.isDragging();
Check if the item is currently being released.
Returns — boolean
var isReleasing = item.isReleasing();
Check if the item is destroyed.
Returns — boolean
var isDestroyed = item.isDestroyed();
Created and maintained by Niklas Rämö.
- This project owes much to David DeSandro's Masonry, Packery and Isotope libraries. You should go ahead and check them out right now if you haven't yet. Thanks Dave!
- Jukka Jylänki's research A Thousand Ways to Pack the Bin came in handy when building Muuri's layout algorithms. Thanks Jukka!
- Big thanks to the people behind Web Animations polyfill, Muuri would be much less cool without smooth animations.
- Haltu Oy was responsible for initiating this project in the first place and funded the initial development. Thanks Haltu!
Copyright © 2015 Haltu Oy. Licensed under the MIT license.