Chuyển tới nội dung

Pro đang mở bán trước. Cài đặt mở từ tháng 1/2027. Xem Pro

Component

Stepper

Hiển thị các bước của một luồng theo thứ tự và vị trí người dùng đang ở (thanh toán, onboarding, thiết lập). Bước đã hoàn thành là button để quay lại bước đó; không đến được bước sắp tới từ đây. Dùng Tabs để chuyển view, không dùng cho một chuỗi tuần tự.

  • npm: 1 trực tiếp, 2 tổng
  • registry: 2 trực tiếp, 2 tổng

Xem trước

  1. Vận chuyển, bước hiện tại
  2. Thanh toán, chưa tới
  3. Xem xét, chưa tới

Props

  • orientation
  • size
  • icons
  • descriptions
import { Stepper } from "@/components/ui/stepper"

const checkoutSteps = [
  { id: "cart", label: "Giỏ hàng" },
  { id: "shipping", label: "Vận chuyển" },
  { id: "payment", label: "Thanh toán" },
  { id: "review", label: "Xem xét" },
]
const goToStep = (index: number) => { /* Hiện bước đó của luồng. */ }

<Stepper statusLabels={{ completed: "đã xong", current: "bước hiện tại", upcoming: "chưa tới", error: "có lỗi", goBack: "quay lại bước này" }} steps={checkoutSteps} current={1} onStepSelect={goToStep} />

Cách dùng

Khi nào dùng

  • Hiện vị trí của một người trong luồng theo thứ tự như thanh toán, onboarding hoặc thiết lập.
  • Cho phép quay lại bước đã hoàn thành mà không mở sớm các bước sắp tới.

Khi nào không dùng

  • Chuyển giữa các view của cùng nội dung. Dùng Tabs.
  • Hiện mức độ hoàn thành công việc mà không đặt tên các bước tuần tự. Dùng Progress.
  • Điều hướng giữa các trang hoặc phần. Dùng Sidebar hoặc BottomNav.

Biến thể

orientation

Hàng hoặc cột. Ở dạng cột, mỗi label nằm cạnh indicator và connector chạy xuống bước tiếp theo. Dùng vertical dưới md khi label không vừa, hoặc trong cột bên.

    1. Vận chuyển, bước hiện tại
    2. Thanh toán, chưa tới
    3. Xem xét, chưa tới

    horizontalmặc định

    1. Vận chuyển, bước hiện tại
    2. Thanh toán, chưa tới
    3. Xem xét, chưa tới

    vertical

import { Stepper } from "@/components/ui/stepper"

const checkoutSteps = [
  { id: "cart", label: "Giỏ hàng" },
  { id: "shipping", label: "Vận chuyển" },
  { id: "payment", label: "Thanh toán" },
  { id: "review", label: "Xem xét" },
]
const goToStep = (index: number) => { /* Hiện bước đó của luồng. */ }

<Stepper statusLabels={{ completed: "đã xong", current: "bước hiện tại", upcoming: "chưa tới", error: "có lỗi", goBack: "quay lại bước này" }} steps={checkoutSteps} current={1} onStepSelect={goToStep} />
<Stepper orientation="vertical" statusLabels={{ completed: "đã xong", current: "bước hiện tại", upcoming: "chưa tới", error: "có lỗi", goBack: "quay lại bước này" }} steps={checkoutSteps} current={1} onStepSelect={goToStep} />

size

Indicator 24, 32 hoặc 40px với icon 12, 16 hoặc 20px; label font-size-sm, -md hoặc -lg. sm cho cột bên và panel, lg cho trang onboarding thoáng. Một size cho mỗi vùng.

    1. Vận chuyển, bước hiện tại
    2. Thanh toán, chưa tới
    3. Xem xét, chưa tới

    sm

    1. Vận chuyển, bước hiện tại
    2. Thanh toán, chưa tới
    3. Xem xét, chưa tới

    mdmặc định

    1. Vận chuyển, bước hiện tại
    2. Thanh toán, chưa tới
    3. Xem xét, chưa tới

    lg

import { Stepper } from "@/components/ui/stepper"

const checkoutSteps = [
  { id: "cart", label: "Giỏ hàng" },
  { id: "shipping", label: "Vận chuyển" },
  { id: "payment", label: "Thanh toán" },
  { id: "review", label: "Xem xét" },
]
const goToStep = (index: number) => { /* Hiện bước đó của luồng. */ }

