ComponentsCarousel

Carousel

component

Sliding 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); }
}