Skip to main content

Infinite Scroll

Implement infinite scroll using the needPanelThreshold option and the needPanel event.

import Flicking from "@egjs/flicking";
import "@egjs/flicking/dist/flicking.css";
import "./styles.css";

const COLORS = ["#3e8ed0", "#00d1b2", "#f14668", "#ffe08a", "#48c78e", "#9c27b0", "#ff5722"];
let nextId = 5;

const flicking = new Flicking("#flick", {
  align: "prev",
  needPanelThreshold: 100
});

function addLog(message) {
  const logEl = document.getElementById("event-log");
  const div = document.createElement("div");
  div.textContent = message;
  logEl.appendChild(div);
  // Keep only last 5 entries
  while (logEl.children.length > 5) {
    logEl.removeChild(logEl.firstChild);
  }
}

function updateCounter() {
  const count = flicking.panelCount;
  document.getElementById("panel-count").textContent = count;
}

flicking.on("needPanel", e => {
  addLog(`needPanel: direction=${e.direction}`);

  if (e.direction === "NEXT") {
    // NEXT: append panels
    const newPanels = [];
    for (let i = 0; i < 3; i++) {
      const panel = document.createElement("div");
      panel.className = "flicking-panel";
      panel.style.background = COLORS[nextId % COLORS.length];
      panel.textContent = `Panel ${nextId + 1}`;
      newPanels.push(panel);
      nextId++;
    }
    flicking.append(newPanels);
    addLog(`Added: Panel ${nextId - 3}, ${nextId - 2}, ${nextId - 1}`);
    updateCounter();
  }
});

flicking.on("ready", updateCounter);

Summary

Key Options

OptionTypeDefaultDescription
needPanelThresholdnumber0Threshold for triggering the needPanel event (px)
EventDescription
needPanelFired when empty space is visible at the viewport edge

Threshold Comparison

needPanelThresholdBehavior
0 (default)Event fires only when the end is fully reached
100Event fires 100px before the end (preloading)
200Event fires 200px before the end

Details

How It Works

  1. Scroll approaches the viewport edge
  2. When within the needPanelThreshold distance, the needPanel event fires
  3. Add new panels in the event handler
  4. Scrolling can continue
<Flicking
needPanelThreshold={100}
onNeedPanel={(e) => {
if (e.direction === "NEXT") {
// Append panels
setPanels(prev => [...prev, newPanel]);
}
}}
>
{panels.map(p => <Panel key={p.id} />)}
</Flicking>

needPanel Event

interface NeedPanelEvent {
direction: "PREV" | "NEXT";
}
  • Use direction to determine which direction needs panels
  • "PREV": Panels needed at the front (prepend)
  • "NEXT": Panels needed at the end (append)

Adding Panels in Vanilla JS

flicking.on("needPanel", (e) => {
if (e.direction === "NEXT") {
const newPanel = document.createElement("div");
newPanel.className = "flicking-panel";
newPanel.textContent = "New Panel";
flicking.append(newPanel);
}
});

Use Cases

When should you use needPanelThreshold?

Recommended:

  • Infinite scroll implementation
  • Pagination (load next page when reaching the end)
  • Progressive loading of large datasets

Appropriate threshold values:

  • 0: When the end must be exactly reached
  • 100~200: Typical preloading
  • Viewport width or more: Very aggressive preloading

Notes

Duplicate Event Firing

The needPanel event may fire again while panels are being added. Manage loading state to prevent duplicate requests.

const [isLoading, setIsLoading] = useState(false);

const handleNeedPanel = async (e) => {
if (isLoading) return; // Prevent duplicates
setIsLoading(true);

await loadMorePanels();

setIsLoading(false);
};