<my-slider>
<h2 class="visually-hidden">Slides</h2>
<div class="slides">
<div class="slide active">
<h3>Slide 1</h3>
<hello-world>
<label>Your name<br>
<input type="text">
</label>
<p>Hello, <span>World</span>!</p>
</hello-world>
</div>
<div class="slide">
<h3>Slide 2</h3>
<spin-button value="0" zero-label="Add to Cart" increment-label="Increment">
<button type="button" class="decrement" aria-label="Decrement" hidden>−</button>
<p class="value" hidden>0</p>
<button type="button" class="increment primary">Add to Cart</button>
</spin-button>
</div>
<div class="slide">
<h3>Slide 3</h3>
<rating-feedback>
<form>
<rating-stars>
<fieldset>
<legend class="visually-hidden">Rate</legend>
<label>
<input type="radio" class="visually-hidden" name="rating" value="1">
<span class="label">☆</span>
</label>
<label>
<input type="radio" class="visually-hidden" name="rating" value="2">
<span class="label">☆</span>
</label>
<label>
<input type="radio" class="visually-hidden" name="rating" value="3">
<span class="label">☆</span>
</label>
<label>
<input type="radio" class="visually-hidden" name="rating" value="4">
<span class="label">☆</span>
</label>
<label>
<input type="radio" class="visually-hidden" name="rating" value="5">
<span class="label">☆</span>
</label>
</fieldset>
</rating-stars>
<div class="feedback" hidden>
<header>
<button button="button" class="hide" aria-label="Hide">×</button>
<p hidden>We're sorry to hear that! Your feedback is important, and we'd love to improve. Let us know how we can do better.</p>
<p hidden>Thank you for your honesty. We appreciate your feedback and will work on making things better.</p>
<p hidden>Thanks for your rating! If there's anything we can improve, we'd love to hear your thoughts.</p>
<p hidden>We're glad you had a good experience! If there's anything that could make it even better, let us know.</p>
<p hidden>Thank you for your support! We're thrilled you had a great experience. Your feedback keeps us motivated!</p>
</header>
<fieldset>
<label for="rating-feedback">Describe your experience (optional)</label>
<textarea id="rating-feedback"></textarea>
<input-button disabled>
<button type="submit" class="primary" disabled>Submit</button>
</input-button>
</fieldset>
</div>
</form>
</rating-feedback>
</div>
</div>
<button type="button" class="prev" aria-label="Previous">‹</button>
<button type="button" class="next" aria-label="Next">›</button>
<div class="dots">
<span class="active"></span>
<span></span>
<span></span>
</div>
</my-slider>
my-slider {
display: flex;
overflow: hidden;
aspect-ratio: 16 / 9;
position: relative;
.slides {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
}
.slide {
min-width: 100%;
text-align: center;
&:not(.active) {
display: none;
}
}
.dots {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
display: flex;
justify-content: center;
gap: var(--space-xs);
padding-block: var(--space-s);
> span {
width: var(--space-s);
height: var(--space-s);
border-radius: 50%;
background-color: var(--color-text);
opacity: var(--opacity-translucent);
&.active {
opacity: var(--opacity-solid);
}
}
}
> button {
position: absolute;
top: 2%;
height: 96%;
border: 0;
border-radius: var(--space-xs);
background: transparent;
padding: var(--space-m);
font-size: var(--font-size-xxl);
color: var(--color-text);
opacity: var(--opacity-dimmed);
transition: opacity var(--transition-short) var(--easing-inout);
&:hover,
&:active,
&:focus {
opacity: var(--opacity-solid);
background-color: rgba(0, 0, 0, 0.05);
}
&:active {
background-color: rgba(0, 0, 0, 0.1);
}
&.prev {
left: 1%;
}
&.next {
right: 1%;
}
}
}
import { type SignalValueProvider, UIElement, toggleClass } from "../../../"
export class MySlider extends UIElement<{ active: number }> {
static localName ='my-slider'
init = {
active: 0,
}
connectedCallback() {
super.connectedCallback()
// Event listeners for navigation
const total = this.querySelectorAll('.slide').length
const setNextSlide = (direction: number) => () => {
this.set('active', v => (v + direction + total) % total)
}
this.first('.prev').on('click', setNextSlide(-1))
this.first('.next').on('click', setNextSlide(1))
// Effects for updating slides and dots
const getActiveByIndex: SignalValueProvider<boolean> = (_, index) =>
this.get('active') === index
this.all('.slide').sync(toggleClass('active', getActiveByIndex))
this.all('.dots span').sync(toggleClass('active', getActiveByIndex))
}
}
MySlider.define()