Skip to main content

Cross Flicking

CrossFlicking is a preset class that combines a horizontal and vertical Flicking into a single 2D carousel. Swipe horizontally to switch between groups and vertically to browse items within a group.

import { CrossFlicking } from "@egjs/flicking";
import "@egjs/flicking/dist/flicking.css";
import "./styles.css";

// The panel structure lives in index.html; attaching CrossFlicking is all that's needed.
new CrossFlicking("#cross", {
  align: "prev",
  moveType: "strict",
  bound: true,
  sideOptions: { moveType: "strict", bound: true }
});

Summary

Key Options

OptionTypeDefaultDescription
sideOptionsPartial<FlickingOptions>{}Options applied to the auto-created vertical (side) Flicking instances
preserveIndexbooleantrueKeep each group's own side index when switching groups
disableSlideOnHoldbooleantrueLock the perpendicular axis while dragging one direction
disableIndexSyncbooleanfalseDisable automatic index synchronization between main/side

CrossFlicking also accepts every FlickingOptions (e.g. moveType, bound) which apply to the horizontal main axis.

Structure

LevelDirectionRole
Main Flicking (CrossFlicking)Horizontal (↔)Navigation between groups
Side Flicking (auto-created)Vertical (↕)Navigation within a group

Each group is a direct child of the camera — a wrapper <div> whose children become the vertical side panels.

Details

How CrossFlicking Works

CrossFlicking reads the group structure from the DOM at initialization, then rebuilds each group into an independent vertical Flicking. The outer instance handles horizontal movement between groups, while each group manages its own vertical movement — producing a grid-like 2D navigation from a single class.

Authoring per Framework

Across all frameworks the demo drives the core CrossFlicking class imperatively: group the panels with a wrapper <div> and pass the viewport element to the constructor.

import { CrossFlicking } from "@egjs/flicking"; // or "@egjs/vue3-flicking"

new CrossFlicking("#cross", {
align: "prev",
moveType: "strict",
bound: true,
sideOptions: { moveType: "strict", bound: true }
});
<div id="cross" class="flicking-viewport">
<div class="flicking-camera">
<div><!-- group: Nature -->
<div class="cross-panel">Forest</div>
<div class="cross-panel">Meadow</div>
</div>
<div><!-- group: Ocean -->
<div class="cross-panel">Reef</div>
<div class="cross-panel">Wave</div>
</div>
</div>
</div>
React / Vue

@egjs/react-flicking also exports CrossFlicking/CrossGroup components, but they currently break under React StrictMode (the instance is destroyed before its async init completes). Until that is fixed, drive the core class from useEffect/onMounted as this demo does. Vue3 has no dedicated wrapper, so the core class is the only option there.

Events

Main-axis events (changed, willChange) carry an extra sideIndex field pointing to the active group's side index. Side-axis events are prefixed with side and carry mainIndex to identify which group moved.

EventPayloadDescription
changed{ index, sideIndex }The horizontal (group) index changed
sideChanged{ index, mainIndex }A group's vertical (item) index changed
sideWillChange{ index, mainIndex }A group's vertical index is about to change
  • Combination with moveType: "strict": Moves exactly one group/item per swipe for clear grid navigation.
  • Combination with bound: true: Prevents empty space at the edges of both axes.
  • sideOptions: Configure the vertical instances independently from the horizontal one.

Use Cases

When should you use this?
  • Category-based galleries (horizontal for categories, vertical for items)
  • Story/reel viewers (horizontal for authors, vertical for posts)
  • Dashboards (horizontal for sections, vertical for cards)

Notes

Caution
  • Give the viewport an explicit height, since the vertical side instances need a fixed layout height.
  • CrossFlicking rebuilds the group DOM on initialization; author groups as wrapper elements rather than expecting the original markup to remain unchanged.
  • Vue has no CrossFlicking/CrossGroup component wrapper — use the core class through ref + onMounted, and call destroy() on unmount.
  • Nested: On/off comparison of the nested option for same-direction nesting
  • Fullpage Scroll: Vertical fullpage pattern