or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

core-scrolling.mdevents.mdfeatures.mdindex.md
tile.json

events.mddocs/

Events

Comprehensive event system for tracking scroll state, user interactions, and lifecycle events. Better Scroll uses a custom event emitter pattern that allows you to listen for various scroll-related events throughout the interaction lifecycle.

Capabilities

Event Management Methods

on

Registers an event listener for the specified event type.

/**
 * Register an event listener
 * @param type - Event type name
 * @param fn - Event handler function
 * @param context - Context for 'this' in handler (default: BScroll instance)
 */
on(type: string, fn: Function, context?: any): void;

once

Registers a one-time event listener that automatically removes itself after first execution.

/**
 * Register a one-time event listener
 * @param type - Event type name  
 * @param fn - Event handler function
 * @param context - Context for 'this' in handler (default: BScroll instance)
 */
once(type: string, fn: Function, context?: any): void;

off

Removes an event listener for the specified event type.

/**
 * Remove an event listener
 * @param type - Event type name
 * @param fn - Event handler function to remove
 */
off(type: string, fn: Function): void;

Usage Examples:

import BScroll from "better-scroll";

const scroll = new BScroll('.wrapper');

// Register event listeners
scroll.on('scroll', handleScroll);
scroll.on('scrollEnd', handleScrollEnd);

// One-time listener
scroll.once('scrollStart', () => {
  console.log('First scroll started!');
});

// Remove listener
scroll.off('scroll', handleScroll);

function handleScroll(position) {
  console.log(`Scrolling to: ${position.x}, ${position.y}`);
}

function handleScrollEnd(position) {
  console.log(`Scroll ended at: ${position.x}, ${position.y}`);
}

Core Events

Scroll Lifecycle Events

scroll

Fired during scrolling with current position coordinates.

// Event: 'scroll'
// Payload: {x: number, y: number}
// Fired: During scrolling movement (frequency depends on probeType)

Usage:

scroll.on('scroll', (position) => {
  console.log(`Current position: ${position.x}, ${position.y}`);
  
  // Update scroll indicator
  updateScrollIndicator(position.y);
  
  // Parallax effects
  updateParallaxElements(position.y);
});

scrollStart

Fired when scrolling begins, before any movement occurs.

// Event: 'scrollStart'
// Payload: none
// Fired: When user starts scroll gesture

beforeScrollStart

Fired before scrolling starts, earliest in the scroll lifecycle.

// Event: 'beforeScrollStart'  
// Payload: none
// Fired: Before scroll gesture processing begins

scrollEnd

Fired when scrolling animation completes and comes to rest.

// Event: 'scrollEnd'
// Payload: {x: number, y: number}
// Fired: When scrolling animation finishes

Usage Example:

scroll.on('scrollStart', () => {
  // Hide UI elements during scroll
  hideFloatingButton();
});

scroll.on('scrollEnd', (position) => {
  // Show UI elements when scroll stops
  showFloatingButton();
  
  // Save scroll position
  saveScrollPosition(position);
  
  // Load more content if near bottom
  if (isNearBottom(position.y)) {
    loadMoreContent();
  }
});

Touch & Interaction Events

touchEnd

Fired when user lifts finger/releases mouse, regardless of whether scrolling will continue.

// Event: 'touchEnd'
// Payload: {x: number, y: number}
// Fired: On touch/mouse up event

flick

Fired when user performs a quick flick gesture.

// Event: 'flick'
// Payload: none
// Fired: When flick gesture is detected (based on flickLimitTime and flickLimitDistance)

scrollCancel

Fired when a scroll operation is canceled (e.g., when a click is detected instead of scroll).

// Event: 'scrollCancel'
// Payload: none  
// Fired: When scroll is canceled due to click detection

Usage Examples:

// Handle touch end for custom logic
scroll.on('touchEnd', (position) => {
  // Check if user scrolled past certain point
  if (position.y < -triggerThreshold) {
    triggerRefresh();
  }
});

// Handle flick gestures
scroll.on('flick', () => {
  // Custom flick behavior
  console.log('User performed a flick gesture');
});

System Events

refresh

Fired after the refresh() method completes recalculation.

// Event: 'refresh'
// Payload: none
// Fired: After refresh() method completes

