Skip to main content

GL Carousel Banner

Version: 1.0.9 Package: @gift-card-market/gl-carousel-banner
Last Updated: July 1, 2026


📖 Table of Contents


🎯 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

PropTypeDefaultDescription
itemsGlCarouselBannerItem[]RequiredArray of carousel slide data
autoRotatebooleantrueEnable/disable automatic slide rotation
rotationSpeednumber3Time in seconds between auto-rotations
transitionSpeednumber0.5Transition animation duration in seconds
pauseOnHoverbooleantruePause auto-rotation when hovering
refGlCarouselBannerHandle-Reference for programmatic control

Vanilla JS Attributes

AttributeTypeDefaultDescription
autoRotatestring"true"Enable/disable automatic rotation ("true" or "false")
rotationSpeedstring"3"Time in seconds between rotations
transitionSpeedstring"0.5"Transition duration in seconds
pauseOnHoverstring"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

MethodParametersReturnsDescription
nextSlide()-voidMove to the next slide
previousSlide()-voidMove to the previous slide
goToSlide(index)index: numbervoidJump to specific slide (0-indexed)
pause()-voidPause auto-rotation
resume()-voidResume auto-rotation
getCurrentSlide()-number | undefinedGet 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 NameEvent TypeDetail ObjectDescription
gl:carousel-loadedCustomEvent{ slideCount: number }Fired when carousel is initialized and ready
gl:slide-changedCustomEvent{ slideIndex: number, direction: 'next' | 'previous' }Fired whenever the active slide changes
gl:carousel-pausedCustomEvent{}Fired when auto-rotation is paused
gl:carousel-resumedCustomEvent{}Fired when auto-rotation is resumed
gl:errorCustomEvent{ error: string }Fired when an error occurs

Event Usage Examples

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

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 autoRotate is set to true
  • Verify rotationSpeed is 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);
};
}, []);

  • 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 CarouselBannerEvents constant export for type-safe event handling
  • ✨ New custom events: gl:carousel-loaded, gl:carousel-paused, gl:carousel-resumed, gl:error
  • 🔄 Enhanced gl:slide-changed event 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.detail contains the active slideIndex and the animation direction ("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! 🎉