Skip to main content

Guides

Grid Types

MasonryInfiniteGrid

MasonryInfiniteGrid is a grid that stacks items with the same width as a stack of bricks. Adjust the width of all images to the same size, find the lowest height column, and insert a new item.

egjs
egjs 0
egjs
egjs 1
egjs
egjs 2
egjs
egjs 3
egjs
egjs 4
egjs
egjs 5
egjs
egjs 6
egjs
egjs 7
egjs
egjs 8
egjs
egjs 9
egjs
egjs 10
egjs
egjs 11
egjs
egjs 12
egjs
egjs 13
egjs
egjs 14
egjs
egjs 15
egjs
egjs 16
egjs
egjs 17
egjs
egjs 18
egjs
egjs 19
egjs
egjs 20
egjs
egjs 21
egjs
egjs 22
egjs
egjs 23
egjs
egjs 24
egjs
egjs 25
egjs
egjs 26
egjs
egjs 27
egjs
egjs 28
egjs
egjs 29
egjs
egjs 30
egjs
egjs 31
egjs
egjs 32
egjs
egjs 33
egjs
egjs 34
egjs
egjs 35
egjs
egjs 36
egjs
egjs 37
egjs
egjs 38
egjs
egjs 39
egjs
egjs 40
egjs
egjs 41
egjs
egjs 42
egjs
egjs 43
egjs
egjs 44
egjs
egjs 45
egjs
egjs 46
egjs
egjs 47
egjs
egjs 48
egjs
egjs 49
egjs
egjs 50
egjs
egjs 51
egjs
egjs 52
egjs
egjs 53
egjs
egjs 54
egjs
egjs 55
egjs
egjs 56
egjs
egjs 57
egjs
egjs 58
egjs
egjs 59
<div class="container"></div>
import { MasonryInfiniteGrid } from "@egjs/infinitegrid";

function getItems(nextGroupKey, count) {
const nextItems = [];

for (let i = 0; i < count; ++i) {
const num = nextGroupKey * count + i;
nextItems.push(`<div class="item">
<div class="thumbnail">
<img src="https://naver.github.io/egjs-infinitegrid/assets/image/${(num % 33) + 1}.jpg" alt="egjs" />
</div>
<div class="info">egjs ${num}</div>
</div>`);
}
return nextItems;
}
const ig = new MasonryInfiniteGrid(".container", {
gap: 5,
});

ig.on("requestAppend", (e) => {
const nextGroupKey = (+e.groupKey || 0) + 1;

ig.append(getItems(nextGroupKey, 10), nextGroupKey);
});
ig.renderItems();

JustifiedInfiniteGrid

'justified' is a printing term with the meaning that 'it fits in one row wide'. JustifiedGrid is a grid that the item is filled up on the basis of a line given a size.

  • If 'data-grid-inline-offset' or 'data-grid-content-offset' are set for item element, the ratio is maintained except for the offset value.
  • If 'data-grid-maintained-target' is set for an element whose ratio is to be maintained, the item is rendered while maintaining the ratio of the element.
egjs
egjs 0
egjs
egjs 1
egjs
egjs 2
egjs
egjs 3
egjs
egjs 4
egjs
egjs 5
egjs
egjs 6
egjs
egjs 7
egjs
egjs 8
egjs
egjs 9
egjs
egjs 10
egjs
egjs 11
egjs
egjs 12
egjs
egjs 13
egjs
egjs 14
egjs
egjs 15
egjs
egjs 16
egjs
egjs 17
egjs
egjs 18
egjs
egjs 19
egjs
egjs 20
egjs
egjs 21
egjs
egjs 22
egjs
egjs 23
egjs
egjs 24
egjs
egjs 25
egjs
egjs 26
egjs
egjs 27
egjs
egjs 28
egjs
egjs 29
egjs
egjs 30
egjs
egjs 31
egjs
egjs 32
egjs
egjs 33
egjs
egjs 34
egjs
egjs 35
egjs
egjs 36
egjs
egjs 37
egjs
egjs 38
egjs
egjs 39
egjs
egjs 40
egjs
egjs 41
egjs
egjs 42
egjs
egjs 43
egjs
egjs 44
egjs
egjs 45
egjs
egjs 46
egjs
egjs 47
egjs
egjs 48
egjs
egjs 49
egjs
egjs 50
egjs
egjs 51
egjs
egjs 52
egjs
egjs 53
egjs
egjs 54
egjs
egjs 55
egjs
egjs 56
egjs
egjs 57
egjs
egjs 58
egjs
egjs 59
egjs
egjs 60
egjs
egjs 61
egjs
egjs 62
egjs
egjs 63
egjs
egjs 64
egjs
egjs 65
egjs
egjs 66
egjs
egjs 67
egjs
egjs 68
egjs
egjs 69
egjs
egjs 70
egjs
egjs 71
egjs
egjs 72
egjs
egjs 73
egjs
egjs 74
egjs
egjs 75
egjs
egjs 76
egjs
egjs 77
egjs
egjs 78
egjs
egjs 79
<div class="container"></div>
import { JustifiedInfiniteGrid } from "@egjs/infinitegrid";