destroy

Fired when the BScroll instance is destroyed.

// Event: 'destroy'
// Payload: none
// Fired: When destroy() method is called

Usage Examples:

scroll.on('refresh', () => {
  // Update custom UI after dimensions recalculated
  updateCustomScrollbar();
});

scroll.on('destroy', () => {
  // Clean up custom resources
  cleanupCustomElements();
  removeCustomEventListeners();
});

Feature-Specific Events

Pull-to-Refresh Events

When pull-to-refresh is enabled, additional events are available:

// Event: 'pullingDown'
// Payload: none
// Fired: When pull-down threshold is reached
// Required: options.pullDownRefresh = true

// Event: 'pullingUp' 
// Payload: none
// Fired: When pull-up threshold is reached  
// Required: options.pullUpLoad = true

Usage:

const scroll = new BScroll('.wrapper', {
  pullDownRefresh: {
    threshold: 50,
    stop: 20
  },
  pullUpLoad: {
    threshold: 50
  }
});

scroll.on('pullingDown', () => {
  // Show loading indicator and refresh data
  showRefreshLoader();
  fetchNewData().then(() => {
    scroll.finishPullDown();
  });
});

scroll.on('pullingUp', () => {
  // Load more data
  showLoadMoreIndicator();
  fetchMoreData().then(() => {
    scroll.finishPullUp();
  });
});

Event Timing & Probe Types

The frequency of scroll events depends on the probeType option:

interface ProbeTypeConfiguration {
  probeType: 0 | 1 | 2 | 3;
}

// probeType: 0 - No scroll events during animation
// probeType: 1 - Non-real-time scroll events (debounced)
// probeType: 2 - Real-time scroll events during momentum only
// probeType: 3 - Real-time scroll events always (including animations)

Usage Examples:

// For basic scroll position tracking
const scroll = new BScroll('.wrapper', {
  probeType: 1
});

// For smooth scroll indicators  
const scroll = new BScroll('.wrapper', {
  probeType: 2
});

// For real-time parallax effects
const scroll = new BScroll('.wrapper', {
  probeType: 3
});

Event-Driven Patterns

Scroll Position Tracking

class ScrollTracker {
  constructor(scrollInstance) {
    this.scroll = scrollInstance;
    this.setupEventListeners();
  }
  
  setupEventListeners() {
    this.scroll.on('scroll', this.updatePosition.bind(this));
    this.scroll.on('scrollEnd', this.savePosition.bind(this));
  }
  
  updatePosition(pos) {
    // Update scroll indicator
    const percentage = Math.abs(pos.y) / Math.abs(this.scroll.maxScrollY);
    this.updateScrollbar(percentage);
  }
  
  savePosition(pos) {
    // Persist scroll position
    localStorage.setItem('scrollPosition', JSON.stringify(pos));
  }
}

Infinite Scroll Implementation

class InfiniteScroll {
  constructor(scrollInstance, threshold = 100) {
    this.scroll = scrollInstance;
    this.threshold = threshold;
    this.loading = false;
    
    this.scroll.on('scroll', this.checkLoadMore.bind(this));
  }
  
  checkLoadMore(pos) {
    if (this.loading) return;
    
    const bottom = Math.abs(pos.y);
    const maxScroll = Math.abs(this.scroll.maxScrollY);
    
    if (bottom + this.threshold >= maxScroll) {
      this.loadMore();
    }
  }
  
  async loadMore() {
    this.loading = true;
    try {
      await this.fetchMoreData();
      this.scroll.refresh(); // Recalculate boundaries
    } finally {
      this.loading = false;
    }
  }
}

Custom Animation Triggers

const scroll = new BScroll('.wrapper', {
  probeType: 3
});

scroll.on('scroll', (pos) => {
  // Parallax background
  const parallaxElement = document.querySelector('.parallax-bg');
  const parallaxSpeed = 0.5;
  const translateY = pos.y * parallaxSpeed;
  parallaxElement.style.transform = `translateY(${translateY}px)`;
  
  // Fade header based on scroll
  const header = document.querySelector('.header');
  const opacity = Math.max(0, 1 - Math.abs(pos.y) / 200);
  header.style.opacity = opacity;
});