GL Carousel Banner
Version: 1.0.9 Package:
@gift-card-market/gl-carousel-banner
Last Updated: July 1, 2026
📖 Table of Contents
- Overview
- Installation
- Quick Start
- API Reference
- Data Structure
- Configuration Options
- Methods & Controls
- Events
- Styling & Customization
- Advanced Examples
- Troubleshooting
🎯 Overview
GL Carousel Banner is a versatile, high-performance carousel component designed for the Gift Card Marketplace. It supports both React and Vanilla JavaScript implementations, making it framework-agnostic and easy to integrate into any project.
Key Features
✅ Dual Implementation - React component & Web Component (Vanilla JS)
✅ Auto-rotation - Configurable automatic slide transitions
✅ Smooth Animations - Customizable transition speeds
✅ Pause on Hover - User-friendly interaction
✅ Programmatic Control - Full API for slide navigation
✅ Event System - Listen to slide changes
✅ Responsive Design - Mobile-friendly and adaptive
✅ TypeScript Support - Full type definitions included
✅ Customizable Styling - CSS variables for theming
📦 Installation
From GitHub Packages
First, configure npm to use GitHub Packages for @gift-card-market scope:
# Create or edit .npmrc in your project root
echo "@gift-card-market:registry=https://npm.pkg.github.com" >> .npmrc
Then install the package:
npm install @gift-card-market/gl-carousel-banner
Peer Dependencies
This package requires React as a peer dependency:
npm install react react-dom
🚀 Quick Start
React Implementation
1. Install Required Dependencies
npm install react react-dom
npm install slick-carousel
2. Import Styles
import '@gift-card-market/gl-carousel-banner/style.css';
import 'slick-carousel/slick/slick.css';
import 'slick-carousel/slick/slick-theme.css';
3. Import Component and Types
import {
GlCarouselBanner,
CarouselBannerEvents,
type GlCarouselBannerHandle,
type GlCarouselBannerItem
} from "@gift-card-market/gl-carousel-banner";
4. Basic Usage Example
import { useRef, useState } from 'react';
import {
GlCarouselBanner,
type GlCarouselBannerHandle,
type GlCarouselBannerItem
} from "@gift-card-market/gl-carousel-banner";
import '@gift-card-market/gl-carousel-banner/style.css';
import 'slick-carousel/slick/slick.css';
import 'slick-carousel/slick/slick-theme.css';
function App() {
const carouselRef = useRef<GlCarouselBannerHandle>(null);
const [currentSlide, setCurrentSlide] = useState(0);
// Sample data
const slides: GlCarouselBannerItem[] = [
{
title_text: 'Welcome to <strong>Our Store</strong>',
title_text_emphasis_color: '#FF6600',
main_text: '<p>Discover amazing products and services</p>',
button_text: 'Shop Now',
button_color: '#0052CC',
button_text_color: '#FFFFFF',
button_link: 'https://example.com/shop',
background_image: 'https://example.com/bg1.svg',
main_image: 'https://example.com/product1.png',
main_image_link: 'https://example.com/product1'
},
{
title_text: 'Special <strong><em>Offer</em></strong>',
main_text: '<p>Get 50% off on selected items</p>',
button_text: 'Learn More',
button_color: '#EE3D84',
button_text_color: '#FFFFFF',
button_link: 'https://example.com/offers',
background_image: 'https://example.com/bg2.svg',
main_image: 'https://example.com/offer.png'
}
];
// Control handlers
const handleNext = () => {
carouselRef.current?.nextSlide();
};
const handlePrevious = () => {
carouselRef.current?.previousSlide();
};
const handleGoToSlide = (index: number) => {
carouselRef.current?.goToSlide(index);
};
return (
<div>
<GlCarouselBanner
ref={carouselRef}
items={slides}
autoRotate={true}
rotationSpeed={3}
transitionSpeed={0.5}
pauseOnHover={true}
/>
<div style={{ marginTop: '20px', textAlign: 'center' }}>
<button onClick={handlePrevious}>Previous</button>
<button onClick={handleNext}>Next</button>
<button onClick={() => handleGoToSlide(0)}>Go to First</button>
</div>
</div>
);
}
export default App;
Vanilla JavaScript Implementation
1. Include Scripts and Styles
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>GL Carousel Banner Demo</title>
<!-- Include CSS -->
<link rel="stylesheet"
href="./node_modules/@gift-card-market/gl-carousel-banner/dist/browser/gl-carousel-banner.css">
</head>
<body>
<div id="carousel-container"></div>
<!-- Include JS -->
<script src="./node_modules/@gift-card-market/gl-carousel-banner/dist/browser/gl-carousel-banner.global.js"></script>
<script type="module">
// Your code here
</script>
</body>
</html>
2. Basic Usage Example
<script type="module">
// Sample data
const carouselData = [
{
title_text: 'Welcome to <strong>Our Store</strong>',
title_text_emphasis_color: '#FF6600',
main_text: '<p>Discover amazing products and services</p>',
button_text: 'Shop Now',
button_color: '#0052CC',
button_text_color: '#FFFFFF',
button_link: 'https://example.com/shop',
background_image: 'https://example.com/bg1.svg',
main_image: 'https://example.com/product1.png',
main_image_link: 'https://example.com/product1'
},
{
title_text: 'Special <strong><em>Offer</em></strong>',
main_text: '<p>Get 50% off on selected items</p>',
button_text: 'Learn More',
button_color: '#EE3D84',
button_text_color: '#FFFFFF',
button_link: 'https://example.com/offers',
background_image: 'https://example.com/bg2.svg',
main_image: 'https://example.com/offer.png'
}
];
// Create carousel element
const carousel = document.createElement('gl-carousel-banner');
// Set attributes
carousel.setAttribute('autoRotate', 'true');
carousel.setAttribute('rotationSpeed', '3');
carousel.setAttribute('transitionSpeed', '0.5');
carousel.setAttribute('pauseOnHover', 'true');
// Append to container
document.getElementById('carousel-container').appendChild(carousel);
// Wait for component to be defined, then set items
customElements.whenDefined('gl-carousel-banner').then(() => {
// Set items as property
carousel.items = carouselData;
console.log('✅ Carousel initialized successfully!');
});
</script>
3. Advanced Vanilla JS Example with Controls
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>GL Carousel Banner - Full Example</title>
<link rel="stylesheet"
href="./node_modules/@gift-card-market/gl-carousel-banner/dist/browser/gl-carousel-banner.css">
<style>
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
max-width: 1200px;
margin: 0 auto;
padding: 20px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
}
.controls {
display: flex;
gap: 10px;
justify-content: center;
margin: 20px 0;
}
button {
padding: 10px 20px;
background: white;
border: none;
border-radius: 8px;
cursor: pointer;
font-weight: 600;
transition: transform 0.2s;
}
button:hover {
transform: scale(1.05);
}
.info-box {
background: white;
padding: 20px;
border-radius: 12px;
margin-top: 20px;
text-align: center;
}
</style>
</head>
<body>
<h1 style="color: white; text-align: center;">GL Carousel Banner Demo</h1>
<div class="controls">
<button id="prevBtn">⬅️ Previous</button>
<button id="pauseBtn">⏸️ Pause</button>
<button id="resumeBtn">▶️ Resume</button>
<button id="nextBtn">Next ➡️</button>
</div>
<div id="carousel-container"></div>
<div class="info-box">
<p>Current Slide: <strong id="currentSlide">1</strong></p>
</div>
<script src="./node_modules/@gift-card-market/gl-carousel-banner/dist/browser/gl-carousel-banner.global.js"></script>
<script type="module">
const carouselData = [
{
title_text: 'Slide 1: <strong>Welcome</strong>',
main_text: '<p>This is the first slide</p>',
button_text: 'Get Started',
button_color: '#0052CC',
button_text_color: '#FFFFFF',
button_link: '#',
background_image: 'https://example.com/bg1.svg',
main_image: 'https://example.com/image1.png'
},
{
title_text: 'Slide 2: <strong>Features</strong>',
main_text: '<p>Explore amazing features</p>',
button_text: 'Learn More',
button_color: '#EE3D84',
button_text_color: '#FFFFFF',
button_link: '#',
background_image: 'https://example.com/bg2.svg',
main_image: 'https://example.com/image2.png'
},
{
title_text: 'Slide 3: <strong>Contact</strong>',
main_text: '<p>Get in touch with us</p>',
button_text: 'Contact Us',
button_color: '#FFE606',
button_text_color: '#183238',
button_link: '#',
background_image: 'https://example.com/bg3.svg',
main_image: 'https://example.com/image3.png'
}
];
const carousel = document.createElement('gl-carousel-banner');
carousel.setAttribute('autoRotate', 'true');
carousel.setAttribute('rotationSpeed', '3');
carousel.setAttribute('transitionSpeed', '0.5');
carousel.setAttribute('pauseOnHover', 'true');
document.getElementById('carousel-container').appendChild(carousel);
customElements.whenDefined('gl-carousel-banner').then(() => {
carousel.items = carouselData;
// Setup event listeners after a small delay
setTimeout(() => {
document.getElementById('prevBtn').addEventListener('click', () => {
carousel.previousSlide();
updateCurrentSlide();
});
document.getElementById('nextBtn').addEventListener('click', () => {
carousel.nextSlide();
updateCurrentSlide();
});
document.getElementById('pauseBtn').addEventListener('click', () => {
carousel.pause();
});
document.getElementById('resumeBtn').addEventListener('click', () => {
carousel.resume();
});
}, 200);
});
function updateCurrentSlide() {
const current = carousel.getCurrentSlide();
if (current !== undefined) {
document.getElementById('currentSlide').textContent = current + 1;
}
}
// Update current slide periodically
setInterval(updateCurrentSlide, 200);
// Listen to slide change events
carousel.addEventListener('slideChange', (event) => {
console.log('Slide changed to:', event.detail);
document.getElementById('currentSlide').textContent = event.detail + 1;
});
// Make carousel available in console for testing
window.carousel = carousel;
</script>
</body>
</html>
📚 API Reference
Exports
The package exports the following:
import {
GlCarouselBanner, // React Component
CarouselBannerEvents, // Event name constants
type GlCarouselBannerHandle, // Type for ref
type GlCarouselBannerItem // Type for slide data
} from "@gift-card-market/gl-carousel-banner";
CarouselBannerEvents Object
Event name constants for listening to carousel events:
CarouselBannerEvents = {
CAROUSEL_LOADED: "gl:carousel-loaded",
SLIDE_CHANGED: "gl:slide-changed",
CAROUSEL_PAUSED: "gl:carousel-paused",
CAROUSEL_RESUMED: "gl:carousel-resumed",
ERROR: "gl:error"
}
See Events section for detailed usage.
React Props
| Prop | Type | Default | Description |
|---|---|---|---|
items | GlCarouselBannerItem[] | Required | Array of carousel slide data |
autoRotate | boolean | true | Enable/disable automatic slide rotation |
rotationSpeed | number | 3 | Time in seconds between auto-rotations |
transitionSpeed | number | 0.5 | Transition animation duration in seconds |
pauseOnHover | boolean | true | Pause auto-rotation when hovering |
ref | GlCarouselBannerHandle | - | Reference for programmatic control |
Vanilla JS Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
autoRotate | string | "true" | Enable/disable automatic rotation ("true" or "false") |
rotationSpeed | string | "3" | Time in seconds between rotations |
transitionSpeed | string | "0.5" | Transition duration in seconds |
pauseOnHover | string | "true" | Pause on hover ("true" or "false") |
Note: For Vanilla JS, set the items property directly (not as an attribute):
carousel.items = arrayOfItems;
🗂️ Data Structure
GlCarouselBannerItem Interface
interface GlCarouselBannerItem {
// Title
title_text: string; // HTML string for title (supports <strong>, <em>)
title_text_emphasis_color?: string; // Color for emphasized text (e.g., '#FF6600')
// Main Content
main_text: string | string[]; // HTML string or array of strings for content
// Button (Call-to-Action)
button_text: string; // Button text
button_color?: string; // Button background color (e.g., '#0052CC')
button_text_color?: string; // Button text color (e.g., '#FFFFFF')
button_link: string; // Button URL
// Images
background_image?: string; // URL for background image/pattern
main_image?: string; // URL for main slide image
main_image_link?: string; // URL when clicking main image
}
Example Data Object
const slideData = {
title_text: 'How <strong><em>local</em> gift cards</strong> work',
title_text_emphasis_color: '#FF6600',
main_text: [
'<strong>Search</strong> for local businesses',
'<strong>Choose</strong> the amount',
'<strong>Send</strong> instantly by email'
],
button_text: 'Get Started',
button_color: '#0052CC',
button_text_color: '#FFFFFF',
button_link: 'https://example.com/start',
background_image: 'https://example.com/pattern.svg',
main_image: 'https://example.com/hero.png',
main_image_link: 'https://example.com/details'
};
⚙️ Configuration Options
Auto-Rotation Settings
// React
<GlCarouselBanner
autoRotate={true} // Enable auto-rotation
rotationSpeed={5} // Rotate every 5 seconds
pauseOnHover={true} // Pause when user hovers
items={slides}
/>
// Vanilla JS
carousel.setAttribute('autoRotate', 'true');
carousel.setAttribute('rotationSpeed', '5');
carousel.setAttribute('pauseOnHover', 'true');
Transition Settings
// React
<GlCarouselBanner
transitionSpeed={0.8} // Slower transitions (0.8 seconds)
items={slides}
/>
// Vanilla JS
carousel.setAttribute('transitionSpeed', '0.8');
Disable Auto-Rotation
// React
<GlCarouselBanner
autoRotate={false} // Manual control only
items={slides}
/>
// Vanilla JS
carousel.setAttribute('autoRotate', 'false');
🎮 Methods & Controls
React (via ref)
const carouselRef = useRef<GlCarouselBannerHandle>(null);
// Navigate to next slide
carouselRef.current?.nextSlide();
// Navigate to previous slide
carouselRef.current?.previousSlide();
// Go to specific slide (0-indexed)
carouselRef.current?.goToSlide(2);
// Pause auto-rotation
carouselRef.current?.pause();
// Resume auto-rotation
carouselRef.current?.resume();
// Get current slide index
const currentIndex = carouselRef.current?.getCurrentSlide();
Vanilla JavaScript
// Navigate to next slide
carousel.nextSlide();
// Navigate to previous slide
carousel.previousSlide();
// Go to specific slide (0-indexed)
carousel.goToSlide(2);
// Pause auto-rotation
carousel.pause();
// Resume auto-rotation
carousel.resume();
// Get current slide index
const currentIndex = carousel.getCurrentSlide();
Method Reference
| Method | Parameters | Returns | Description |
|---|---|---|---|
nextSlide() | - | void | Move to the next slide |
previousSlide() | - | void | Move to the previous slide |
goToSlide(index) | index: number | void | Jump to specific slide (0-indexed) |
pause() | - | void | Pause auto-rotation |
resume() | - | void | Resume auto-rotation |
getCurrentSlide() | - | number | undefined | Get current slide index |
📡 Events
The carousel component emits custom events that you can listen to for various lifecycle events and state changes.
CarouselBannerEvents Constants
The package exports a CarouselBannerEvents object containing all available event names:
import { CarouselBannerEvents } from "@gift-card-market/gl-carousel-banner";
// Event names:
CarouselBannerEvents.CAROUSEL_LOADED // "gl:carousel-loaded"
CarouselBannerEvents.SLIDE_CHANGED // "gl:slide-changed"
CarouselBannerEvents.CAROUSEL_PAUSED // "gl:carousel-paused"
CarouselBannerEvents.CAROUSEL_RESUMED // "gl:carousel-resumed"
CarouselBannerEvents.ERROR // "gl:error"
Available Events
| Event Name | Event Type | Detail Object | Description |
|---|---|---|---|
gl:carousel-loaded | CustomEvent | { slideCount: number } | Fired when carousel is initialized and ready |
gl:slide-changed | CustomEvent | { slideIndex: number, direction: 'next' | 'previous' } | Fired whenever the active slide changes |
gl:carousel-paused | CustomEvent | {} | Fired when auto-rotation is paused |
gl:carousel-resumed | CustomEvent | {} | Fired when auto-rotation is resumed |
gl:error | CustomEvent | { error: string } | Fired when an error occurs |
Event Usage Examples
1. Carousel Loaded Event
Listen for when the carousel finishes initialization:
document.addEventListener('gl:carousel-loaded', (event) => {
console.log('✅ Carousel loaded with', event.detail.slideCount, 'slides');
// Initialize custom UI or analytics
});
// Or use the constant:
import { CarouselBannerEvents } from "@gift-card-market/gl-carousel-banner";
document.addEventListener(CarouselBannerEvents.CAROUSEL_LOADED, (event) => {
console.log('Carousel ready!', event.detail);
});
2. Slide Changed Event
Track slide changes with direction information:
document.addEventListener('gl:slide-changed', (event) => {
const { slideIndex, direction } = event.detail;
console.log(`Moved to slide ${slideIndex} (${direction})`);
// Update custom UI
document.getElementById('currentSlide').textContent = slideIndex + 1;
// Track analytics
analytics.track('Carousel Slide Changed', {
slide: slideIndex,
direction: direction
});
});
3. Pause/Resume Events
Monitor auto-rotation state:
document.addEventListener('gl:carousel-paused', () => {
console.log('⏸️ Carousel paused');
document.getElementById('status').textContent = 'Paused';
});
document.addEventListener('gl:carousel-resumed', () => {
console.log('▶️ Carousel resumed');
document.getElementById('status').textContent = 'Playing';
});
4. Error Handling
Handle errors gracefully:
document.addEventListener('gl:error', (event) => {
console.error('❌ Carousel error:', event.detail.error);
// Show error to user or log to error tracking service
showNotification('Carousel failed to load', 'error');
});
Complete Event Listener Example
import { CarouselBannerEvents } from "@gift-card-market/gl-carousel-banner";
// Setup all event listeners
function setupCarouselEventListeners() {
// Loaded
document.addEventListener(CarouselBannerEvents.CAROUSEL_LOADED, (event) => {
console.log('🎠 Carousel initialized with', event.detail.slideCount, 'slides');
});
// Slide changed
document.addEventListener(CarouselBannerEvents.SLIDE_CHANGED, (event) => {
const { slideIndex, direction } = event.detail;
console.log(`📍 Slide ${slideIndex + 1} (${direction})`);
updateIndicator(slideIndex);
});
// Paused
document.addEventListener(CarouselBannerEvents.CAROUSEL_PAUSED, () => {
console.log('⏸️ Paused');
document.getElementById('playButton').textContent = 'Play';
});
// Resumed
document.addEventListener(CarouselBannerEvents.CAROUSEL_RESUMED, () => {
console.log('▶️ Playing');
document.getElementById('playButton').textContent = 'Pause';
});
// Error
document.addEventListener(CarouselBannerEvents.ERROR, (event) => {
console.error('❌ Error:', event.detail.error);
showErrorMessage(event.detail.error);
});
}
setupCarouselEventListeners();
React Event Listeners
In React, you can listen to these events using useEffect:
import { useEffect, useState } from 'react';
import { CarouselBannerEvents } from "@gift-card-market/gl-carousel-banner";
function CarouselWithEvents() {
const [slideInfo, setSlideInfo] = useState({ index: 0, total: 0 });
const [isPaused, setIsPaused] = useState(false);
useEffect(() => {
// Carousel loaded handler
const handleLoaded = (event: CustomEvent) => {
setSlideInfo(prev => ({ ...prev, total: event.detail.slideCount }));
console.log('Carousel loaded');
};
// Slide changed handler
const handleSlideChange = (event: CustomEvent) => {
setSlideInfo(prev => ({
...prev,
index: event.detail.slideIndex
}));
console.log('Slide changed to', event.detail.slideIndex);
};
// Pause handler
const handlePause = () => {
setIsPaused(true);
};
// Resume handler
const handleResume = () => {
setIsPaused(false);
};
// Error handler
const handleError = (event: CustomEvent) => {
console.error('Carousel error:', event.detail.error);
};
// Add event listeners
document.addEventListener(CarouselBannerEvents.CAROUSEL_LOADED, handleLoaded as EventListener);
document.addEventListener(CarouselBannerEvents.SLIDE_CHANGED, handleSlideChange as EventListener);
document.addEventListener(CarouselBannerEvents.CAROUSEL_PAUSED, handlePause);
document.addEventListener(CarouselBannerEvents.CAROUSEL_RESUMED, handleResume);
document.addEventListener(CarouselBannerEvents.ERROR, handleError as EventListener);
// Cleanup
return () => {
document.removeEventListener(CarouselBannerEvents.CAROUSEL_LOADED, handleLoaded as EventListener);
document.removeEventListener(CarouselBannerEvents.SLIDE_CHANGED, handleSlideChange as EventListener);
document.removeEventListener(CarouselBannerEvents.CAROUSEL_PAUSED, handlePause);
document.removeEventListener(CarouselBannerEvents.CAROUSEL_RESUMED, handleResume);
document.removeEventListener(CarouselBannerEvents.ERROR, handleError as EventListener);
};
}, []);
return (
<div>
<GlCarouselBanner items={slides} />
<div>
Slide {slideInfo.index + 1} of {slideInfo.total}
{isPaused ? ' (Paused)' : ' (Playing)'}
</div>
</div>
);
}
Event Bubbling
All carousel events use bubbles: true and composed: true, which means:
- Events bubble up through the DOM tree
- Events can cross shadow DOM boundaries
- You can listen on
documentor any parent element
Legacy slideChange Event (Deprecated)
Note: The component still supports the legacy slideChange event on the carousel element itself for backward compatibility, but it's recommended to use the new gl:slide-changed event with CarouselBannerEvents constants instead.
// ❌ Old way (still works, but deprecated)
carousel.addEventListener('slideChange', (event) => {
console.log('Slide:', event.detail);
});
// ✅ New way (recommended)
document.addEventListener(CarouselBannerEvents.SLIDE_CHANGED, (event) => {
console.log('Slide:', event.detail.slideIndex);
});
🎨 Styling & Customization
CSS Variables
You can customize the carousel appearance using CSS variables:
:root {
/* Dot Navigation */
--gl-carousel-dot-color: #cccccc;
--gl-carousel-dot-active-color: #0052cc;
/* Arrow Controls */
--gl-carousel-arrow-color: #000000;
--gl-carousel-arrow-bg: rgba(255, 255, 255, 0.8);
/* Slide Title */
--gl-slide-title-font: 'Arial', sans-serif;
--gl-slide-title-size: 32px;
--gl-slide-title-color: #000000;
/* Slide Text */
--gl-slide-text-font: 'Arial', sans-serif;
--gl-slide-text-size: 18px;
--gl-slide-text-color: #333333;
/* Button */
--gl-button-border-radius: 4px;
/* Layout */
--gl-slide-padding: 40px;
}
Example Customization
:root {
--gl-carousel-dot-active-color: #EE3D84;
--gl-slide-title-size: 40px;
--gl-slide-title-color: #1a1a1a;
--gl-button-border-radius: 24px;
}
Override Specific Styles
/* Custom arrow styling */
gl-carousel-banner .slick-arrow {
background: rgba(0, 82, 204, 0.9) !important;
border-radius: 50%;
}
/* Custom dot styling */
gl-carousel-banner .slick-dots li button:before {
font-size: 14px;
}
🚀 Advanced Examples
Dynamic Data Loading
React
import { useState, useEffect, useRef } from 'react';
import { GlCarouselBanner, type GlCarouselBannerItem } from '@gift-card-market/gl-carousel-banner';
function DynamicCarousel() {
const [slides, setSlides] = useState<GlCarouselBannerItem[]>([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
// Fetch slides from API
fetch('https://api.example.com/carousel-slides')
.then(res => res.json())
.then(data => {
setSlides(data);
setLoading(false);
})
.catch(err => {
console.error('Failed to load slides:', err);
setLoading(false);
});
}, []);
if (loading) {
return <div>Loading carousel...</div>;
}
return (
<GlCarouselBanner
items={slides}
autoRotate={true}
rotationSpeed={4}
/>
);
}
Vanilla JS
// Fetch and render carousel dynamically
async function loadCarousel() {
try {
const response = await fetch('https://api.example.com/carousel-slides');
const slides = await response.json();
const carousel = document.createElement('gl-carousel-banner');
carousel.setAttribute('autoRotate', 'true');
carousel.setAttribute('rotationSpeed', '4');
document.getElementById('carousel-container').appendChild(carousel);
await customElements.whenDefined('gl-carousel-banner');
carousel.items = slides;
console.log('Carousel loaded with', slides.length, 'slides');
} catch (error) {
console.error('Failed to load carousel:', error);
}
}
loadCarousel();
Multiple Carousels on Same Page
function MultiCarouselPage() {
const carousel1Data = [...];
const carousel2Data = [...];
return (
<div>
<section>
<h2>Featured Products</h2>
<GlCarouselBanner
items={carousel1Data}
autoRotate={true}
rotationSpeed={3}
/>
</section>
<section style={{ marginTop: '40px' }}>
<h2>Customer Stories</h2>
<GlCarouselBanner
items={carousel2Data}
autoRotate={true}
rotationSpeed={5}
/>
</section>
</div>
);
}
Controlled Carousel with External Navigation
function ControlledCarousel() {
const carouselRef = useRef<GlCarouselBannerHandle>(null);
const [currentSlide, setCurrentSlide] = useState(0);
const slides: GlCarouselBannerItem[] = [...];
const handleThumbnailClick = (index: number) => {
carouselRef.current?.goToSlide(index);
setCurrentSlide(index);
};
return (
<div>
<GlCarouselBanner
ref={carouselRef}
items={slides}
autoRotate={false}
/>
<div className="thumbnails">
{slides.map((slide, index) => (
<img
key={index}
src={slide.main_image}
onClick={() => handleThumbnailClick(index)}
className={currentSlide === index ? 'active' : ''}
style={{
width: '100px',
cursor: 'pointer',
opacity: currentSlide === index ? 1 : 0.5
}}
/>
))}
</div>
</div>
);
}
Responsive Configuration
function ResponsiveCarousel() {
const [isMobile, setIsMobile] = useState(window.innerWidth < 768);
useEffect(() => {
const handleResize = () => {
setIsMobile(window.innerWidth < 768);
};
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
return (
<GlCarouselBanner
items={slides}
autoRotate={!isMobile} // Disable auto-rotate on mobile
rotationSpeed={isMobile ? 5 : 3} // Slower on mobile
pauseOnHover={!isMobile} // Only on desktop
/>
);
}
🐛 Troubleshooting
Common Issues
1. Carousel Not Rendering (Vanilla JS)
Problem: Carousel appears empty or doesn't render.
Solution: Make sure to wait for the custom element to be defined before setting items:
// ❌ Wrong
const carousel = document.createElement('gl-carousel-banner');
carousel.items = data; // Too early!
document.body.appendChild(carousel);
// ✅ Correct
const carousel = document.createElement('gl-carousel-banner');
document.body.appendChild(carousel);
customElements.whenDefined('gl-carousel-banner').then(() => {
carousel.items = data; // Set items after component is ready
});
2. Methods Not Available (Vanilla JS)
Problem: carousel.nextSlide() throws "not a function" error.
Solution: Wait for component initialization with a small delay:
customElements.whenDefined('gl-carousel-banner').then(() => {
carousel.items = data;
// Wait for React to mount internally
setTimeout(() => {
carousel.nextSlide(); // Now available!
}, 200);
});
3. Styles Not Applied
Problem: Carousel has no styling or looks broken.
Solution: Ensure all CSS files are imported:
// React - Import ALL required styles
import '@gift-card-market/gl-carousel-banner/style.css';
import 'slick-carousel/slick/slick.css';
import 'slick-carousel/slick/slick-theme.css';
<!-- Vanilla JS - Include stylesheet -->
<link rel="stylesheet"
href="./node_modules/@gift-card-market/gl-carousel-banner/dist/browser/gl-carousel-banner.css">
4. TypeScript Errors (React)
Problem: Type errors when using the component.
Solution: Import types explicitly:
import {
GlCarouselBanner,
type GlCarouselBannerHandle,
type GlCarouselBannerItem
} from "@gift-card-market/gl-carousel-banner";
// Use the types
const carouselRef = useRef<GlCarouselBannerHandle>(null);
const slides: GlCarouselBannerItem[] = [...];
5. Auto-Rotation Not Working
Problem: Carousel doesn't auto-advance.
Solution:
- Check
autoRotateis set totrue - Verify
rotationSpeedis a positive number - Ensure carousel is not paused
// React
<GlCarouselBanner
autoRotate={true} // Must be boolean true
rotationSpeed={3} // Must be number > 0
items={slides}
/>
6. Images Not Loading
Problem: Slide images don't appear.
Solution:
- Verify image URLs are accessible
- Check for CORS issues
- Ensure URLs are complete (include protocol)
// ✅ Good
background_image: 'https://example.com/image.png'
// ❌ Bad
background_image: '/image.png' // Relative path may not work
background_image: 'example.com/image.png' // Missing protocol
📊 Performance Tips
1. Optimize Images
- Use WebP format for better compression
- Lazy load images for off-screen slides
- Provide appropriate image sizes (avoid oversized images)
2. Limit Slide Count
- Keep carousel to 5-10 slides for best performance
- For more content, consider pagination or multiple carousels
3. Adjust Animation Speed
- Balance between smooth transitions and performance
- Slower devices may benefit from faster transitions (lower
transitionSpeed)
<GlCarouselBanner
transitionSpeed={0.3} // Faster = better performance
rotationSpeed={4} // Longer view time = less frequent transitions
items={slides}
/>
4. Disable Auto-Rotation When Not Visible
useEffect(() => {
const handleVisibilityChange = () => {
if (document.hidden) {
carouselRef.current?.pause();
} else {
carouselRef.current?.resume();
}
};
document.addEventListener('visibilitychange', handleVisibilityChange);
return () => {
document.removeEventListener('visibilitychange', handleVisibilityChange);
};
}, []);
🔗 Links & Resources
- Package Location:
@gift-card-market/gl-carousel-banner - Current Version: 1.0.9
- Dependencies:
- React 18+ (for React implementation)
- Slick Carousel (for animations)
- Key Features:
- React & Vanilla JS support
- Comprehensive event system with
CarouselBannerEvents - Full TypeScript definitions
- Programmatic control API
- CSS customization
📝 Changelog
Version 1.0.9 (Current)
- 🔒 Encapsulated CSS bleeding fixes (scoped variables and nested selectors).
- ⚙️ Added Tailwind utility prefix and configured important option.
Version 1.0.7
- 🔒 CSS of slick-carousel is encapsulated into the Shadow DOM to protect layouts.
- 📢 Custom events (
gl:slide-changed, etc.) are now dispatched directly on the custom element host wrapper. - ⚡ Bug fixes and performance improvements on Slick slide state tracking and slide-changing transitions.
Version 1.0.6 - 1.0.4
- 🐛 Bug fixes and stability improvements.
Version 1.0.3
- ✨ Added
CarouselBannerEventsconstant export for type-safe event handling - ✨ New custom events:
gl:carousel-loaded,gl:carousel-paused,gl:carousel-resumed,gl:error - 🔄 Enhanced
gl:slide-changedevent with direction information - 📚 Comprehensive event documentation with React and Vanilla JS examples
- ⚡ Improved event system with bubbling support
- 🐛 Bug fixes and performance improvements
Version 1.0.2
- 🐛 Bug fixes and stability improvements
- 📚 Documentation enhancements
Version 1.0.1
- 🎉 Initial release
- ✅ React component support
- ✅ Web Component (Vanilla JS) support
- ✅ Auto-rotation with configurable speed
- ✅ Pause on hover functionality
- ✅ Programmatic control API
- ✅ Basic event system for slide changes
- ✅ Full TypeScript support
- ✅ CSS customization via variables
🔗 Shadow DOM & Events
Shadow DOM Isolation
The Web Component wrapper (gl-carousel-banner) uses Shadow DOM (mode: 'open') to isolate styles. This ensures that the component styles do not bleed out to the host application, and outside CSS does not disrupt the carousel slider layout. CSS imports (including slick-carousel dependency styles) are compiled and injected directly into the shadow root.
Custom Events
Custom DOM Events are dispatched directly on the custom element host instance and bubble up with composed: true:
gl:carousel-loaded— Fired when the carousel has successfully initialized.gl:slide-changed— Fired on slide transition.event.detailcontains the activeslideIndexand the animationdirection("next" | "previous").gl:carousel-paused— Fired when user hovers mouse over the banner, pausing autoplay.gl:carousel-resumed— Fired when user hovers mouse out of the banner, resuming autoplay.gl:error— Fired on exceptions during slide change or loading.
You can listen to these events on the component instance:
const banner = document.querySelector('gl-carousel-banner');
banner.addEventListener('gl:slide-changed', (e) => {
console.log('Slide changed to:', e.detail.slideIndex);
});
📞 Support
For questions, issues, or feature requests, please contact the Gift Card Marketplace development team.
📄 License
© 2025 Gift Card Marketplace. All rights reserved.
Happy Coding! 🎉