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);
};