Prisma
Live Preview
65
40%
40
$200
$800
$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.jsonslider · 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"
/>