@arc-lang/arc-sliders
v0.1.0
Published
CSS scroll-snap carousel, before/after comparison slider, and enhanced infinite marquee. CSS-first, ~700B optional JS, zero dependencies.
Maintainers
Readme
arc-sliders
Five CSS-first UI slider components. CSS drives everything — the optional JS (~1KB total) adds interactivity only where CSS alone cannot.
Part of Arc — the zero-dependency web framework.
Install
npm install arc-slidersCDN:
<link rel="stylesheet" href="https://unpkg.com/arc-sliders/index.css">Components
Carousel
CSS scroll-snap carousel. Works without JS — users can swipe and scroll natively. Add js/carousel.js for prev/next buttons and dot sync.
<div class="carousel" style="--slides-visible: 2; --carousel-gap: 16px;">
<div class="carousel__track">
<div class="carousel__slide">Slide 1</div>
<div class="carousel__slide">Slide 2</div>
<div class="carousel__slide">Slide 3</div>
</div>
<button class="carousel__prev">←</button>
<button class="carousel__next">→</button>
<div class="carousel__dots">
<button class="carousel__dot is-active"></button>
<button class="carousel__dot"></button>
<button class="carousel__dot"></button>
</div>
</div>
<script src="https://unpkg.com/arc-sliders/js/carousel.js"></script>| Modifier | Effect |
|----------|--------|
| .carousel--peek | Reveals edge of next slide (set --carousel-peek) |
| .carousel--fade | Fades track edges with mask-image |
| .carousel--vertical | Vertical scroll-snap (set --carousel-height) |
| .carousel--crossfade | Crossfade between slides (opacity transition, no scroll) |
| .carousel--loop | True infinite loop — no content duplication needed |
Infinite loop: Add .carousel--loop — JS clones the minimum number of edge slides needed to fill one viewport, then uses scrollend to silently reset position when the user reaches a clone. Requires no content duplication in HTML. Requires scrollend event support (Chrome 114+, Firefox 109+, Safari 17.4+).
Autoplay: Add data-autoplay="3000" for 3s auto-advance. Pauses on hover/focus, skipped if prefers-reduced-motion is active. Works with .carousel--loop.
<div class="carousel" data-autoplay="4000">...</div>| CSS property | Default | Description |
|---|---|---|
| --slides-visible | 1 | How many slides show at once |
| --carousel-gap | 0px | Gap between slides |
| --carousel-peek | 0px | How much of the next slide to reveal |
| --carousel-height | 400px | Height for vertical and crossfade carousels |
| --carousel-crossfade-duration | 0.5s | Transition duration for .carousel--crossfade |
| --carousel-dot-color | rgba(0,0,0,0.25) | Inactive dot color |
| --carousel-dot-active | #000 | Active dot color |
Comparison
Before/after image reveal. Drag the handle or use arrow keys to compare. JS sets --comparison-split; CSS drives the entire visual via clip-path.
<div class="comparison" style="height: 400px;">
<img class="comparison__before" src="before.jpg" alt="Before">
<img class="comparison__after" src="after.jpg" alt="After">
<div class="comparison__handle"></div>
<span class="comparison__label-before">Before</span>
<span class="comparison__label-after">After</span>
</div>
<script src="https://unpkg.com/arc-sliders/js/comparison.js"></script>| CSS property | Default | Description |
|---|---|---|
| --comparison-split | 50% | Divider position (set by JS on drag) |
| --comparison-handle-color | #fff | Handle line and knob color |
| --comparison-handle-size | 44px | Knob diameter |
Accessibility: Keyboard navigable (arrow keys ±5%), role="slider", aria-valuenow — all added automatically by js/comparison.js.
Marquee
Enhanced infinite scrolling ticker. Duplicate content inside .marquee__track for a seamless loop.
<div class="marquee marquee--pause-hover marquee--fade">
<div class="marquee__track">
<span class="marquee__item">Item <span class="marquee__sep"></span></span>
<span class="marquee__item">Item <span class="marquee__sep"></span></span>
<!-- duplicate for seamless loop -->
<span class="marquee__item">Item <span class="marquee__sep"></span></span>
<span class="marquee__item">Item <span class="marquee__sep"></span></span>
</div>
</div>| Modifier | Effect |
|----------|--------|
| .marquee--reverse | Scrolls right instead of left |
| .marquee--pause-hover | Pauses on hover (opt-in) |
| .marquee--slow | 40s duration |
| .marquee--fast | 10s duration |
| .marquee--fade | Fades left/right edges |
| .marquee--vertical | Vertical scrolling |
| CSS property | Default | Description |
|---|---|---|
| --marquee-duration | 20s | Animation speed |
| --marquee-gap | 2rem | Gap between items |
Range
Styled <input type="range"> — single or dual handle. CSS custom properties control colors and sizing; JS (js/range.js) syncs the fill bar and prevents handles from crossing in dual mode.
<!-- Single handle -->
<div class="range">
<input type="range" min="0" max="100" value="40">
</div>
<!-- Dual handle -->
<div class="range range--dual">
<input type="range" min="0" max="100" value="20">
<input type="range" min="0" max="100" value="80">
</div>
<script src="https://unpkg.com/arc-sliders/js/range.js"></script>| CSS property | Default | Description |
|---|---|---|
| --range-track-height | 4px | Track thickness |
| --range-thumb-size | 18px | Thumb diameter |
| --range-color | #3b82f6 | Thumb + fill color |
| --range-track-color | #e2e8f0 | Unfilled track color |
| --range-track-fill | var(--range-color) | Fill bar color (override separately) |
Scroll progress + fade-in-view
Pure CSS, zero JS. Uses animation-timeline: scroll() and animation-timeline: view().
Browser support: Chrome 115+, Firefox 114+, Safari 18+. Graceful fallback: bar invisible, content visible.
<!-- Reading progress bar (place once near top of <body>) -->
<div class="scroll-progress"></div>
<!-- Reveal element as it enters the viewport -->
<div class="fade-in-view">Any content</div>| CSS property | Default | Description |
|---|---|---|
| --scroll-progress-height | 3px | Progress bar height |
| --scroll-progress-color | #3b82f6 | Progress bar color |
Tree-shaking
Import only what you need:
<link rel="stylesheet" href="https://unpkg.com/arc-sliders/src/base.css">
<link rel="stylesheet" href="https://unpkg.com/arc-sliders/src/marquee.css">| File | Size (approx) |
|------|---------------|
| src/base.css | ~0.5 KB |
| src/carousel.css | ~2 KB |
| src/comparison.css | ~1.5 KB |
| src/marquee.css | ~1.5 KB |
| src/range.css | ~1.5 KB |
| src/scroll.css | ~0.5 KB |
| js/carousel.js | ~600 B |
| js/comparison.js | ~400 B |
| js/range.js | ~300 B |
| Full bundle | ~7.5 KB CSS + ~1.3 KB JS |
Browser support
| Feature | Chrome | Firefox | Safari | Edge | |---------|--------|---------|--------|------| | Carousel (scroll-snap) | 69+ | 68+ | 11+ | 79+ | | Comparison (clip-path) | 55+ | 54+ | 9.1+ | 79+ | | Marquee (CSS animations) | 43+ | 16+ | 9+ | 79+ | | Marquee fade (mask-image) | 120+ | — | 15.4+ | 120+ | | Range (input styling) | 4+ | 23+ | 4+ | 12+ | | Scroll progress (animation-timeline) | 115+ | 114+ | 18+ | 115+ | | Fade-in-view (animation-timeline) | 115+ | 114+ | 18+ | 115+ |
Accessibility
prefers-reduced-motion: marquee pauses; carouselscroll-behaviorcollapses to instant; carousel autoplay is skipped; crossfade is instant; scroll progress shows static- Comparison slider: keyboard navigable (←/→ keys ±5%),
role="slider",aria-valuenow— added automatically by the JS - Carousel buttons: standard
<button>elements, keyboard-focusable - Range inputs: native
<input type="range">semantics — full keyboard, screen reader, and platform accessibility built in - Focus ring: comparison container gets
:focus-visiblering (2px,#5956f0)
License
MIT © Arc contributors
