# Slider Component Usage
## Overview
The slider component allows users to select a value from a range by moving a thumb along a track. It's ideal for settings like volume, brightness, or any continuous value selection. The component uses native HTML range input with enhanced styling.
## JavaScript Requirements
### Required Scripts
```html
<!-- Include Basecoat CSS and JavaScript -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/basecoat-css@latest/dist/basecoat.cdn.min.css">
<script src="https://cdn.jsdelivr.net/npm/basecoat-css@latest/dist/js/basecoat.min.js" defer></script>
<script src="https://cdn.jsdelivr.net/npm/basecoat-css@latest/dist/js/slider.min.js" defer></script>
```
## HTML Structure
### Basic Slider
```html
<input type="range" class="slider" min="0" max="100" value="50">
```
### Slider with Label
```html
<div class="grid gap-3">
<label for="volume" class="label">Volume</label>
<input type="range" id="volume" class="slider" min="0" max="100" value="50">
</div>
```
### Slider with Value Display
```html
<div class="grid gap-3">
<div class="flex items-center justify-between">
<label for="brightness" class="label">Brightness</label>
<span id="brightness-value" class="text-muted-foreground text-sm">50%</span>
</div>
<input
type="range"
id="brightness"
class="slider"
min="0"
max="100"
value="50"
oninput="document.getElementById('brightness-value').textContent = this.value + '%'"
>
</div>
```
## Attributes
### Range Attributes
```html
<!-- Standard range -->
<input type="range" class="slider" min="0" max="100" value="50">
<!-- Custom step -->
<input type="range" class="slider" min="0" max="100" value="50" step="10">
<!-- Decimal values -->
<input type="range" class="slider" min="0" max="1" value="0.5" step="0.1">
<!-- Disabled slider -->
<input type="range" class="slider" min="0" max="100" value="50" disabled>
```
## Implementation Examples
### Volume Control
```html
<div class="w-full max-w-sm">
<div class="flex items-center gap-3">
<svg class="size-5 text-muted-foreground" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"></polygon>
</svg>
<input type="range" id="volume-slider" class="slider flex-1" min="0" max="100" value="75">
<svg class="size-5 text-muted-foreground" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"></polygon>
<path d="M19.07 4.93a10 10 0 0 1 0 14.14M15.54 8.46a5 5 0 0 1 0 7.07"></path>
</svg>
</div>
</div>
```
### Price Range Filter
```html
<div class="space-y-4 w-full max-w-sm">
<h4 class="font-medium">Price Range</h4>
<div class="space-y-3">
<div class="flex items-center justify-between text-sm">
<span class="text-muted-foreground">Min</span>
<span id="min-price-value">$0</span>
</div>
<input
type="range"
id="min-price"
class="slider w-full"
min="0"
max="1000"
value="0"
step="50"
oninput="document.getElementById('min-price-value').textContent = '$' + this.value"
>
</div>
<div class="space-y-3">
<div class="flex items-center justify-between text-sm">
<span class="text-muted-foreground">Max</span>
<span id="max-price-value">$1000</span>
</div>
<input
type="range"
id="max-price"
class="slider w-full"
min="0"
max="1000"
value="1000"
step="50"
oninput="document.getElementById('max-price-value').textContent = '$' + this.value"
>
</div>
</div>
```
### Settings Sliders
```html
<form class="form space-y-6 w-full max-w-md">
<h3 class="text-lg font-medium">Display Settings</h3>
<div class="space-y-6">
<div class="grid gap-3">
<div class="flex items-center justify-between">
<label for="brightness-setting" class="label">Brightness</label>
<span id="brightness-value" class="text-muted-foreground text-sm tabular-nums">50%</span>
</div>
<input
type="range"
id="brightness-setting"
class="slider"
min="0"
max="100"
value="50"
oninput="document.getElementById('brightness-value').textContent = this.value + '%'"
>
</div>
<div class="grid gap-3">
<div class="flex items-center justify-between">
<label for="contrast-setting" class="label">Contrast</label>
<span id="contrast-value" class="text-muted-foreground text-sm tabular-nums">50%</span>
</div>
<input
type="range"
id="contrast-setting"
class="slider"
min="0"
max="100"
value="50"
oninput="document.getElementById('contrast-value').textContent = this.value + '%'"
>
</div>
<div class="grid gap-3">
<div class="flex items-center justify-between">
<label for="saturation-setting" class="label">Saturation</label>
<span id="saturation-value" class="text-muted-foreground text-sm tabular-nums">50%</span>
</div>
<input
type="range"
id="saturation-setting"
class="slider"
min="0"
max="100"
value="50"
oninput="document.getElementById('saturation-value').textContent = this.value + '%'"
>
</div>
</div>
<button type="submit" class="btn">Apply Settings</button>
</form>
```
### Font Size Selector
```html
<div class="space-y-3 w-full max-w-sm">
<div class="flex items-center justify-between">
<label for="font-size" class="label">Font Size</label>
<span id="font-size-value" class="text-muted-foreground text-sm">16px</span>
</div>
<div class="flex items-center gap-3">
<span class="text-xs text-muted-foreground">A</span>
<input
type="range"
id="font-size"
class="slider flex-1"
min="12"
max="24"
value="16"
step="1"
oninput="
document.getElementById('font-size-value').textContent = this.value + 'px';
document.getElementById('preview-text').style.fontSize = this.value + 'px';
"
>
<span class="text-xl text-muted-foreground">A</span>
</div>
<p id="preview-text" class="text-center p-4 border rounded-lg" style="font-size: 16px">
Preview text at selected size
</p>
</div>
```
### Stepped Slider with Labels
```html
<div class="space-y-3 w-full max-w-sm">
<label for="quality" class="label">Video Quality</label>
<input
type="range"
id="quality"
class="slider w-full"
min="0"
max="4"
value="2"
step="1"
>
<div class="flex justify-between text-xs text-muted-foreground">
<span>360p</span>
<span>480p</span>
<span>720p</span>
<span>1080p</span>
<span>4K</span>
</div>
</div>
<script>
const qualitySlider = document.getElementById('quality');
const qualityLabels = ['360p', '480p', '720p', '1080p', '4K'];
qualitySlider.addEventListener('input', function() {
const quality = qualityLabels[this.value];
console.log('Selected quality:', quality);
});
</script>
```
## JavaScript Events
### Input Event (Continuous Updates)
```javascript
const slider = document.getElementById('volume-slider');
const valueDisplay = document.getElementById('volume-value');
slider.addEventListener('input', function() {
valueDisplay.textContent = this.value + '%';
// This fires continuously while dragging
});
```
### Change Event (Final Value)
```javascript
const slider = document.getElementById('volume-slider');
slider.addEventListener('change', function() {
console.log('Final value:', this.value);
// This fires when the user stops dragging
saveUserPreference('volume', this.value);
});
```
### Programmatic Value Setting
```javascript
function setSliderValue(id, value) {
const slider = document.getElementById(id);
if (slider) {
slider.value = value;
// Trigger events if needed
slider.dispatchEvent(new Event('input', { bubbles: true }));
slider.dispatchEvent(new Event('change', { bubbles: true }));
}
}
// Usage
setSliderValue('volume-slider', 75);
```
## Accessibility Guidelines
### ARIA Requirements
```html
<div class="grid gap-3">
<label id="volume-label" for="volume-slider">Volume</label>
<input
type="range"
id="volume-slider"
class="slider"
min="0"
max="100"
value="50"
aria-labelledby="volume-label"
aria-valuemin="0"
aria-valuemax="100"
aria-valuenow="50"
aria-valuetext="50 percent"
>
</div>
```
### Keyboard Navigation
- **Left/Down Arrow**: Decrease value by step
- **Right/Up Arrow**: Increase value by step
- **Home**: Jump to minimum value
- **End**: Jump to maximum value
- **Page Up**: Increase by larger increment
- **Page Down**: Decrease by larger increment
### Screen Reader Announcements
```javascript
const slider = document.getElementById('volume-slider');
slider.addEventListener('input', function() {
// Update ARIA attributes for screen readers
this.setAttribute('aria-valuenow', this.value);
this.setAttribute('aria-valuetext', this.value + ' percent');
});
```
## Best Practices
### When to Use Sliders
- Continuous value ranges
- Settings adjustments (volume, brightness)
- Filtering numerical ranges
- Non-critical value selection
### When to Use Other Components
- Precise values needed: Use Input with type="number"
- Discrete options: Use Select or Radio Group
- On/Off: Use Switch
### Visual Guidelines
- Always show the current value
- Provide clear min/max indicators
- Use appropriate step values
- Consider touch-friendly sizing on mobile
### Value Display
```javascript
// Format values appropriately
function formatSliderValue(value, type) {
switch(type) {
case 'percent':
return value + '%';
case 'currency':
return '$' + value.toLocaleString();
case 'time':
const mins = Math.floor(value / 60);
const secs = value % 60;
return `${mins}:${secs.toString().padStart(2, '0')}`;
default:
return value;
}
}
```
## Form Integration
### Using with Form Class
```html
<form class="form grid gap-6">
<div class="grid gap-3">
<div class="flex items-center justify-between">
<label for="donation" class="label">Donation Amount</label>
<span id="donation-value" class="font-medium">$50</span>
</div>
<input
type="range"
id="donation"
name="donation"
class="slider"
min="10"
max="500"
value="50"
step="10"
oninput="document.getElementById('donation-value').textContent = '$' + this.value"
>
<div class="flex justify-between text-xs text-muted-foreground">
<span>$10</span>
<span>$500</span>
</div>
</div>
<button type="submit" class="btn">Donate</button>
</form>
```
### Validation
```javascript
const form = document.querySelector('form');
const slider = document.querySelector('#donation');
form.addEventListener('submit', function(e) {
const value = parseInt(slider.value);
if (value < 10) {
e.preventDefault();
showError('Minimum donation is $10');
}
});
```
## Common Patterns
### Range Slider with Dual Thumbs (Custom Implementation)
```html
<div class="relative w-full max-w-sm">
<div class="flex items-center justify-between mb-2">
<label class="label">Price Range</label>
<span class="text-sm text-muted-foreground">
$<span id="range-min">100</span> - $<span id="range-max">500</span>
</span>
</div>
<div class="relative h-2 bg-muted rounded-full">
<div id="range-track" class="absolute h-full bg-primary rounded-full" style="left: 10%; right: 50%"></div>
<input
type="range"
id="min-slider"
class="absolute w-full pointer-events-none appearance-none bg-transparent"
min="0"
max="1000"
value="100"
>
<input
type="range"
id="max-slider"
class="absolute w-full pointer-events-none appearance-none bg-transparent"
min="0"
max="1000"
value="500"
>
</div>
</div>
```
### Slider with Tooltip
```javascript
const slider = document.getElementById('volume-slider');
const tooltip = document.createElement('div');
tooltip.className = 'absolute -top-8 transform -translate-x-1/2 bg-foreground text-background px-2 py-1 rounded text-xs hidden';
slider.parentElement.style.position = 'relative';
slider.parentElement.appendChild(tooltip);
slider.addEventListener('input', function() {
const percent = (this.value - this.min) / (this.max - this.min);
const thumbOffset = percent * this.offsetWidth;
tooltip.style.left = thumbOffset + 'px';
tooltip.textContent = this.value + '%';
tooltip.classList.remove('hidden');
});
slider.addEventListener('mouseleave', function() {
tooltip.classList.add('hidden');
});
```