function getItems(nextGroupKey, count) {
const nextItems = [];

for (let i = 0; i < count; ++i) {
const num = nextGroupKey * count + i;
nextItems.push(`<div class="item">
<div class="thumbnail">
<img src="https://naver.github.io/egjs-infinitegrid/assets/image/${(num % 33) + 1}.jpg" alt="egjs" data-grid-maintained-target="true"/>
</div>
<div class="info">egjs ${num}</div>
</div>`);
}
return nextItems;
}
const ig = new JustifiedInfiniteGrid(".container", {
gap: 5,
});

ig.on("requestAppend", (e) => {
const nextGroupKey = (+e.groupKey || 0) + 1;

ig.append(getItems(nextGroupKey, 10), nextGroupKey);
});
ig.renderItems();

JustifiedInfiniteGrid (Stretch)

stretch is possible to basically break the proportion of the item and stretch the inline size to fill the container. If you set the sizeRange range narrowly, you can stretch well.

  • stretchRange: If -, +, or % are added as a string value, it is a relative value to the original size. If it is a number value, the stretch range can be set as an absolute value. If data-grid-min-stretch and data-grid-max-stretch are set in the Element or JSX of each item, they will be applied first.
  • passUnstretchRow: Items placed in the last row are not stretched and are drawn maintaining their proportions. When using InfiniteGrid, it is calculated and re-rendered as follows:
egjs
egjs 0
egjs
egjs 1
egjs
egjs 2
egjs
egjs 3
egjs
egjs 4
egjs
egjs 5
egjs
egjs 6
egjs
egjs 7
egjs
egjs 8
egjs
egjs 9
<div class="container"></div>
import { JustifiedInfiniteGrid } from "@egjs/infinitegrid";

function getItems(nextGroupKey, count) {
const nextItems = [];

for (let i = 0; i < count; ++i) {
const num = nextGroupKey * count + i;
nextItems.push(`<div class="item">
<div class="thumbnail">
<img src="https://naver.github.io/egjs-infinitegrid/assets/image/${(num % 33) + 1}.jpg" alt="egjs" />
</div>
<div class="info">egjs ${num}</div>
</div>`);
}
return nextItems;
}
const ig = new JustifiedInfiniteGrid(".container", {
gap: 5,
stretch: true,
passUnstretchRow: true,
sizeRange: [228,228],
stretchRange: [144,320],
});

ig.on("requestAppend", (e) => {
const nextGroupKey = (+e.groupKey || 0) + 1;

ig.append(getItems(nextGroupKey, 10), nextGroupKey);
});
ig.renderItems();

FrameInfiniteGrid

'Frame' is a printing term with the meaning that 'it fits in one row wide'. FrameGrid is a grid that the item is filled up on the basis of a line given a size.

egjs
egjs
egjs
egjs
egjs
egjs
egjs
egjs
egjs
egjs
<div class="container"></div>
import { FrameInfiniteGrid } from "@egjs/infinitegrid";