<Stepper size="sm" statusLabels={{ completed: "đã xong", current: "bước hiện tại", upcoming: "chưa tới", error: "có lỗi", goBack: "quay lại bước này" }} steps={checkoutSteps} current={1} onStepSelect={goToStep} />
<Stepper statusLabels={{ completed: "đã xong", current: "bước hiện tại", upcoming: "chưa tới", error: "có lỗi", goBack: "quay lại bước này" }} steps={checkoutSteps} current={1} onStepSelect={goToStep} />
<Stepper size="lg" statusLabels={{ completed: "đã xong", current: "bước hiện tại", upcoming: "chưa tới", error: "có lỗi", goBack: "quay lại bước này" }} steps={checkoutSteps} current={1} onStepSelect={goToStep} />

Ví dụ

Thanh toán

  1. Vận chuyển, current step
  2. Thanh toán, not reached
  3. Xem xét, not reached
import { Stepper } from "@/components/ui/stepper"

const checkoutSteps = [
  { id: "cart", label: "Giỏ hàng" },
  { id: "shipping", label: "Vận chuyển" },
  { id: "payment", label: "Thanh toán" },
  { id: "review", label: "Xem xét" },
]
const goToStep = (index: number) => { /* Hiện bước đó của luồng. */ }

<Stepper current={1} steps={checkoutSteps} onStepSelect={goToStep} />

Dọc, có mô tả

Mỗi label nằm trên đường giữa của indicator, với mô tả bên dưới.

  1. Nhóm, current stepMời mọi người
  2. Không gian làm việc, not reachedTên và địa chỉ
import { Stepper } from "@/components/ui/stepper"

const setupSteps = [
  { id: "account", label: "Tài khoản", description: "Email và mật khẩu" },
  { id: "team", label: "Nhóm", description: "Mời mọi người" },
  { id: "workspace", label: "Không gian làm việc", description: "Tên và địa chỉ" },
]
const goToStep = (index: number) => { /* Hiện bước đó của luồng. */ }

<Stepper orientation="vertical" current={1} steps={setupSteps} onStepSelect={goToStep} />

Có icon

Icon của bước thay số cho đến khi bước hoàn thành.

  1. Thanh toán, current step
  2. Xem xét, not reached
import { IconCreditCard, IconReceipt, IconShoppingCart, IconTruck } from "@tabler/icons-react"
import { Stepper } from "@/components/ui/stepper"

const iconSteps = [
  { id: "cart", label: "Giỏ hàng", icon: <IconShoppingCart size={16} /> },
  { id: "shipping", label: "Vận chuyển", icon: <IconTruck size={16} /> },
  { id: "payment", label: "Thanh toán", icon: <IconCreditCard size={16} /> },
  { id: "review", label: "Xem xét", icon: <IconReceipt size={16} /> },
]
const goToStep = (index: number) => { /* Hiện bước đó của luồng. */ }

<Stepper current={2} steps={iconSteps} onStepSelect={goToStep} />

Nhỏ, trong cột bên

  1. Nhóm, current stepMời mọi người
  2. Không gian làm việc, not reachedTên và địa chỉ
import { Stepper } from "@/components/ui/stepper"

const setupSteps = [
  { id: "account", label: "Tài khoản", description: "Email và mật khẩu" },
  { id: "team", label: "Nhóm", description: "Mời mọi người" },
  { id: "workspace", label: "Không gian làm việc", description: "Tên và địa chỉ" },
]
const goToStep = (index: number) => { /* Hiện bước đó của luồng. */ }

<Stepper orientation="vertical" size="sm" current={1} steps={setupSteps} onStepSelect={goToStep} />

Nên và không nên

Nên

  • Giữ label trong một hoặc hai từ.
  • Dùng 3 đến 7 bước; nhiều hơn thì cần nhóm lại.
  • Cho mọi bước một icon, hoặc không bước nào.
  • Cũng hiện số bước trong heading của trang (Bước 2 trên 4) khi Stepper bị ẩn trên màn hình nhỏ.

Không nên

  • Đừng dùng Tabs cho một chuỗi mà người dùng phải đi theo thứ tự.
  • Đừng dùng làm điều hướng tới các bước người dùng chưa đến.
  • Đừng trộn hai size của Stepper trên một màn hình.

Props

