Prisma
Live Preview
Uploading...65%
Complete100%
Loading...30%

Progress Bar Component

Skill này hướng dẫn tạo component Progress Bar — hiển thị tiến trình determinate/indeterminate cho upload, loading, step completion.

1. Mục tiêu (Objective)

Tạo component Progress Bar cho hiển thị determinate/indeterminate progress: upload, loading, step completion. Hỗ trợ nhiều sizes, variants, và types.

2. AI Context & Intent (Ngữ cảnh cho AI)

Khi nào dùng Progress Bar?

  • File upload: Show upload progress 0-100%
  • Step completion: 3/5 steps done → 60%
  • Loading content: Indeterminate while fetching data
  • Form validation: Password strength meter

⚠️ Phân biệt Progress Bar vs Spinner vs Skeleton (QUAN TRỌNG)

Tiêu chí Progress Bar Spinner Skeleton
Bản chất Linear bar Circular animation Content placeholder
Best for Known progress (%) Unknown duration Known layout, loading
Info shown Exact percentage Just "loading" Visual content preview
Shape Horizontal bar Circle Mimics content
Ví dụ File upload (45%) Button loading Page skeleton

Decision Tree cho AI

text
Cần show loading state?
├─ Biết progress % chính xác → Progress Bar (determinate)
│   ├─ Upload/download → Progress Bar + label (%)
│   ├─ Step completion → Progress Bar + "3 of 5"
│   └─ Dual progress → Progress Bar (buffer type)
│
├─ Không biết duration → chọn theo context:
│   ├─ Biết content layout → Skeleton
│   ├─ Inline nhỏ → Spinner (xs/sm)
│   ├─ Button loading → Spinner (button variant)
│   ├─ Section loading → Progress Bar (indeterminate)
│   └─ Page loading → Spinner (xl) hoặc Skeleton
│
└─ Process status theo steps → Stepper

3. Anatomy

text
Determinate:
  Uploading... 45%
  ┌──────────────────────────────┐
  │████████████░░░░░░░░░░░░░░░░░│ ← Track: --muted bg
  └──────────────────────────────┘   Fill: --primary bg
                                     Radius: --radius-full

Buffer (YouTube-style):
  Buffering...
  ┌──────────────────────────────┐
  │████████▓▓▓▓▓░░░░░░░░░░░░░░░│ ← Fill ████ + Buffer ▓▓▓
  └──────────────────────────────┘

Indeterminate:
  Loading...
  ┌──────────────────────────────┐
  │░░░░████████░░░░░░░░░░░░░░░░░│ ← Animated sliding fill
  └──────────────────────────────┘

4. Platform Mapping

Platform Component Key Difference
Web <progress> / ProgressBar Linear horizontal bar
iOS UIProgressView Thin linear bar, tinting
Android (M3) LinearProgressIndicator Determinate + indeterminate
Fluent ProgressBar Linear with label
Carbon ProgressBar With percentage label

Cross-platform: ALL platforms, consistent UX.

5. Variants

Variant Mô tả
default Primary color fill
success Green fill — completed
warning Yellow fill — attention needed
error Red fill — failed/blocked

Types

Type Mô tả
determinate Known progress 0–100%
indeterminate Unknown duration, animation loop
buffer YouTube-style: loaded + played

Sizes

sm (2px), md (4px), lg (8px)

5.4. Slot Map (Figma ↔ Code)

📎 Source: slot-manifest.jsonprogress · Layer: item

Figma Slot data-slot CSS Class Required Accepts
Root progress .progress-bar
Track progress-track
Fill progress-fill .progress-fill
Label progress-label text, percentage

6. Token Mapping

📦 Atomic Mapping: Xem ATOMIC-MAPPING.md → mục progress — Density Tier: comp.

Track bg dùng --muted, fill bg dùng --primary (default), radius dùng --radius-full. Variants dùng --warning, --success. Component token JSON files đã deprecated.

7. Props & API

typescript
interface ProgressBarProps {
  value?: number;           // 0–100, undefined = indeterminate
  variant?: 'default' | 'success' | 'warning' | 'error';
  size?: 'sm' | 'md' | 'lg';
  showLabel?: boolean;      // Show percentage text
  bufferValue?: number;     // Buffer progress (0–100)
  'aria-label': string;
}

8. Accessibility (a11y)

  • role="progressbar", aria-valuenow, aria-valuemin="0", aria-valuemax="100".
  • Indeterminate: omit aria-valuenow.
  • aria-label required (e.g., "Uploading file").

9. Best Practices & Rules

  • Animation: Smooth width transition for determinate, CSS animation for indeterminate.
  • Stripe animation: Optional animated stripes for active progress.
  • Label position: Inside bar when lg, above/below when sm/md.
  • Không Hardcode: Mọi giá trị từ Token.

10. Example Usage

jsx
{/* File upload progress */}
<ProgressBar
  value={uploadPercent}
  showLabel
  aria-label="Uploading document"
/>

{/* Step completion */}
<ProgressBar
  value={(completedSteps / totalSteps) * 100}
  variant="success"
  size="lg"
  aria-label="Onboarding progress"
/>

{/* Indeterminate loading */}
<ProgressBar
  variant="default"
  size="sm"
  aria-label="Loading content"
/>

{/* Buffer (streaming) */}
<ProgressBar
  value={playedPercent}
  bufferValue={loadedPercent}
  size="sm"
  aria-label="Video progress"
/>