function getItems(nextGroupKey, count) {
const nextItems = [];

for (let i = 0; i < count; ++i) {
const num = nextGroupKey * count + i;
nextItems.push(`<div class="item">
<div class="thumbnail">
<img src="https://naver.github.io/egjs-infinitegrid/assets/image/${(num % 33) + 1}.jpg" alt="egjs" />
</div>
<div class="info">egjs ${num}</div>
</div>`);
}
return nextItems;
}
const ig = new FrameInfiniteGrid(".container", {
gap: 5,
frame: [[1,1,2,3,3],[1,1,4,4,5]],
});

ig.on("requestAppend", (e) => {
const nextGroupKey = (+e.groupKey || 0) + 1;

ig.append(getItems(nextGroupKey, 10), nextGroupKey);
});
ig.renderItems();

PackingInfiniteGrid

The PackingGrid is a grid that shows the important items bigger without sacrificing the weight of the items.

  • Rows and columns are separated so that items are dynamically placed within the horizontal and vertical space rather than arranged in an orderly fashion.
  • If sizeWeight is higher than ratioWeight, the size of items is preserved as much as possible.
  • Conversely, if ratioWeight is higher than sizeWeight, the ratio of items is preserved as much as possible.
egjs
egjs
egjs
egjs
egjs
egjs
egjs
egjs
egjs
egjs
<div class="container"></div>
import { PackingInfiniteGrid } from "@egjs/infinitegrid";

function getItems(nextGroupKey, count) {
const nextItems = [];

for (let i = 0; i < count; ++i) {
const num = nextGroupKey * count + i;
nextItems.push(`<div class="item">
<div class="thumbnail">
<img src="https://naver.github.io/egjs-infinitegrid/assets/image/${(num % 33) + 1}.jpg" alt="egjs" />
</div>
<div class="info">egjs ${num}</div>
</div>`);
}
return nextItems;
}
const ig = new PackingInfiniteGrid(".container", {
gap: 5,
});

ig.on("requestAppend", (e) => {
const nextGroupKey = (+e.groupKey || 0) + 1;

ig.append(getItems(nextGroupKey, 10), nextGroupKey);
});
ig.renderItems();

Insert Data

Through scrolling, when the scroll reaches the end, the requestAppend event is raised, and when it reaches the start, the requestPrepend event is raised. You can add data within this event.

  • You can set the key of an item through itemBy prop.
  • You can set the group's key through groupBy prop.
egjs
egjs 0
egjs
egjs 1
egjs
egjs 2
egjs
egjs 3
egjs
egjs 4
egjs
egjs 5
egjs
egjs 6
egjs
egjs 7
egjs
egjs 8
egjs
egjs 9
egjs
egjs 10
egjs
egjs 11
egjs
egjs 12
egjs
egjs 13
egjs
egjs 14
egjs
egjs 15
egjs
egjs 16
egjs
egjs 17
egjs
egjs 18
egjs
egjs 19
egjs
egjs 20
egjs
egjs 21
egjs
egjs 22
egjs
egjs 23
egjs
egjs 24
egjs
egjs 25
egjs
egjs 26
egjs
egjs 27
egjs
egjs 28
egjs
egjs 29
egjs
egjs 30
egjs
egjs 31
egjs
egjs 32
egjs
egjs 33
egjs
egjs 34
egjs
egjs 35
egjs
egjs 36
egjs
egjs 37
egjs
egjs 38
egjs
egjs 39
egjs
egjs 40
egjs
egjs 41
egjs
egjs 42
egjs
egjs 43
egjs
egjs 44
egjs
egjs 45
egjs
egjs 46
egjs
egjs 47
egjs
egjs 48
egjs
egjs 49
egjs
egjs 50
egjs
egjs 51
egjs
egjs 52
egjs
egjs 53
egjs
egjs 54
egjs
egjs 55
egjs
egjs 56
egjs
egjs 57
egjs
egjs 58
egjs
egjs 59

If the append method or prepend method is used, there is no need to use a separate key. You can set the groupKey through the second argument.

ig.on("requestAppend", e => {
const nextGroupKey = (+e.groupKey || 0) + 1;

ig.append(getItems(nextGroupKey, 10), nextGroupKey);
});

