MotionRailExtension
Extension plugin interface.
Type Definition
ts
type MotionRailExtension = {
name: string;
onInit?: (motionRail: MotionRail, state: MotionRailState) => void;
onUpdate?: (motionRail: MotionRail, state: MotionRailState) => void;
onDestroy?: (motionRail: MotionRail, state: MotionRailState) => void;
}Properties
name
Unique identifier for the extension.
- Type:
string - Required: Yes
ts
const customExtension: MotionRailExtension = {
name: 'custom-logger'
};onInit
Called once when the carousel is initialized.
- Type:
(motionRail: MotionRail, state: MotionRailState) => void - Optional: Yes
Parameters:
motionRail- The MotionRail instancestate- Current MotionRailState
ts
const customExtension: MotionRailExtension = {
name: 'init-tracker',
onInit: (motionRail, state) => {
console.log('Carousel initialized with', state.totalItems, 'items');
}
};onUpdate
Called whenever the carousel state updates (scroll, resize, content changes).
- Type:
(motionRail: MotionRail, state: MotionRailState) => void - Optional: Yes
Parameters:
motionRail- The MotionRail instancestate- Updated MotionRailState
ts
const customExtension: MotionRailExtension = {
name: 'scroll-tracker',
onUpdate: (motionRail, state) => {
console.log('Visible items:', state.visibleItemIndexes);
}
};onDestroy
Called when the carousel is destroyed for cleanup.
- Type:
(motionRail: MotionRail, state: MotionRailState) => void - Optional: Yes
Parameters:
motionRail- The MotionRail instancestate- Final MotionRailState
ts
const customExtension: MotionRailExtension = {
name: 'cleanup-tracker',
onDestroy: (motionRail, state) => {
console.log('Carousel destroyed');
}
};Lifecycle Order
Extensions follow this lifecycle:
onInit- Carousel initialization (called once)onUpdate- State changes (called multiple times)onDestroy- Carousel cleanup (called once)
ts
const lifecycleExtension: MotionRailExtension = {
name: 'lifecycle-demo',
onInit: (motionRail, state) => {
console.log('1. Init');
},
onUpdate: (motionRail, state) => {
console.log('2. Update (called on scroll, resize, etc.)');
},
onDestroy: (motionRail, state) => {
console.log('3. Destroy');
}
};Usage
Adding Extensions
ts
import { MotionRail } from 'motionrail';
const carousel = new MotionRail(element, {
extensions: [
customExtension1,
customExtension2
]
});Built-in Extensions
ts
import { Arrows } from 'motionrail/extensions/arrows';
import { Dots } from 'motionrail/extensions/dots';
import { Thumbnails } from 'motionrail/extensions/thumbnails';
import { Logger } from 'motionrail/extensions/logger';
const carousel = new MotionRail(element, {
extensions: [
Arrows(),
Dots({ dotSize: 48 }),
Thumbnails(),
Logger()
]
});See Extensions Overview for built-in extensions.
Examples
Simple Logger
ts
const logger: MotionRailExtension = {
name: 'simple-logger',
onInit: (motionRail, state) => {
console.log('Initialized');
},
onUpdate: (motionRail, state) => {
console.log('State updated:', state);
},
onDestroy: (motionRail, state) => {
console.log('Destroyed');
}
};Counter Display
ts
const counter: MotionRailExtension = {
name: 'counter',
onUpdate: (motionRail, state) => {
const counterEl = document.querySelector('.counter');
if (counterEl) {
const current = state.visibleItemIndexes[0] + 1;
counterEl.textContent = `${current} / ${state.totalItems}`;
}
}
};Custom Controls
ts
const customControls: MotionRailExtension = {
name: 'custom-controls',
onInit: (motionRail, state) => {
const prevBtn = document.querySelector('.my-prev');
const nextBtn = document.querySelector('.my-next');
prevBtn?.addEventListener('click', () => motionRail.prev());
nextBtn?.addEventListener('click', () => motionRail.next());
},
onUpdate: (motionRail, state) => {
const prevBtn = document.querySelector('.my-prev') as HTMLButtonElement;
const nextBtn = document.querySelector('.my-next') as HTMLButtonElement;
if (prevBtn) prevBtn.disabled = state.isFirstItemVisible;
if (nextBtn) nextBtn.disabled = state.isLastItemVisible;
}
};Progress Bar
ts
const progressBar: MotionRailExtension = {
name: 'progress-bar',
onInit: (motionRail, state) => {
const container = motionRail.getOptions();
const progressEl = document.createElement('div');
progressEl.className = 'progress-bar';
progressEl.style.cssText = 'height: 4px; background: #ccc; position: relative;';
const bar = document.createElement('div');
bar.className = 'progress-bar-fill';
bar.style.cssText = 'height: 100%; background: #007bff; width: 0; transition: width 0.3s;';
progressEl.appendChild(bar);
// Insert progress bar before carousel
},
onUpdate: (motionRail, state) => {
const bar = document.querySelector('.progress-bar-fill') as HTMLElement;
if (bar && state.totalItems > 0) {
const progress = ((state.visibleItemIndexes[0] + 1) / state.totalItems) * 100;
bar.style.width = `${progress}%`;
}
}
};Keyboard Navigation
ts
const keyboardNav: MotionRailExtension = {
name: 'keyboard-navigation',
onInit: (motionRail, state) => {
const handleKeydown = (e: KeyboardEvent) => {
if (e.key === 'ArrowLeft') motionRail.prev();
if (e.key === 'ArrowRight') motionRail.next();
};
document.addEventListener('keydown', handleKeydown);
// Store for cleanup
(motionRail as any)._keyboardHandler = handleKeydown;
},
onDestroy: (motionRail, state) => {
const handler = (motionRail as any)._keyboardHandler;
if (handler) {
document.removeEventListener('keydown', handler);
}
}
};External State Sync
ts
const stateSync: MotionRailExtension = {
name: 'state-sync',
onUpdate: (motionRail, state) => {
// Sync to external state management (Redux, Vuex, etc.)
window.dispatchEvent(new CustomEvent('carousel-state-change', {
detail: state
}));
}
};TypeScript Support
Full TypeScript support with type checking:
ts
import { MotionRail } from 'motionrail';
import type { MotionRailExtension, MotionRailState } from 'motionrail';
const typedExtension: MotionRailExtension = {
name: 'typed-extension',
onInit: (motionRail: MotionRail, state: MotionRailState) => {
// Full type checking and autocomplete
console.log(state.totalItems);
motionRail.play();
}
};Next Steps
- Creating Custom Extensions - Detailed guide
- Built-in Extensions - Arrows, Dots, Thumbnails, Logger
- MotionRail Class
- MotionRailState