TênKiểuGiá trịMặc địnhMô tả
steps bắt buộc{ id: string; label: string; description?: string; status?: "error"; icon?: React.ReactNode }[]--Các bước theo thứ tự. icon thay số trên bước hiện tại hoặc bước sắp tới; indicator đặt kích thước và màu, còn bước đã hoàn thành và bước lỗi giữ icon check và icon cảnh báo. status error ghi đè trạng thái hiển thị được tính của bước đó.
current bắt buộcnumber--Chỉ số bắt đầu từ 0 của bước hiện tại. Các bước trước đó là đã hoàn thành.
orientationenumhorizontal | verticalhorizontalHàng hoặc cột. Ở dạng cột, mỗi label nằm cạnh indicator và connector chạy xuống bước tiếp theo. Dùng vertical dưới md khi label không vừa, hoặc trong cột bên.
sizeenumsm | md | lgmdIndicator 24, 32 hoặc 40px với icon 12, 16 hoặc 20px; label font-size-sm, -md hoặc -lg. sm cho cột bên và panel, lg cho trang onboarding thoáng. Một size cho mỗi vùng.
onStepSelect(index: number) => void--Được gọi với chỉ số khi một bước đã hoàn thành được kích hoạt, để quay lại bước đó. Type bắt buộc khi current lớn hơn 0, vì một bước trước đó có thể được kích hoạt.
statusLabels{ completed?: string; current?: string; upcoming?: string; error?: string; goBack?: string }--Từ thêm vào tên truy cập của mỗi bước, dạng {label}, {status}: { completed, current, upcoming, error }. Mặc định: completed, current step, not reached, has an error. Tiếng Việt: đã xong, bước hiện tại, chưa đến, có lỗi. goBack đặt tên button của bước đã hoàn thành: EN `{label}, completed, go back to this step`, VI `{label}, đã xong, quay lại bước này`.

Slot

TênBắt buộcMô tả
stepIconkhôngIcon tùy chọn cho mỗi bước, thay số trên bước hiện tại hoặc bước sắp tới (không bao giờ là icon check hoặc icon cảnh báo). Bất kỳ node SVG nào; indicator đặt kích thước và màu.

Cấu tạo

PhầnMô tả
rootol sắp các bước thành một hàng hoặc một cột.
stepMột li: nội dung (button trên bước đã hoàn thành) và các connector. Ở dạng hàng, indicator nằm trên label; ở dạng cột, nằm cạnh label, với khoảng trống bên dưới cho connector.
indicatorVòng tròn đặc, không có outline: số bước hoặc icon của bước, dấu check khi hoàn thành, icon cảnh báo khi lỗi. 24, 32 hoặc 40px theo size.
stepIndicatorIndicator bên trong button của bước đã hoàn thành. Hover và nhấn chỉ làm đậm vòng tròn, không phải một khung quanh label.
iconBất kỳ icon nào trong indicator (icon của bước, dấu check, cảnh báo): 12, 16 hoặc 20px theo size, màu theo trạng thái của bước.
labelTiêu đề bước, độ đậm medium ở bước hiện tại. Ở dạng cột, label nằm trên đường giữa của indicator.
descriptionDòng phụ tùy chọn dưới label.
connectorĐường 2px giữa hai indicator, có khoảng hở ở mỗi đầu; accent khi bước trước đã hoàn thành.

Khả năng truy cập

Role: list

PhímHành động
TabChuyển tới bước đã hoàn thành tiếp theo (một button). Bước hiện tại và bước sắp tới không focus được.
Enter / SpaceQuay lại bước đã hoàn thành đang focus thông qua onStepSelect.
  • Một danh sách có thứ tự. Bước hiện tại có aria-current="step" và đặt data-current.
  • Bước đã hoàn thành là một button có tên EN `{label}, completed, go back to this step`, VI `{label}, đã xong, quay lại bước này`.
  • Văn bản truy cập của mỗi bước gồm từ trạng thái (completed, current, upcoming, error) từ statusLabels, không chỉ icon hoặc màu.
  • Indicator bị ẩn với trình đọc màn hình: danh sách cho vị trí và label cho trạng thái. Các đường connector chỉ để trang trí (aria-hidden).
  • Bước có lỗi hiện icon cảnh báo trên nền danger mềm và từ từ statusLabels.error.
  • Button của bước đã hoàn thành đạt size-target-min theo chiều cao trên cảm ứng, qua ::before trong suốt.

Cài đặt

npx werewolf-ui add stepper

Chạy npx werewolf-ui init một lần trong app trước khi thêm component. Init cài token, thêm CSS import và luật cho agent. Add cài component này cùng các dependency và giữ nguyên theme của bạn. Xem Cài đặt để biết yêu cầu và cách cài qua registry.