Components · Data Display
Carousel
A swipeable set of slides — onboarding, a feature tour, a gallery — rendered through the shared Carousel.
Examples
<!-- Paste-and-run: save as .html and open in a browser. No build step, no bundler.
Carousel is a COMPOSITE (antd, no framework-free element), so its HTML form is a
CDN-React page — React + antd load from a CDN (esm.sh) and mount on open. It
consumes the SAME shared `carouselTheme` the React/Vue wrappers use, so it renders
the DS V3 look (radius-8 slides, brand active dot). Keeps antd's built-in motion.
No JSX here (JSX needs a compiler) — we use React.createElement via the `h` alias. -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/ahaslides-product/ahaslides-design@master/lib/tokens.css">
<style>
.aha-slide { box-sizing:border-box; height:160px; padding:24px; border-radius:var(--aha-radius-default);
background:var(--aha-purple-10); color:var(--aha-purple-60); font-family:var(--aha-font-product);
display:flex; align-items:center; justify-content:center; font-size:20px; font-weight:700; }
.ant-carousel { max-width:520px; }
.ant-carousel .slick-dots li.slick-active button { background:var(--aha-color-primary); }
</style>
<div id="root"></div>
<script type="module">
import React from 'https://esm.sh/react@18';
import { createRoot } from 'https://esm.sh/react-dom@18/client';
import { ConfigProvider, Carousel } from 'https://esm.sh/antd@6?deps=react@18,react-dom@18';
import { carouselTheme } from 'https://cdn.jsdelivr.net/gh/ahaslides-product/ahaslides-design@master/lib/carousel-theme.js';
const h = React.createElement;
const slides = ['Create in minutes', 'Present live', 'Share the results'];
// Same shared theme the React/Vue wrappers pass to ConfigProvider.
// Full matrix on one component: dotPosition (top/bottom/left/right) · effect (scrollx/fade) · autoplay · arrows.
createRoot(document.getElementById('root')).render(
h(ConfigProvider, { theme: carouselTheme },
h(Carousel, { dots: true, dotPosition: 'bottom', effect: 'scrollx', autoplay: false, arrows: false },
...slides.map((s, i) => h('div', { key: i }, h('div', { className: 'aha-slide' }, s)))
)
)
);
</script>
import { ConfigProvider, Carousel } from 'antd'; // antd v6
import { carouselTheme } from '@ahaslides-product/design/carousel-theme';
const slides = ['Create in minutes', 'Present live', 'Share the results'];
<ConfigProvider theme={carouselTheme}>
<Carousel
dots // position dots (on by default)
dotPosition="bottom" // top | bottom | left | right
effect="scrollx" // scrollx (slide) | fade
autoplay={false} // ambient galleries only
arrows={false} // opt-in prev/next
afterChange={setCurrent}
>
{slides.map((s, i) => (
<div key={i}>
<div className="aha-slide">{s}</div>
</div>
))}
</Carousel>
</ConfigProvider>
// One shared carouselTheme → the DS V3 look; keeps antd's built-in slide/fade motion.
<script setup>
import { ConfigProvider, Carousel } from 'ant-design-vue'; // ant-design-vue v4
import { carouselTheme } from '@ahaslides-product/design/carousel-theme';
const slides = ['Create in minutes', 'Present live', 'Share the results'];
</script>
<template>
<a-config-provider :theme="carouselTheme">
<a-carousel
:dots="true"
dot-position="bottom"
effect="scrollx"
:autoplay="false"
:arrows="false"
@after-change="onChange"
>
<div v-for="(s, i) in slides" :key="i">
<div class="aha-slide">{{ s }}</div>
</div>
</a-carousel>
</a-config-provider>
</template>
<!-- The SAME carouselTheme as React → one DS V3 look across both vendor libraries.
Same matrix: dot-position (top/bottom/left/right) · effect (scrollx/fade) · autoplay · arrows. -->
// @ahaslides-product/design/carousel-theme — declared ONCE, consumed by both tiers.
import { carouselTheme } from '@ahaslides-product/design/carousel-theme';
export const carouselTheme = {
token: {
colorPrimary: '#6A1EBB',
borderRadius: 8,
fontFamily: 'var(--aha-font-product, "Plus Jakarta Sans", sans-serif)',
},
components: {
Carousel: {
dotWidth: 16,
dotHeight: 4,
dotActiveWidth: 28, // brand-primary active dot, wider
dotGap: 8,
arrowSize: 20,
arrowOffset: 12,
},
},
};
API
| Prop | Type | Default | Notes |
|---|---|---|---|
autoplay | boolean | false | Advance slides automatically |
dots | boolean | true | Show the position dots |
dotPosition | top | bottom | left | right | bottom | Where the dots sit relative to the track |
effect | scrollx | fade | scrollx | Slide transition style |
arrows | boolean | false | Show prev/next arrows |
afterChange | (current) => void | — | Fires after the active slide changes |
Install
# .npmrc — once: point the @ahaslides-product scope at GitHub Packages
@ahaslides-product:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN} # a GitHub token with read:packages
npm i @ahaslides-product/design
import '@ahaslides-product/design/tokens.css'; // once, at the app root
import '@ahaslides-product/design/carousel-theme'; // registers <carousel>
Agent feed for this component (absolute, fetchable anywhere): carousel.agent.json · carousel.md · carousel.llms.txt
When to use
When to use
- Carousel — a small, ordered set of equally-weighted panels the user can browse at their own pace
- Tabs — named sections the user jumps between directly, not in sequence
- Steps — a linear process with a clear start and finish
Keep it to a handful of slides and always show the dots so people know there is more. Autoplay only for ambient galleries — never for content people need to read.
Surfaces
editor dashboard audience
Spec
Slide radius 8 · brand-tint #F9F5FF panel · Active dot brand #6A1EBB, wider (28px) · Rest dot 16×4, gap 8 · Dot position bottom (default) · top · left · right · Effect slide (scrollx, default) · fade · Arrows opt-in prev/next via the arrows prop · Motion antd's built-in slide/fade transition (kept) · Autoplay opt-in via the autoplay prop