Carousel
An image and content carousel with swipe gestures, autoplay, thumbnail navigation, and keyboard support.
Basic Usage
Image Carousel
A basic image carousel with dot navigation and arrow buttons.
import { Carousel } from 'fluxo-ui';
import type { CarouselSlide } from 'fluxo-ui';
const slides: CarouselSlide[] = [
{ id: 's1', type: 'image', src: '/photo1.jpg', alt: 'Mountain landscape' },
{ id: 's2', type: 'image', src: '/photo2.jpg', alt: 'Ocean sunset' },
{ id: 's3', type: 'image', src: '/photo3.jpg', alt: 'City skyline' },
];
<Carousel slides={slides} />Thumbnail Navigation
Use navigation="thumbnails" to display a clickable thumbnail strip below (or beside) the carousel.
Thumbnail Navigation
Navigate slides using clickable thumbnail strip below the main viewport.
import { Carousel } from 'fluxo-ui';
<Carousel
slides={slides}
navigation="thumbnails"
thumbnailPosition="bottom"
/>Editable Thumbnails
Pass thumbnailActions for per-thumbnail overlay buttons and trailingThumbnail for an extra tile after the strip. Both are fully generic — supply any icon and handler for delete, edit, add, or any custom action.
Editable Thumbnails
Generic per-thumbnail action buttons plus a trailing add tile. Any icon and handler is configurable.
import { Carousel } from 'fluxo-ui';
import { EditIcon, PlusIcon, TrashIcon } from 'fluxo-ui/icons';
<Carousel
slides={slides}
navigation="thumbnails"
showThumbnailInfo
thumbnailActions={[
{
icon: <EditIcon />,
label: 'Rename',
onClick: (slide, index) => rename(index),
},
{
icon: <TrashIcon />,
label: 'Delete',
variant: 'danger',
onClick: (slide, index) => remove(index),
},
]}
trailingThumbnail={{
icon: <PlusIcon />,
label: 'Add image',
onClick: () => addSlide(),
}}
/>Add Images
Pass onAddImages to make the carousel an attachment surface. Files can be dragged onto the viewport (a drop overlay appears) or chosen via the trailing add tile's file picker. Forward clipboard paste from your form to the same callback for paste-anywhere support. Filter accepted files withaddImagesAccept.
Add Images (drop · paste · pick)
Set onAddImages to turn the carousel into an attachment surface: drag-and-drop onto the viewport, an add tile that opens the file picker, and (via a consumer paste listener) clipboard paste — all feeding the same callback.
import { Carousel } from 'fluxo-ui';
import { TrashIcon } from 'fluxo-ui/icons';
const addFromFiles = (files: File[]) => {
Promise.all(
files.map(
(file) =>
new Promise<CarouselSlide>((resolve) => {
const url = URL.createObjectURL(file);
resolve({ id: crypto.randomUUID(), type: 'image', src: url, name: file.name });
}),
),
).then((next) => setSlides((prev) => [...prev, ...next]));
};
// Drag-drop and the trailing file-picker tile are handled by the carousel.
// Forward clipboard paste to the same callback for paste-anywhere support.
useEffect(() => {
const onPaste = (e: ClipboardEvent) => {
const files = Array.from(e.clipboardData?.files ?? []).filter((f) => f.type.startsWith('image/'));
if (files.length) addFromFiles(files);
};
window.addEventListener('paste', onPaste);
return () => window.removeEventListener('paste', onPaste);
}, []);
<Carousel
slides={slides}
navigation="thumbnails"
aspectRatio="16/10"
onAddImages={addFromFiles}
thumbnailActions={[{ icon: <TrashIcon />, label: 'Delete', variant: 'danger', onClick: (_s, i) => remove(i) }]}
/>Autoplay
Enable autoplay with loop for continuous slide rotation. Autoplay pauses on hover.
Autoplay with Loop
Slides advance automatically every 3 seconds and loop back to the first slide. Pauses on hover.
import { Carousel } from 'fluxo-ui';
<Carousel
slides={slides}
autoplay
autoplayInterval={3000}
loop
/>Import
import { Carousel } from 'fluxo-ui';
import type { CarouselProps, CarouselSlide, CarouselThumbnailAction, CarouselTrailingThumbnail } from 'fluxo-ui';Carousel Props
slidesreqCarouselSlide[]Array of slide data.
slidesreqCarouselSlide[]Array of slide data.
activeIndexnumberControlled active slide index.
activeIndexnumberControlled active slide index.
onSlideChange(index: number) => voidCalled when the active slide changes.
onSlideChange(index: number) => voidCalled when the active slide changes.
navigation'dots' | 'arrows' | 'thumbnails' | 'none'"'dots'"Navigation style.
navigation'dots' | 'arrows' | 'thumbnails' | 'none'"'dots'"Navigation style.
thumbnailPosition'top' | 'bottom' | 'left' | 'right'"'bottom'"Position of thumbnail strip.
thumbnailPosition'top' | 'bottom' | 'left' | 'right'"'bottom'"Position of thumbnail strip.
autoplayboolean"false"Enable automatic slide advancement.
autoplayboolean"false"Enable automatic slide advancement.
autoplayIntervalnumber"5000"Autoplay interval in milliseconds.
autoplayIntervalnumber"5000"Autoplay interval in milliseconds.
loopboolean"false"Loop back to first slide after the last.
loopboolean"false"Loop back to first slide after the last.
showArrowsboolean"true"Show previous/next arrow buttons.
showArrowsboolean"true"Show previous/next arrow buttons.
showDotsbooleanShow dot indicators (overrides navigation).
showDotsbooleanShow dot indicators (overrides navigation).
lazyLoadboolean"false"Lazy-load images as they become active.
lazyLoadboolean"false"Lazy-load images as they become active.
swipeableboolean"true"Enable swipe/drag gesture navigation.
swipeableboolean"true"Enable swipe/drag gesture navigation.
aspectRatiostringCSS aspect ratio for slides (e.g. "16/9").
aspectRatiostringCSS aspect ratio for slides (e.g. "16/9").
classNamestringAdditional CSS class for the container.
classNamestringAdditional CSS class for the container.
slideClassNamestringAdditional CSS class for each slide.
slideClassNamestringAdditional CSS class for each slide.
ariaLabelstring"'Image carousel'"Accessible name for the carousel region.
ariaLabelstring"'Image carousel'"Accessible name for the carousel region.
showAutoplayToggleboolean"true"Show a play/pause button when autoplay is enabled (WCAG 2.2.2).
showAutoplayToggleboolean"true"Show a play/pause button when autoplay is enabled (WCAG 2.2.2).
thumbnailActionsCarouselThumbnailAction[]Per-thumbnail overlay action buttons (e.g. delete, edit). Each action has { icon, label, onClick(slide, index), variant?, isVisible? }. Generic — any icon and handler.
thumbnailActionsCarouselThumbnailAction[]Per-thumbnail overlay action buttons (e.g. delete, edit). Each action has { icon, label, onClick(slide, index), variant?, isVisible? }. Generic — any icon and handler.
trailingThumbnailCarouselTrailingThumbnailAn extra tile rendered after the last thumbnail (e.g. an add button). Shape: { icon, label, onClick }.
trailingThumbnailCarouselTrailingThumbnailAn extra tile rendered after the last thumbnail (e.g. an add button). Shape: { icon, label, onClick }.
onAddImages(files: File[]) => voidEnables image attachment. When set, the carousel accepts drag-and-drop of image files onto the viewport (with a drop overlay) and renders a trailing 'add' tile that opens a file picker (unless a custom trailingThumbnail is provided). Receives the filtered File[]. Combine with a consumer-side clipboard paste handler that forwards pasted files to the same callback.
onAddImages(files: File[]) => voidEnables image attachment. When set, the carousel accepts drag-and-drop of image files onto the viewport (with a drop overlay) and renders a trailing 'add' tile that opens a file picker (unless a custom trailingThumbnail is provided). Receives the filtered File[]. Combine with a consumer-side clipboard paste handler that forwards pasted files to the same callback.
addImagesAcceptstring"'image/*'"Comma-separated accept filter (MIME types like 'image/png' or extensions like '.png') applied to dropped and picked files before onAddImages fires.
addImagesAcceptstring"'image/*'"Comma-separated accept filter (MIME types like 'image/png' or extensions like '.png') applied to dropped and picked files before onAddImages fires.
addImagesDropLabelstring"'Drop image to add'"Label shown in the drop overlay and used as the trailing add tile's accessible label when onAddImages is set.
addImagesDropLabelstring"'Drop image to add'"Label shown in the drop overlay and used as the trailing add tile's accessible label when onAddImages is set.
CarouselSlide Interface
idreqstringUnique identifier for the slide.
idreqstringUnique identifier for the slide.
typereq'image' | 'video' | 'custom'Slide content type.
typereq'image' | 'video' | 'custom'Slide content type.
srcstringImage URL (for image type).
srcstringImage URL (for image type).
altstringAlt text for the image.
altstringAlt text for the image.
thumbnailstringThumbnail URL for thumbnail navigation.
thumbnailstringThumbnail URL for thumbnail navigation.
contentReactNodeCustom content (for custom type).
contentReactNodeCustom content (for custom type).
CarouselThumbnailAction Interface
iconreqReactNodeIcon rendered inside the action button.
iconreqReactNodeIcon rendered inside the action button.
labelreqstringAccessible label / tooltip for the action.
labelreqstringAccessible label / tooltip for the action.
onClickreq(slide: CarouselSlide, index: number) => voidInvoked with the slide and its index when the action is clicked.
onClickreq(slide: CarouselSlide, index: number) => voidInvoked with the slide and its index when the action is clicked.
variant'default' | 'danger'"'default'"Visual style of the action button.
variant'default' | 'danger'"'default'"Visual style of the action button.
isVisible(slide: CarouselSlide, index: number) => booleanOptional predicate to conditionally show the action per slide.
isVisible(slide: CarouselSlide, index: number) => booleanOptional predicate to conditionally show the action per slide.
CarouselTrailingThumbnail Interface
iconreqReactNodeIcon rendered inside the trailing tile (e.g. a plus icon).
iconreqReactNodeIcon rendered inside the trailing tile (e.g. a plus icon).
labelreqstringAccessible label / tooltip for the trailing tile.
labelreqstringAccessible label / tooltip for the trailing tile.
onClickreq() => voidInvoked when the trailing tile is clicked.
onClickreq() => voidInvoked when the trailing tile is clicked.
Features
Swipe Gestures
Touch and pointer swipe support for mobile and desktop navigation.
Autoplay
Auto-advance slides at a configurable interval, pausing on hover.
Thumbnails
Thumbnail strip with configurable position for visual slide selection.
Keyboard Navigation
Arrow keys navigate between slides with focus management.
Lazy Loading
Only load slide content when it becomes active to reduce initial bandwidth.
Accessibility
ARIA roledescription, tab roles for dots, and labeled arrow buttons.