3d-whell-parallax-carousel
v1.0.3
Published
Smooth 3D parallax carousel with trapezoid perspective effect. Works with Vanilla JS, React, and Vue.
Downloads
436
Maintainers
Readme
3d-whell-parallax-carousel
Smooth 3D parallax carousel with trapezoid perspective effect. Shows 5 cards at once — center card flat, side cards angled like a fan. Works with Vanilla JS, React, Vue 3, and TypeScript.
Install
npm install 3d-whell-parallax-carouselUsage
Vanilla JS
import { ParallaxCarousel } from "3d-whell-parallax-carousel";
const carousel = new ParallaxCarousel("#my-container", [
'<div style="color:white">Card 1</div>',
'<div style="color:white">Card 2</div>',
'<div style="color:white">Card 3</div>',
]);With renderItem callback (HTML string)
import { ParallaxCarousel } from "3d-whell-parallax-carousel";
const products = [
{ id: 1, name: "Product 1", image: "/img1.jpg" },
{ id: 2, name: "Product 2", image: "/img2.jpg" },
];
const carousel = new ParallaxCarousel("#my-container", products, {
renderItem: ({ item, index }) => `
<div style="text-align: center; padding: 20px;">
<img src="${item.image}" alt="${item.name}" style="width: 100%; border-radius: 4px;" />
<h3 style="margin-top: 10px; color: white;">${item.name}</h3>
</div>
`,
});TypeScript
import { ParallaxCarousel, type ParallaxCarouselOptions } from "3d-whell-parallax-carousel";
interface Product {
id: number;
name: string;
image: string;
}
const products: Product[] = [
{ id: 1, name: "Product 1", image: "/img1.jpg" },
{ id: 2, name: "Product 2", image: "/img2.jpg" },
];
const options: ParallaxCarouselOptions<Product> = {
autoplay: true,
renderItem: ({ item }) => `
<div>
<img src="${item.image}" alt="${item.name}" />
<h3>${item.name}</h3>
</div>
`,
};
const carousel = new ParallaxCarousel<Product>("#my-container", products, options);React
import { ParallaxCarouselReact } from "3d-whell-parallax-carousel/react";
const items = ["<div>Card 1</div>", "<div>Card 2</div>", "<div>Card 3</div>"];
function App() {
const ref = useRef(null);
return (
<>
<ParallaxCarouselReact
ref={ref}
items={items}
options={{ autoplay: true, interval: 3000 }}
onChange={({ index }) => console.log("Slide:", index)}
/>
<button onClick={() => ref.current.next()}>Next</button>
</>
);
}React with renderItem (JSX Component)
import { ParallaxCarouselReact } from "3d-whell-parallax-carousel/react";
const products = [
{ id: 1, name: "Product 1", image: "/img1.jpg" },
{ id: 2, name: "Product 2", image: "/img2.jpg" },
];
// Your custom React component
function ProductCard({ product, index }) {
return (
<div style={{ padding: '20px', textAlign: 'center' }}>
<img src={product.image} alt={product.name} style={{ width: '100%', borderRadius: '4px' }} />
<h3 style={{ marginTop: '10px', color: 'white' }}>{product.name}</h3>
<p style={{ color: 'rgba(255,255,255,0.6)' }}>Index: {index}</p>
</div>
);
}
function App() {
const ref = useRef(null);
return (
<ParallaxCarouselReact
ref={ref}
items={products}
options={{
autoplay: true,
renderItem: ({ item, index }) => (
<ProductCard product={item} index={index} />
),
}}
onChange={({ index }) => console.log("Slide:", index)}
/>
);
}React with TypeScript
import { useRef } from "react";
import {
ParallaxCarouselReact,
type ParallaxCarouselReactHandle,
type ParallaxCarouselReactProps,
} from "3d-whell-parallax-carousel/react";
interface Product {
id: number;
name: string;
image: string;
}
const items: Product[] = [
{ id: 1, name: "Product 1", image: "/img1.jpg" },
{ id: 2, name: "Product 2", image: "/img2.jpg" },
];
function App() {
const carouselRef = useRef<ParallaxCarouselReactHandle>(null);
const handleChange: ParallaxCarouselReactProps["onChange"] = ({ index, total }) => {
console.log(`Slide ${index} of ${total}`);
};
return (
<>
<ParallaxCarouselReact<Product>
ref={carouselRef}
items={items}
options={{
autoplay: true,
renderItem: ({ item, index }) => (
<div>
<img src={item.image} alt={item.name} />
<h3>{item.name}</h3>
</div>
),
}}
onChange={handleChange}
/>
<button onClick={() => carouselRef.current?.next()}>Next</button>
</>
);
}Vue 3
<template>
<ParallaxCarousel
ref="carousel"
:items="items"
:options="{ autoplay: true, interval: 3000 }"
@change="onSlideChange"
/>
<button @click="$refs.carousel.next()">Next</button>
</template>
<script setup>
import { ParallaxCarouselVue as ParallaxCarousel } from "3d-whell-parallax-carousel/vue";
const items = ["<div>Card 1</div>", "<div>Card 2</div>"];
const onSlideChange = ({ index, total }) => console.log(index, total);
</script>Vue 3 with renderItem (VNode)
<template>
<ParallaxCarousel
ref="carousel"
:items="products"
:options="{
autoplay: true,
renderItem: ({ item, index }) => h('div', {
style: { padding: '20px', textAlign: 'center' }
}, [
h('img', { src: item.image, style: { width: '100%', borderRadius: '4px' } }),
h('h3', { style: { marginTop: '10px', color: 'white' } }, item.name),
h('p', { style: { color: 'rgba(255,255,255,0.6)' } }, `Index: ${index}`),
]),
}"
@change="onSlideChange"
/>
</template>
<script setup>
import { h } from 'vue';
import { ParallaxCarouselVue as ParallaxCarousel } from "3d-whell-parallax-carousel/vue";
const products = [
{ id: 1, name: "Product 1", image: "/img1.jpg" },
{ id: 2, name: "Product 2", image: "/img2.jpg" },
];
const onSlideChange = ({ index, total }) => console.log(index, total);
</script>Vue 3 with TypeScript
<template>
<ParallaxCarousel
ref="carouselRef"
:items="products"
:options="options"
@change="onSlideChange"
/>
<button @click="carouselRef?.next()">Next</button>
</template>
<script setup lang="ts">
import { ref, h, type VNode } from "vue";
import {
ParallaxCarouselVue as ParallaxCarousel,
type ParallaxCarouselInstance,
type ParallaxCarouselOptions,
type RenderItemContext,
} from "3d-whell-parallax-carousel/vue";
interface Product {
id: number;
name: string;
image: string;
}
const carouselRef = ref<ParallaxCarouselInstance | null>(null);
const products: Product[] = [
{ id: 1, name: "Product 1", image: "/img1.jpg" },
{ id: 2, name: "Product 2", image: "/img2.jpg" },
];
const options: ParallaxCarouselOptions<Product> = {
autoplay: true,
renderItem: ({ item, index }: RenderItemContext<Product>): VNode => {
return h('div', { style: { padding: '20px' } }, [
h('img', { src: item.image, style: { width: '100%' } }),
h('h3', item.name),
]);
},
};
const onSlideChange = ({ index, total }: { index: number; total: number }) => {
console.log(`Slide ${index} of ${total}`);
};
</script>Options
| Option | Type | Default | Description |
| -------------- | ------- | ----------------------------- | ---------------------------- |
| autoplay | boolean | true | Enable auto-advance |
| interval | number | 2800 | Autoplay interval in ms |
| pauseOnHover | boolean | true | Pause autoplay on hover |
| duration | number | 650 | Transition duration in ms |
| easing | string | 'cubic-bezier(0.4,0,0.2,1)' | CSS easing |
| background | string | '#111111' | Card background color |
| borderColor | string | 'rgba(255,255,255,0.1)' | Card border color |
| borderWidth | string | '1.5px' | Card border width |
| borderRadius | string | '4px' | Card border radius |
| stageHeight | string | '420px' | Height of the carousel stage |
| perspective | number | 900 | CSS perspective value in px |
| showGrid | boolean | true | Show background grid |
| gridColor | string | 'rgba(255,255,255,0.032)' | Grid line color |
| gridSize | string | '38px' | Grid cell size |
| slots | object | see below | Per-slot position config |
| renderItem | function | undefined | Custom render function |
slots config
Customize each of the 5 visible positions (-2 to +2):
import type { ParallaxCarouselOptions } from "3d-whell-parallax-carousel";
const options: ParallaxCarouselOptions = {
slots: {
'-2': { x: -490, w: 220, h: 330, ry: 50, origin: 'right center', z: 1, op: 1 },
'-1': { x: -255, w: 192, h: 295, ry: 26, origin: 'right center', z: 2, op: 1 },
'0': { x: 0, w: 188, h: 275, ry: 0, origin: 'center center', z: 3, op: 1 },
'1': { x: 255, w: 192, h: 295, ry: -26, origin: 'left center', z: 2, op: 1 },
'2': { x: 490, w: 220, h: 330, ry: -50, origin: 'left center', z: 1, op: 1 },
},
};| Field | Description |
| -------- | ----------------------------------- |
| x | Horizontal offset from center in px |
| w | Card width in px |
| h | Card height in px |
| ry | rotateY angle in degrees |
| origin | CSS transform-origin |
| z | z-index |
| op | opacity (0–1) |
renderItem callback
Custom render function for each item. Returns depend on framework:
| Framework | Return Type | Example |
|-----------|-------------|---------|
| Vanilla JS | string | HTMLElement | '<div>Content</div>' |
| React | ReactNode | <MyComponent /> |
| Vue 3 | VNode | string | h('div', 'Content') |
Context object:
type RenderItem = (context: {
item: T; // The item data
index: number; // Item index
container: HTMLElement; // Card container element
}) => ReactNode | VNode | HTMLElement | string;API
Vanilla JS / Core
carousel.next(); // Go to next slide
carousel.prev(); // Go to previous slide
carousel.goTo(index); // Jump to specific index
carousel.updateOptions({
// Update options at runtime
interval: 5000,
background: "#222",
});
carousel.destroy(); // Clean up and remove from DOMReact Ref Methods
const ref = useRef<ParallaxCarouselReactHandle>(null);
ref.current?.next();
ref.current?.prev();
ref.current?.goTo(2);
ref.current?.updateOptions({ interval: 5000 });
ref.current?.destroy();Vue Ref Methods
<script setup lang="ts">
const carouselRef = ref<ParallaxCarouselInstance | null>(null);
carouselRef.value?.next();
carouselRef.value?.prev();
carouselRef.value?.goTo(2);
carouselRef.value?.updateOptions({ interval: 5000 });
carouselRef.value?.destroy();
</script>Events
Vanilla JS
container.addEventListener("change", (e) => {
console.log(e.detail.index); // current index
console.log(e.detail.total); // total items
});React
<ParallaxCarouselReact
items={items}
onChange={({ index, total }) => {
console.log(`Slide ${index} of ${total}`);
}}
/>Vue
<ParallaxCarousel
:items="items"
@change="({ index, total }) => console.log(`Slide ${index} of ${total}`)"
/>Build from source
npm install
npm run buildOutput goes to dist/.
Development
# Watch mode
npm run dev
# Type check
npm run typecheckTypeScript Support
This library includes full TypeScript support with:
- ✅ Complete type definitions for all exports
- ✅ Generic type support for items (
<T>) - ✅ Type-safe
renderItemcallback with framework-specific return types - ✅ ReactNode support for React
- ✅ VNode support for Vue
- ✅ Type-safe options and props
- ✅ Typed event handlers
- ✅ Proper ref types for React and Vue
- ✅ tsconfig.json included
License
MIT