Wait Data Loading

Use wait & ready

If you want to add items asynchronously, call the e.wait function and when the data is ready call the e.ready function.

egjs
egjs 0
egjs
egjs 1
egjs
egjs 2
egjs
egjs 3
egjs
egjs 4
egjs
egjs 5
egjs
egjs 6
egjs
egjs 7
egjs
egjs 8
egjs
egjs 9
egjs
egjs 10
egjs
egjs 11
egjs
egjs 12
egjs
egjs 13
egjs
egjs 14
egjs
egjs 15
egjs
egjs 16
egjs
egjs 17
egjs
egjs 18
egjs
egjs 19
ig.on("requestAppend", e => {
const nextGroupKey = (+e.groupKey || 0) + 1;

e.wait();

setTimeout(() => {
e.ready();
ig.append(getItems(nextGroupKey, 10), nextGroupKey);
}, 1000);
});

Use Placeholder

You can add placeholders to show instead while data is being loaded/added. The placeholder is placed on the grid instead of the actual item and can be maintained until the actual item is added.

egjs
egjs 0
egjs
egjs 1
egjs
egjs 2
egjs
egjs 3
egjs
egjs 4
egjs
egjs 5
egjs
egjs 6
egjs
egjs 7
egjs
egjs 8
egjs
egjs 9
egjs
egjs 10
egjs
egjs 11
egjs
egjs 12
egjs
egjs 13
egjs
egjs 14
egjs
egjs 15
egjs
egjs 16
egjs
egjs 17
egjs
egjs 18
egjs
egjs 19

You can set a placeholder through the ig.setPlaceholder method.

ig.setPlaceholder({
html: `<div class="placeholder"></div>`,
});

ig.on("requestAppend", e => {
const nextGroupKey = (+e.groupKey || 0) + 1;

e.wait();
e.currentTarget.appendPlaceholders(5, nextGroupKey);
setTimeout(() => {
e.ready();
ig.append(getItems(nextGroupKey, 10), nextGroupKey);
}, 1000);
});

Use loading

You can show the loading bar while the data is loading. It can be added by calling the e.wait function, and the loading bar automatically disappears when data is loaded.

egjs
egjs 0
egjs
egjs 1
egjs
egjs 2
egjs
egjs 3
egjs
egjs 4
egjs
egjs 5
egjs
egjs 6
egjs
egjs 7
egjs
egjs 8
egjs
egjs 9
egjs
egjs 10
egjs
egjs 11
egjs
egjs 12
egjs
egjs 13
egjs
egjs 14
egjs
egjs 15
egjs
egjs 16
egjs
egjs 17
egjs
egjs 18
egjs
egjs 19
Loading...

You can set a loading through the ig.setLoading method.

ig.setLoading({
html: `<div class="loading">Loading...</div>`,
});

ig.on("requestAppend", e => {
const nextGroupKey = (+e.groupKey || 0) + 1;

e.wait();
setTimeout(() => {
e.ready();
ig.append(getItems(nextGroupKey, 10), nextGroupKey);
}, 1000);
});

Restore Status

You want to save the current status to storage before moving the page and restore it after returning the page.

If it does not support BF Cache like Safari, you need to save and restore the status.

InfiniteGrid provides a way to get and restore status.

If you want to restore dynamically, call the setStatus method.

In the framework, items must also be saved and restored.

Get Status & Restore Status

