Carousel specifically for images.
<div class="img-slider" style="--accent:#BFD9F2;">
<input class="img-slider__radio" type="radio" name="img-slider-slide" id="img-slider-s1" checked />
<input class="img-slider__radio" type="radio" name="img-slider-slide" id="img-slider-s2" />
<input class="img-slider__radio" type="radio" name="img-slider-slide" id="img-slider-s3" />
<div class="img-slider__viewport" style="border-radius:10px;">
<div class="img-slider__track">
<img class="img-slider__img" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='400' height='260'%3E%3Crect width='400' height='260' fill='%23A8E6C1'/%3E%3Ccircle cx='200' cy='130' r='70' fill='%23FAF7F2'/%3E%3C/svg%3E" alt="Slide 1: pale circle on mint" loading="lazy" width="400" height="260" />
<img class="img-slider__img" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='400' height='260'%3E%3Crect width='400' height='260' fill='%23BFD9F2'/%3E%3Ccircle cx='200' cy='130' r='70' fill='%23FAF7F2'/%3E%3C/svg%3E" alt="Slide 2: pale circle on sky blue" loading="lazy" width="400" height="260" />
<img class="img-slider__img" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='400' height='260'%3E%3Crect width='400' height='260' fill='%23F5C2E0'/%3E%3Ccircle cx='200' cy='130' r='70' fill='%23FAF7F2'/%3E%3C/svg%3E" alt="Slide 3: pale circle on blush pink" loading="lazy" width="400" height="260" />
</div>
<div class="img-slider__arrows">
<label class="img-slider__arrow img-slider__arrow--for-1" for="img-slider-s3" aria-label="Previous image">‹</label>
<label class="img-slider__arrow img-slider__arrow--for-1" for="img-slider-s2" aria-label="Next image">›</label>
<label class="img-slider__arrow img-slider__arrow--for-2" for="img-slider-s1" aria-label="Previous image">‹</label>
<label class="img-slider__arrow img-slider__arrow--for-2" for="img-slider-s3" aria-label="Next image">›</label>
<label class="img-slider__arrow img-slider__arrow--for-3" for="img-slider-s2" aria-label="Previous image">‹</label>
<label class="img-slider__arrow img-slider__arrow--for-3" for="img-slider-s1" aria-label="Next image">›</label>
</div>
</div>
<div class="img-slider__dots img-slider__dots--circle">
<label class="img-slider__dot" for="img-slider-s1" aria-label="Go to slide 1"></label>
<label class="img-slider__dot" for="img-slider-s2" aria-label="Go to slide 2"></label>
<label class="img-slider__dot" for="img-slider-s3" aria-label="Go to slide 3"></label>
</div>
</div>
<style>
.img-slider { max-width: 360px; font: 13px/1.4 system-ui, sans-serif; color: #241430; }
.img-slider__radio { position: absolute; opacity: 0; width: 1px; height: 1px; overflow: hidden; }
.img-slider__viewport { position: relative; overflow: hidden; border: 1px solid #24143022; }
.img-slider__track { display: flex; width: 300%; }
@media (prefers-reduced-motion: no-preference) {
.img-slider__track { transition: transform .2s ease; }
}
.img-slider__img { flex: 0 0 33.333%; display: block; width: 33.333%; aspect-ratio: 400 / 260; object-fit: cover; }
#img-slider-s1:checked ~ .img-slider__viewport .img-slider__track { transform: translateX(0%); }
#img-slider-s2:checked ~ .img-slider__viewport .img-slider__track { transform: translateX(-33.333%); }
#img-slider-s3:checked ~ .img-slider__viewport .img-slider__track { transform: translateX(-66.666%); }
.img-slider__arrows { position: absolute; inset: 0; display: flex; align-items: center; justify-content: space-between; padding: 0 8px; pointer-events: none; }
.img-slider__arrow { pointer-events: auto; display: none; align-items: center; justify-content: center; width: 28px; height: 28px; border-radius: 50%; background: #FAF7F2cc; color: #241430; cursor: pointer; font-size: 16px; line-height: 1; text-decoration: none; }
.img-slider__arrow:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
#img-slider-s1:checked ~ .img-slider__viewport .img-slider__arrow--for-1 { display: flex; }
#img-slider-s2:checked ~ .img-slider__viewport .img-slider__arrow--for-2 { display: flex; }
#img-slider-s3:checked ~ .img-slider__viewport .img-slider__arrow--for-3 { display: flex; }
.img-slider__dots { display: flex; gap: 8px; justify-content: center; margin-top: 10px; }
.img-slider__dot { display: block; cursor: pointer; background: #24143033; }
.img-slider__dots--circle .img-slider__dot { width: 8px; height: 8px; border-radius: 50%; }
.img-slider__dots--line .img-slider__dot { width: 20px; height: 4px; border-radius: 2px; }
.img-slider__dot:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
#img-slider-s1:checked ~ .img-slider__dots label:nth-of-type(1) { background: var(--accent); }
#img-slider-s2:checked ~ .img-slider__dots label:nth-of-type(2) { background: var(--accent); }
#img-slider-s3:checked ~ .img-slider__dots label:nth-of-type(3) { background: var(--accent); }
</style><div class="img-slider-tw max-w-[360px] font-sans text-[13px] text-[#241430]" style="--accent:#BFD9F2;">
<input class="img-slider-tw__radio" type="radio" name="img-slider-tw-slide" id="img-slider-tw-s1" checked />
<input class="img-slider-tw__radio" type="radio" name="img-slider-tw-slide" id="img-slider-tw-s2" />
<input class="img-slider-tw__radio" type="radio" name="img-slider-tw-slide" id="img-slider-tw-s3" />
<div class="img-slider-tw__viewport relative overflow-hidden border border-[#24143022]" style="border-radius:10px;">
<div class="img-slider-tw__track flex w-[300%] motion-safe:transition-transform motion-safe:duration-300">
<img class="block w-1/3 object-cover" style="aspect-ratio:400/260;" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='400' height='260'%3E%3Crect width='400' height='260' fill='%23A8E6C1'/%3E%3Ccircle cx='200' cy='130' r='70' fill='%23FAF7F2'/%3E%3C/svg%3E" alt="Slide 1: pale circle on mint" loading="lazy" width="400" height="260" />
<img class="block w-1/3 object-cover" style="aspect-ratio:400/260;" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='400' height='260'%3E%3Crect width='400' height='260' fill='%23BFD9F2'/%3E%3Ccircle cx='200' cy='130' r='70' fill='%23FAF7F2'/%3E%3C/svg%3E" alt="Slide 2: pale circle on sky blue" loading="lazy" width="400" height="260" />
<img class="block w-1/3 object-cover" style="aspect-ratio:400/260;" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='400' height='260'%3E%3Crect width='400' height='260' fill='%23F5C2E0'/%3E%3Ccircle cx='200' cy='130' r='70' fill='%23FAF7F2'/%3E%3C/svg%3E" alt="Slide 3: pale circle on blush pink" loading="lazy" width="400" height="260" />
</div>
<div class="absolute inset-0 flex items-center justify-between px-2" style="pointer-events:none;">
<label class="img-slider-tw__arrow img-slider-tw__arrow--for-1 w-7 h-7 rounded-full items-center justify-center bg-[#FAF7F2]/80 text-[#241430] cursor-pointer" style="pointer-events:auto;" for="img-slider-tw-s3" aria-label="Previous image">‹</label>
<label class="img-slider-tw__arrow img-slider-tw__arrow--for-1 w-7 h-7 rounded-full items-center justify-center bg-[#FAF7F2]/80 text-[#241430] cursor-pointer" style="pointer-events:auto;" for="img-slider-tw-s2" aria-label="Next image">›</label>
<label class="img-slider-tw__arrow img-slider-tw__arrow--for-2 w-7 h-7 rounded-full items-center justify-center bg-[#FAF7F2]/80 text-[#241430] cursor-pointer" style="pointer-events:auto;" for="img-slider-tw-s1" aria-label="Previous image">‹</label>
<label class="img-slider-tw__arrow img-slider-tw__arrow--for-2 w-7 h-7 rounded-full items-center justify-center bg-[#FAF7F2]/80 text-[#241430] cursor-pointer" style="pointer-events:auto;" for="img-slider-tw-s3" aria-label="Next image">›</label>
<label class="img-slider-tw__arrow img-slider-tw__arrow--for-3 w-7 h-7 rounded-full items-center justify-center bg-[#FAF7F2]/80 text-[#241430] cursor-pointer" style="pointer-events:auto;" for="img-slider-tw-s2" aria-label="Previous image">‹</label>
<label class="img-slider-tw__arrow img-slider-tw__arrow--for-3 w-7 h-7 rounded-full items-center justify-center bg-[#FAF7F2]/80 text-[#241430] cursor-pointer" style="pointer-events:auto;" for="img-slider-tw-s1" aria-label="Next image">›</label>
</div>
</div>
<div class="img-slider-tw__dots img-slider-tw__dots--circle flex gap-2 justify-center mt-2.5">
<label class="img-slider-tw__dot block cursor-pointer bg-[#24143033]" for="img-slider-tw-s1" aria-label="Go to slide 1"></label>
<label class="img-slider-tw__dot block cursor-pointer bg-[#24143033]" for="img-slider-tw-s2" aria-label="Go to slide 2"></label>
<label class="img-slider-tw__dot block cursor-pointer bg-[#24143033]" for="img-slider-tw-s3" aria-label="Go to slide 3"></label>
</div>
</div>
<style>
.img-slider-tw__radio { position: absolute; opacity: 0; width: 1px; height: 1px; overflow: hidden; }
#img-slider-tw-s1:checked ~ .img-slider-tw__viewport .img-slider-tw__track { transform: translateX(0%); }
#img-slider-tw-s2:checked ~ .img-slider-tw__viewport .img-slider-tw__track { transform: translateX(-33.333%); }
#img-slider-tw-s3:checked ~ .img-slider-tw__viewport .img-slider-tw__track { transform: translateX(-66.666%); }
.img-slider-tw__arrow { display: none; }
.img-slider-tw__arrow:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
#img-slider-tw-s1:checked ~ .img-slider-tw__viewport .img-slider-tw__arrow--for-1 { display: flex; }
#img-slider-tw-s2:checked ~ .img-slider-tw__viewport .img-slider-tw__arrow--for-2 { display: flex; }
#img-slider-tw-s3:checked ~ .img-slider-tw__viewport .img-slider-tw__arrow--for-3 { display: flex; }
.img-slider-tw__dots--circle .img-slider-tw__dot { width: 8px; height: 8px; border-radius: 50%; }
.img-slider-tw__dots--line .img-slider-tw__dot { width: 20px; height: 4px; border-radius: 2px; }
.img-slider-tw__dot:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
#img-slider-tw-s1:checked ~ .img-slider-tw__dots label:nth-of-type(1) { background: var(--accent); }
#img-slider-tw-s2:checked ~ .img-slider-tw__dots label:nth-of-type(2) { background: var(--accent); }
#img-slider-tw-s3:checked ~ .img-slider-tw__dots label:nth-of-type(3) { background: var(--accent); }
</style>export function ImageSlider({
dotStyle = "circle",
accent = "#BFD9F2",
showArrows = true,
radius = 10,
}) {
const slides = [
{ fill: "#A8E6C1", alt: "Slide 1: pale circle on mint" },
{ fill: "#BFD9F2", alt: "Slide 2: pale circle on sky blue" },
{ fill: "#F5C2E0", alt: "Slide 3: pale circle on blush pink" },
];
const dotSize = dotStyle === "line" ? { width: 20, height: 4, borderRadius: 2 } : { width: 8, height: 8, borderRadius: "50%" };
return (
<div style={{ maxWidth: 360, font: "13px/1.4 system-ui, sans-serif", color: "#241430", "--accent": accent }}>
<input className="img-slider-rc__radio" type="radio" name="img-slider-rc-slide" id="img-slider-rc-s1" defaultChecked />
<input className="img-slider-rc__radio" type="radio" name="img-slider-rc-slide" id="img-slider-rc-s2" />
<input className="img-slider-rc__radio" type="radio" name="img-slider-rc-slide" id="img-slider-rc-s3" />
<div className="img-slider-rc__viewport" style={{ position: "relative", overflow: "hidden", border: "1px solid #24143022", borderRadius: radius }}>
<div className="img-slider-rc__track" style={{ display: "flex", width: "300%" }}>
{slides.map((s) => (
<svg key={s.alt} viewBox="0 0 400 260" width="100%" height="100%" style={{ flex: "0 0 33.333%", display: "block" }} role="img" aria-label={s.alt}>
<rect width="400" height="260" fill={s.fill} />
<circle cx="200" cy="130" r="70" fill="#FAF7F2" />
</svg>
))}
</div>
{showArrows && (
<div className="img-slider-rc__arrows" style={{ position: "absolute", inset: 0, display: "flex", alignItems: "center", justifyContent: "space-between", padding: "0 8px", pointerEvents: "none" }}>
<label className="img-slider-rc__arrow img-slider-rc__arrow--for-1" htmlFor="img-slider-rc-s3" aria-label="Previous image">‹</label>
<label className="img-slider-rc__arrow img-slider-rc__arrow--for-1" htmlFor="img-slider-rc-s2" aria-label="Next image">›</label>
<label className="img-slider-rc__arrow img-slider-rc__arrow--for-2" htmlFor="img-slider-rc-s1" aria-label="Previous image">‹</label>
<label className="img-slider-rc__arrow img-slider-rc__arrow--for-2" htmlFor="img-slider-rc-s3" aria-label="Next image">›</label>
<label className="img-slider-rc__arrow img-slider-rc__arrow--for-3" htmlFor="img-slider-rc-s2" aria-label="Previous image">‹</label>
<label className="img-slider-rc__arrow img-slider-rc__arrow--for-3" htmlFor="img-slider-rc-s1" aria-label="Next image">›</label>
</div>
)}
</div>
<div style={{ display: "flex", gap: 8, justifyContent: "center", marginTop: 10 }}>
<label className="img-slider-rc__dot" htmlFor="img-slider-rc-s1" aria-label="Go to slide 1" style={{ display: "block", cursor: "pointer", background: "#24143033", ...dotSize }} />
<label className="img-slider-rc__dot" htmlFor="img-slider-rc-s2" aria-label="Go to slide 2" style={{ display: "block", cursor: "pointer", background: "#24143033", ...dotSize }} />
<label className="img-slider-rc__dot" htmlFor="img-slider-rc-s3" aria-label="Go to slide 3" style={{ display: "block", cursor: "pointer", background: "#24143033", ...dotSize }} />
</div>
<style>{`
.img-slider-rc__radio { position: absolute; opacity: 0; width: 1px; height: 1px; overflow: hidden; }
@media (prefers-reduced-motion: no-preference) {
.img-slider-rc__track { transition: transform .2s ease; }
}
#img-slider-rc-s1:checked ~ .img-slider-rc__viewport .img-slider-rc__track { transform: translateX(0%); }
#img-slider-rc-s2:checked ~ .img-slider-rc__viewport .img-slider-rc__track { transform: translateX(-33.333%); }
#img-slider-rc-s3:checked ~ .img-slider-rc__viewport .img-slider-rc__track { transform: translateX(-66.666%); }
.img-slider-rc__arrow { pointer-events: auto; display: none; align-items: center; justify-content: center; width: 28px; height: 28px; border-radius: 50%; background: #FAF7F2cc; color: #241430; cursor: pointer; font-size: 16px; line-height: 1; text-decoration: none; }
.img-slider-rc__arrow:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
#img-slider-rc-s1:checked ~ .img-slider-rc__viewport .img-slider-rc__arrow--for-1 { display: flex; }
#img-slider-rc-s2:checked ~ .img-slider-rc__viewport .img-slider-rc__arrow--for-2 { display: flex; }
#img-slider-rc-s3:checked ~ .img-slider-rc__viewport .img-slider-rc__arrow--for-3 { display: flex; }
.img-slider-rc__dot:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
#img-slider-rc-s1:checked ~ div label:nth-of-type(1),
#img-slider-rc-s2:checked ~ div label:nth-of-type(2),
#img-slider-rc-s3:checked ~ div label:nth-of-type(3) { background: var(--accent); }
`}</style>
</div>
);
}