ComponentsCarousel
Carousel
componentSliding panels with prev/next and dot pagination.
Carousel
Sliding panels with prev/next and dot pagination.
Composes: Button
Recipe CSS
This is the exact CSS your kit ships for Carousel — token-driven, so it re-themes with every knob. Get it (and the rest) from the configurator's Use kit panel.
/* === Carousel (.carousel) — shadcn gap filler ========================
* Sliding track of equal-width slides + absolute prev/next arrows. Dots
* reuse the existing .cdots component. Radius follows the Box token. */
.carousel { display: flex; flex-direction: column; gap: var(--k-s-12); }
.carousel__viewport { position: relative; overflow: hidden; border-radius: var(--k-radius-lg); }
.carousel__track { display: flex; transition: transform var(--k-dur, 280ms) var(--k-ease, ease); }
.carousel__slide {
flex: 0 0 100%; aspect-ratio: 16 / 7; display: flex; align-items: flex-end;
padding: var(--k-s-16); color: #fff;
}
.carousel__caption { font-size: var(--k-type-body); font-weight: var(--k-weight-semibold); text-shadow: 0 1px 3px hsl(0 0% 0% / 0.4); }
.carousel__arrow {
position: absolute; top: 50%; transform: translateY(-50%);
width: var(--k-icon-chip); height: var(--k-icon-chip); border-radius: 50%; border: 0; cursor: pointer;
display: grid; place-items: center; color: var(--k-fg);
background: var(--k-surface); box-shadow: var(--k-shadow-md, 0 2px 8px hsl(0 0% 0% / 0.18));
}
.carousel__arrow:hover { background: var(--k-state-hover); }
.carousel__arrow:active { background: var(--k-state-press); }
.carousel__arrow--prev { left: var(--k-s-10); }
.carousel__arrow--next { right: var(--k-s-10); }
/* ----- Pagination dots (.cdots) — the carousel's position indicator; also
* reusable standalone for onboarding / story progress. Three shapes via a
* modifier: dots (default), numbers (--num), segment bars (--bars). ----- */
.cdots {
display: flex;
align-items: center;
justify-content: center;
gap: var(--k-s-4);
padding: var(--k-s-4) 0;
}
.cdots__dot {
width: 6px;
height: 6px;
border-radius: 999px;
background: var(--k-fg-faint);
border: 0;
padding: 0;
cursor: pointer;
opacity: 0.4;
transition:
width var(--k-dur-fast, 110ms) var(--k-ease, ease),
background var(--k-dur-fast, 110ms) var(--k-ease, ease),
opacity var(--k-dur-fast, 110ms) var(--k-ease, ease);
}
.cdots__dot.is-on {
width: 18px;
background: var(--k-primary);
opacity: 1;
}
.cdots--num { gap: var(--k-s-4); }
.cdots__num {
width: 22px;
height: 22px;
border-radius: 50%;
background: transparent;
border: 0;
color: var(--k-fg-muted);
font-size: var(--k-type-caption);
font-weight: var(--k-weight-semibold);
cursor: pointer;
font-variant-numeric: tabular-nums;
font-family: var(--k-font-body);
}
.cdots__num.is-on {
background: var(--k-primary);
color: var(--k-primary-fg);
}
.cdots--bars { gap: var(--k-s-4); }
.cdots__bar {
flex: 1;
height: 3px;
border-radius: 2px;
background: var(--k-fg-faint);
opacity: 0.35;
position: relative;
overflow: hidden;
}
.cdots__bar.is-done {
background: var(--k-primary);
opacity: 1;
}
.cdots__bar.is-on {
background: var(--k-fg-faint);
opacity: 0.6;
}
.cdots__bar.is-on::after {
content: '';
position: absolute;
inset: 0;
background: var(--k-primary);
transform-origin: left;
animation: cdots-fill 3s linear infinite;
}
@keyframes cdots-fill {
from { transform: scaleX(0); }
to { transform: scaleX(1); }
}