egjs
egjs 0
egjs
egjs 1
egjs
egjs 2
egjs
egjs 3
egjs
egjs 4
egjs
egjs 5
egjs
egjs 6
egjs
egjs 7
egjs
egjs 8
egjs
egjs 9
egjs
egjs 10
egjs
egjs 11
egjs
egjs 12
egjs
egjs 13
egjs
egjs 14
egjs
egjs 15
egjs
egjs 16
egjs
egjs 17
egjs
egjs 18
egjs
egjs 19
egjs
egjs 20
egjs
egjs 21
egjs
egjs 22
egjs
egjs 23
egjs
egjs 24
egjs
egjs 25
egjs
egjs 26
egjs
egjs 27
egjs
egjs 28
egjs
egjs 29
egjs
egjs 30
egjs
egjs 31
egjs
egjs 32
egjs
egjs 33
egjs
egjs 34
egjs
egjs 35
egjs
egjs 36
egjs
egjs 37
egjs
egjs 38
egjs
egjs 39
egjs
egjs 40
egjs
egjs 41
egjs
egjs 42
egjs
egjs 43
egjs
egjs 44
egjs
egjs 45
egjs
egjs 46
egjs
egjs 47
egjs
egjs 48
egjs
egjs 49
egjs
egjs 50
egjs
egjs 51
egjs
egjs 52
egjs
egjs 53
egjs
egjs 54
egjs
egjs 55
egjs
egjs 56
egjs
egjs 57
egjs
egjs 58
egjs
egjs 59

Get Status

const status = ig.getStatus();

Restore Status

const ig = new MasonryInfiniteGrid(...);

ig.setStatus(status);

Restore Visible Status

To reduce the size of the status, only the status of the items in the visible area is fetched.

import { STATUS_TYPE } from "@egjs/infinitegrid";

// (default) gets all infos
ig.getStatus(STATUS_TYPE.NOT_REMOVE);

// gets visible infos
ig.getStatus(STATUS_TYPE.REMOVE_INVISIBLE_GROUPS);

// gets visible infos. However, the information is simplified for invisible items.
ig.getStatus(STATUS.MINIMIZE_INVISIBLE_ITEMS);

// gets visible infos. However, invisible items are removed and only the outline remains.
ig.getStatus(STATUS.MINIMIZE_INVISIBLE_GROUPS);
import { STATUS_TYPE } from "@egjs/infinitegrid";

const status = ig.getStatus(STATUS_TYPE.MINIMIZE_INVISIBLE_ITEMS);
const [startCursor, endCursor] = status.groupManager.itemCursors;
const itemsStatus = items.slice(startCursor, endCursor + 1);

Restore Visible Status with virtual items

Since you got the status for the visible area, replace it with a placeholder to handle the invisible area.

egjs
egjs 0
egjs
egjs 1
egjs
egjs 2
egjs
egjs 3
egjs
egjs 4
egjs
egjs 5
egjs
egjs 6
egjs
egjs 7
egjs
egjs 8
egjs
egjs 9
egjs
egjs 10
egjs
egjs 11
egjs
egjs 12
egjs
egjs 13
egjs
egjs 14
egjs
egjs 15
egjs
egjs 16
egjs
egjs 17
egjs
egjs 18
egjs
egjs 19
egjs
egjs 20
egjs
egjs 21
egjs
egjs 22
egjs
egjs 23
egjs
egjs 24
egjs
egjs 25
egjs
egjs 26
egjs
egjs 27
egjs
egjs 28
egjs
egjs 29
egjs
egjs 30
egjs
egjs 31
egjs
egjs 32
egjs
egjs 33
egjs
egjs 34
egjs
egjs 35
egjs
egjs 36
egjs
egjs 37
egjs
egjs 38
egjs
egjs 39
egjs
egjs 40
egjs
egjs 41
egjs
egjs 42
egjs
egjs 43
egjs
egjs 44
egjs
egjs 45
egjs
egjs 46
egjs
egjs 47
egjs
egjs 48
egjs
egjs 49
<div class="container"></div>
import { MasonryInfiniteGrid } from "@egjs/infinitegrid";

function getItems(nextGroupKey, count) {
const nextItems = [];

for (let i = 0; i < count; ++i) {
const num = nextGroupKey * count + i;
nextItems.push(`<div class="item">
<div class="thumbnail">
<img src="https://naver.github.io/egjs-infinitegrid/assets/image/${(num % 33) + 1}.jpg" alt="egjs" />
</div>
<div class="info">egjs ${num}</div>
</div>`);
}
return nextItems;
}
const ig = new MasonryInfiniteGrid(".container", {
gap: 5,
});

ig.setPlaceholder({
html: `<div class="placeholder"></div>`,
});


