Carousel
Native scroll-snap containers without a slider runtime
Carousel
Import
@import "tailwindcss";
@import "@duskmoon-dev/core";
Individual CSS: @duskmoon-dev/core/components/carousel.css (also available via the style export condition on @duskmoon-dev/core/components/carousel).
JavaScript import { css, styles } from "@duskmoon-dev/core/components/carousel" exposes CSS text and a nullable CSSStyleSheet (null during SSR). It is not an interaction runtime.
Example
Carousel composition
<section class="carousel carousel-center" tabindex="0" aria-label="Project summaries"><article class="carousel-item card" style="width: 18rem"><div class="card-body"><h2 class="card-title">Observatory</h2><p>Night-sky observations</p><a class="btn btn-primary" href="#api">Open project</a></div></article><article class="carousel-item card" style="width: 22rem"><div class="card-body"><h2 class="card-title">Moon atlas</h2><p>Surface mapping</p><a class="btn" href="#api">Open atlas</a></div></article></section>API And Accessibility
Semantic text variants: carousel-primary, carousel-secondary,
carousel-tertiary, carousel-info, carousel-success,
carousel-warning, carousel-error. Keep meaningful labels and values;
color alone is not an accessible distinction.
Classes: carousel, carousel-item, carousel-horizontal (default), carousel-vertical, carousel-start, carousel-center, carousel-end. Vertical containers are bounded by --carousel-height (24rem default). Items can have different sizes, bounded by the container. Keep the scrollbar available. The focused container supports browser scrolling keys; touch and pointer scrolling are native. Tab reaches nested links and buttons.
Provide a visible heading or accessible label and tabindex="0" on the scroll container. No autoplay or looping is provided. Smooth scrolling becomes immediate under reduced motion. Optional navigation requires an application controller; CSS does not make buttons scroll.
const carousel = document.querySelector(".carousel");
const items = [...carousel.querySelectorAll(".carousel-item")];
const buttons = document.querySelectorAll('[data-carousel-index]');
// Wire each labeled navigation button to its corresponding item.
buttons.forEach((button, index) => button.addEventListener("click", () => {
items[index].scrollIntoView({ block: "nearest", inline: "start",
behavior: matchMedia("(prefers-reduced-motion: reduce)").matches ? "instant" : "smooth" });
}));
For the two-item example, place these controls outside the scroll region:
<nav aria-label="Project navigation">
<button class="btn btn-sm" data-carousel-index="0">Observatory</button>
<button class="btn btn-sm" data-carousel-index="1">Moon atlas</button>
</nav>