<div class="atm-range-slider" data-component="range-slider">
<div class="slider-wrapper">
<label for="age-slider">Leeftijd</label>
<div class="slider-track">
<input type="range" id="age-slider" name="age" min="15" max="40" value="24" step="1">
<div class="slider-value"><span>24</span></div>
</div>
</div>
</div>
<div class="atm-range-slider" data-component="range-slider">
<div class="slider-wrapper">
<label for="{{id}}">{{label}}</label>
<div class="slider-track">
<input type="range" id="{{id}}" name="{{name}}" min="{{min}}" max="{{max}}" value="{{value}}" step="{{step}}">
<div class="slider-value"><span>{{value}}</span></div>
</div>
</div>
</div>
{
"id": "age-slider",
"name": "age",
"label": "Leeftijd",
"min": 15,
"max": 40,
"value": 24,
"step": 1
}
.atm-range-slider {
@apply relative mb-8 text-white font-display;
.slider-wrapper {
@apply flex items-center gap-8;
}
label {
@apply text-lg whitespace-nowrap min-w-[100px];
}
.slider-value {
@apply absolute bg-links text-black rounded-md flex items-center justify-center h-7 w-8 cursor-pointer text-md;
transform: translate(-50%, -50%);
top: 50%;
z-index: 3;
user-select: none;
}
.slider-track {
@apply relative h-2 flex-1;
}
input[type='range'] {
@apply absolute w-full h-4 appearance-none cursor-pointer;
background: transparent;
z-index: 2;
}
/* White background track */
.slider-track::before {
content: '';
@apply absolute top-1/2 -translate-y-1/2 w-full h-1 bg-white rounded-full;
z-index: 1;
}
/* Orange filled track */
.slider-track::after {
content: '';
@apply absolute top-1/2 -translate-y-1/2 h-1 bg-links rounded-full;
left: 0;
width: var(--fill-width, 0%);
z-index: 2;
}
/* Hide default thumb */
input[type='range']::-webkit-slider-thumb {
@apply appearance-none;
width: 0;
height: 0;
background: transparent;
}
input[type='range']::-moz-range-thumb {
width: 0;
height: 0;
border: 0;
background: transparent;
}
input[type='range']::-ms-thumb {
width: 0;
height: 0;
background: transparent;
}
}
(function () {
'use strict';
function initRangeSliders(context) {
const sliders = (context || document).querySelectorAll('[data-component="range-slider"]');
sliders.forEach(slider => {
const input = slider.querySelector('input[type="range"]');
const valueDisplay = slider.querySelector('.slider-value span');
const valueBox = slider.querySelector('.slider-value');
const track = slider.querySelector('.slider-track');
function updateValue() {
const { min, max } = getSliderValues();
const value = parseFloat(input.value) || 0;
const percentage = ((value - min) / (max - min)) * 100;
// Update value display
if (valueDisplay) {
valueDisplay.textContent = value;
}
// Update visual position and fill
if (valueBox && track) {
valueBox.style.left = `${percentage}%`;
track.style.setProperty('--fill-width', `${percentage}%`);
}
}
function updateValueFromPosition(clientX) {
const rect = track.getBoundingClientRect();
const { min, max, step } = getSliderValues();
// Calculate position ratio (0-1) from mouse position
const positionRatio = Math.max(0, Math.min(1, (clientX - rect.left) / rect.width));
// Convert position to value and apply step constraints
const rawValue = min + positionRatio * (max - min);
const steppedValue = Math.round(rawValue / step) * step;
const clampedValue = Math.max(min, Math.min(max, steppedValue));
// Update input and trigger events
input.value = clampedValue;
updateValue();
input.dispatchEvent(new Event('input', { bubbles: true }));
}
function getSliderValues() {
return {
min: parseFloat(input.min) || 0,
max: parseFloat(input.max) || 100,
step: parseFloat(input.step) || 1
};
}
let isDragging = false;
// Make value box draggable
valueBox.addEventListener('mousedown', (e) => {
isDragging = true;
e.preventDefault();
});
// Click on track to set value
track.addEventListener('click', (e) => {
if (e.target === track || e.target === track.querySelector('::before')) {
updateValueFromPosition(e.clientX);
}
});
document.addEventListener('mousemove', (e) => {
if (isDragging) {
updateValueFromPosition(e.clientX);
}
});
document.addEventListener('mouseup', () => {
isDragging = false;
});
// Touch support
valueBox.addEventListener('touchstart', (e) => {
isDragging = true;
e.preventDefault();
});
document.addEventListener('touchmove', (e) => {
if (isDragging && e.touches.length > 0) {
updateValueFromPosition(e.touches[0].clientX);
}
});
document.addEventListener('touchend', () => {
isDragging = false;
});
input.addEventListener('input', updateValue);
updateValue(); // Initial value
});
}
// Initial load
initRangeSliders();
// Expose to global scope for re-initialization if needed
window.initRangeSliders = initRangeSliders;
})();
No notes defined.