Live Preview
$0$1,000
Slider / Range Component
Skill này hướng dẫn tạo component Slider — chọn giá trị trong khoảng bằng cách kéo thumb trên track.
1. Mục tiêu (Objective)
Tạo component Slider cho chọn giá trị trong khoảng: volume, price filter, rating. Hỗ trợ single value, range (min-max), và discrete steps.
2. AI Context & Intent (Ngữ cảnh cho AI)
Khi nào dùng Slider?
- Volume/brightness: Single continuous value
- Price filter: Min-max range for products
- Rating scale: 1-5 stars via discrete slider
- Settings: Opacity, font size, spacing
⚠️ Phân biệt Slider vs Input[number] vs Stepper (QUAN TRỌNG)
| Tiêu chí | Slider | Number Input | Stepper (+/−) |
|---|---|---|---|
| Bản chất | Drag thumb on track | Type exact number | Click +/− buttons |
| Best for | Approximate values | Exact values | Small increments |
| Range visible | ✅ Visual track | ❌ No context | ❌ No context |
| Precision | Low-medium | High | Medium |
| Ví dụ | Volume control | Quantity: 42 | Item count: +/− |
Decision Tree cho AI
text
Cần chọn giá trị số?
├─ Approximate value, range visible → Slider
│ ├─ Single value → Slider (single)
│ ├─ Min-max range → Slider (range, 2 thumbs)
│ ├─ Fixed steps (1-5, 1-10) → Slider (discrete + ticks)
│ └─ Vertical (equalizer) → Slider (vertical)
│
├─ Exact value cần typed → Number Input
├─ Small increments → Stepper (+/−)
└─ Percentage → Slider hoặc Progress Bar (read-only)
3. Anatomy
text
value tooltip
┌───┐
│ 45│ ← Tooltip: --surface bg (on drag)
└─┬─┘
Min label ◉ Max label
0 ━━━━━━━━━━━━●━━━━━━━━━━━━ 100
↑ filled ↑ thumb ↑ track
--primary --primary --muted
Range:
$100 ━━━━━━●━━━━━━━━━●━━━━━━ $1000
↑ min ↑ max
thumb thumb
Discrete with ticks:
1 ━━●━━━━●━━━━●━━━━●━━━━● 5
│ │ │ │ │
tick marks (--border)
4. Platform Mapping
| Platform | Component | Key Difference |
|---|---|---|
| Web | <input type="range"> / Slider |
Custom styled track + thumb |
| iOS | UISlider | Rounded track, circular thumb |
| Android (M3) | Slider | Tick marks, value label |
| Fluent | Slider | Horizontal/vertical, snap to grid |
| Carbon | Slider | With text input for exact value |
Cross-platform: ALL platforms, consistent drag interaction.
5. Types
| Type | Mô tả |
|---|---|
single |
One thumb, single value |
range |
Two thumbs, min-max range |
discrete |
Stepped values with tick marks |
5.4. Slot Map (Figma ↔ Code)
📎 Source:
slot-manifest.json→slider· Layer: item
| Figma Slot | data-slot |
CSS Class | Required | Accepts |
|---|---|---|---|---|
| Root | slider |
.slider |
✅ | — |
| Track | slider-track |
— | ✅ | — |
| Fill | slider-fill |
— | ✅ | — |
| Thumb | slider-thumb |
— | ✅ | — |
| Label | slider-label |
— | ❌ | text, value |
6. Token Mapping
📦 Atomic Mapping: Xem
ATOMIC-MAPPING.md→ mục slider — Density Tier: comp.Track bg dùng
--muted, fill bg dùng--primary, thumb bg dùng--primary, thumb border dùng--background(ring). Component token JSON files đã deprecated.
7. Props & API
typescript
interface SliderProps {
value?: number | [number, number];
min?: number;
max?: number;
step?: number;
type?: 'single' | 'range' | 'discrete';
showTooltip?: boolean;
showTicks?: boolean;
showMinMax?: boolean;
disabled?: boolean;
orientation?: 'horizontal' | 'vertical';
onChange: (value: number | [number, number]) => void;
'aria-label': string;
}
8. Accessibility (a11y)
role="slider",aria-valuenow,aria-valuemin,aria-valuemax.- Range: 2 sliders, each with
aria-label("Minimum price", "Maximum price"). - Keyboard:
Arrow Left/Right±1 step,Page Up/Down±10%,Home/End= min/max.
9. Best Practices & Rules
- Touch target: Thumb minimum 44px touch area (expand hitbox beyond visual).
- Value tooltip: Show on drag, hide on release.
- Discrete ticks: Only for ≤ 10 steps. More → continuous.
- Không Hardcode: Mọi giá trị từ Token.
10. Example Usage
jsx
{/* Volume control */}
<Slider
value={volume}
min={0}
max={100}
onChange={setVolume}
aria-label="Volume"
/>
{/* Price range filter */}
<Slider
type="range"
value={[minPrice, maxPrice]}
min={0}
max={1000}
step={10}
showTooltip
showMinMax
onChange={([min, max]) => setPriceRange(min, max)}
aria-label="Price range"
/>
{/* Rating discrete */}
<Slider
type="discrete"
value={rating}
min={1}
max={5}
step={1}
showTicks
onChange={setRating}
aria-label="Rating"
/>