ig.on("requestPrepend", e => {
if (e.isVirtual) {
e.wait();
setTimeout(() => {
e.ready();
ig.prepend(getItems(nextGroupKey, 10), nextGroupKey);
}, 200);
}
});
ig.on("requestAppend", e => {
if (e.isVirtual) {
e.wait();
e.currentTarget.appendPlaceholders(5, nextGroupKey);
setTimeout(() => {
e.ready();
ig.append(getItems(nextGroupKey, 10), nextGroupKey);
}, 200);
}
});
ig.renderItems();

Restore Visible Status with virtual items and scroll 0

Since you got the status for the visible area, replace it with a placeholder to handle the invisible area.

Even if you move the scroll to 0 to the invisible area, all items can be restored.

egjs
egjs 0
egjs
egjs 1
egjs
egjs 2
egjs
egjs 3
egjs
egjs 4
egjs
egjs 5
egjs
egjs 6
egjs
egjs 7
egjs
egjs 8
egjs
egjs 9
egjs
egjs 10
egjs
egjs 11
egjs
egjs 12
egjs
egjs 13
egjs
egjs 14
egjs
egjs 15
egjs
egjs 16
egjs
egjs 17
egjs
egjs 18
egjs
egjs 19
egjs
egjs 20
egjs
egjs 21
egjs
egjs 22
egjs
egjs 23
egjs
egjs 24
egjs
egjs 25
egjs
egjs 26
egjs
egjs 27
egjs
egjs 28
egjs
egjs 29
egjs
egjs 30
egjs
egjs 31
egjs
egjs 32
egjs
egjs 33
egjs
egjs 34
egjs
egjs 35
egjs
egjs 36
egjs
egjs 37
egjs
egjs 38
egjs
egjs 39
egjs
egjs 40
egjs
egjs 41
egjs
egjs 42
egjs
egjs 43
egjs
egjs 44
egjs
egjs 45
egjs
egjs 46
egjs
egjs 47
egjs
egjs 48
egjs
egjs 49
egjs
egjs 50
egjs
egjs 51
egjs
egjs 52
egjs
egjs 53
egjs
egjs 54
egjs
egjs 55
egjs
egjs 56
egjs
egjs 57
egjs
egjs 58
egjs
egjs 59
 
<div class="container"></div>
import { MasonryInfiniteGrid } from "@egjs/infinitegrid";

function getItems(nextGroupKey, count) {
const nextItems = [];

for (let i = 0; i < count; ++i) {
const num = nextGroupKey * count + i;
nextItems.push({
groupKey: nextGroupKey,
key: num,
html: `<div class="item">
<div class="thumbnail">
<img src="https://naver.github.io/egjs-infinitegrid/assets/image/${(num % 33) + 1}.jpg" alt="egjs" />
</div>
<div class="info">egjs ${num}</div>
</div>`,
});
}
return nextItems;
}
const ig = new MasonryInfiniteGrid(".container", {
gap: 5,
});

ig.setPlaceholder({
html: `<div class="placeholder"></div>`,
});


ig.on("requestPrepend", e => {
if (e.isVirtual) {
e.wait();
setTimeout(() => {
e.ready();
ig.prepend(e.nextGroupKeys.map(key => getItems(key, 10)).flat());
}, 200);
}
});
ig.on("requestAppend", e => {
if (e.isVirtual) {
e.wait();
e.currentTarget.appendPlaceholders(5, nextGroupKey);
setTimeout(() => {
e.ready();
ig.append(e.nextGroupKeys.map(key => getItems(key, 10)).flat());
}, 200);
}
});
ig.renderItems();

Use Transition

If you want to use transition, use CSS.

.item {
transition: all ease 0.2s;
}
egjs
egjs 0
egjs
egjs 1
egjs
egjs 2
egjs
egjs 3
egjs
egjs 4
egjs
egjs 5
egjs
egjs 6
egjs
egjs 7
egjs
egjs 8
egjs
egjs 9
egjs
egjs 10
egjs
egjs 11
egjs
egjs 12
egjs
egjs 13
egjs
egjs 14
egjs
egjs 15
egjs
egjs 16
egjs
egjs 17
egjs
egjs 18
egjs
egjs 19