Skip to content
Lenso UI

ProgressBar 进度条

进度条用于展示某项操作随时间变化的确定或不确定进度。

用法

import { ProgressBar, Label } from '@lenso/ui';

此预览复用英文版适配,不代表中文源示例已完成本地实现。

"use client";
import { ProgressBar } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";const styles = stylex.create({ progress: { width: 256 } });
export function Basic() {  return (    <ProgressBar aria-label="Loading" xstyle={styles.progress} value={60}>      <ProgressBar.Label>Loading</ProgressBar.Label>      <ProgressBar.Output />      <ProgressBar.Track>        <ProgressBar.Fill />      </ProgressBar.Track>    </ProgressBar>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

组件结构

import { ProgressBar, Label } from '@lenso/ui';
export default () => (  <ProgressBar value={60}>    <Label>Loading</Label>    <ProgressBar.Output />    <ProgressBar.Track>      <ProgressBar.Fill />    </ProgressBar.Track>  </ProgressBar>);

示例

尺寸

此预览复用英文版适配,不代表中文源示例已完成本地实现。

"use client";// Adapted from HeroUI v3.2.6 (Apache-2.0).import { ProgressBar } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";const styles = stylex.create({  column: { display: "flex", width: 256, flexDirection: "column", gap: 24 },});export function Sizes() {  return (    <div {...stylex.props(styles.column)}>      <ProgressBar aria-label="Small" size="sm" value={40}>        <ProgressBar.Label>Small</ProgressBar.Label>        <ProgressBar.Output />        <ProgressBar.Track>          <ProgressBar.Fill />        </ProgressBar.Track>      </ProgressBar>      <ProgressBar aria-label="Medium" size="md" value={60}>        <ProgressBar.Label>Medium</ProgressBar.Label>        <ProgressBar.Output />        <ProgressBar.Track>          <ProgressBar.Fill />        </ProgressBar.Track>      </ProgressBar>      <ProgressBar aria-label="Large" size="lg" value={80}>        <ProgressBar.Label>Large</ProgressBar.Label>        <ProgressBar.Output />        <ProgressBar.Track>          <ProgressBar.Fill />        </ProgressBar.Track>      </ProgressBar>    </div>  );}export default Sizes;

Local adaptation source above. Derived from HeroUI v3.2.6 source.

颜色

此预览复用英文版适配,不代表中文源示例已完成本地实现。

"use client";// Adapted from HeroUI v3.2.6 (Apache-2.0).import { ProgressBar } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";const styles = stylex.create({  column: { display: "flex", width: 256, flexDirection: "column", gap: 24 },});export function Colors() {  return (    <div {...stylex.props(styles.column)}>      {(["default", "accent", "success", "warning", "danger"] as const).map((color) => (        <ProgressBar key={color} color={color} value={50}>          <ProgressBar.Label>            {color[0]?.toUpperCase()}            {color.slice(1)}          </ProgressBar.Label>          <ProgressBar.Output />          <ProgressBar.Track>            <ProgressBar.Fill />          </ProgressBar.Track>        </ProgressBar>      ))}    </div>  );}export default Colors;

Local adaptation source above. Derived from HeroUI v3.2.6 source.

无可见标签

无需可见标签时,使用 aria-label 提供无障碍标签。

此预览复用英文版适配,不代表中文源示例已完成本地实现。

"use client";// Adapted from HeroUI v3.2.6 (Apache-2.0).import { ProgressBar } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";const styles = stylex.create({ progress: { width: 256 } });export function WithoutLabel() {  return (    <ProgressBar aria-label="Loading progress" xstyle={styles.progress} value={45}>      <ProgressBar.Track>        <ProgressBar.Fill />      </ProgressBar.Track>    </ProgressBar>  );}export default WithoutLabel;

Local adaptation source above. Derived from HeroUI v3.2.6 source.

不确定进度

无法确定进度时使用 isIndeterminate。

此预览复用英文版适配,不代表中文源示例已完成本地实现。

"use client";// Adapted from HeroUI v3.2.6 (Apache-2.0); null is Base UI's indeterminate value.import { ProgressBar } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";const styles = stylex.create({ progress: { width: 256 } });export function Indeterminate() {  return (    <ProgressBar aria-label="Loading" xstyle={styles.progress} value={null}>      <ProgressBar.Label>Loading...</ProgressBar.Label>      <ProgressBar.Track>        <ProgressBar.Fill />      </ProgressBar.Track>    </ProgressBar>  );}export default Indeterminate;

Local adaptation source above. Derived from HeroUI v3.2.6 source.

自定义数值范围

使用 minValue、maxValue 与 formatOptions 自定义取值范围与显示格式。

此预览复用英文版适配,不代表中文源示例已完成本地实现。

"use client";// Adapted from HeroUI v3.2.6 (Apache-2.0); native Base UI range and selection contracts.import { NumberField, ProgressBar, Select, Separator } from "@lenso/ui";import { useId, useState } from "react";import * as stylex from "@stylexjs/stylex";const formatStyleOptions = [  { label: "Currency", value: "currency" },  { label: "Percent", value: "percent" },  { label: "Decimal", value: "decimal" },  { label: "Unit", value: "unit" },];const formatOptionsMap: Record<string, Intl.NumberFormatOptions> = {  currency: { currency: "USD", style: "currency" },  decimal: { style: "decimal" },  percent: { style: "percent" },  unit: { style: "unit", unit: "mile" },};const styles = stylex.create({  root: {    display: "flex",    width: "100%",    flexDirection: { default: "column", "@media (min-width: 768px)": "row" },    alignItems: { default: "stretch", "@media (min-width: 768px)": "center" },    gap: { default: 24, "@media (min-width: 768px)": 40 },  },  preview: { display: "flex", width: "100%", maxWidth: 448, flex: 1, justifyContent: "center" },  progress: { width: "100%", maxWidth: 208 },  horizontal: { display: { default: "block", "@media (min-width: 768px)": "none" } },  vertical: { display: { default: "none", "@media (min-width: 768px)": "block" } },  options: { display: "flex", maxWidth: 208, flexDirection: "column", gap: 12 },  caption: { fontSize: 12, lineHeight: "16px", fontWeight: 500, color: "var(--muted)" },  field: { display: "flex", flexDirection: "column", gap: 4 },  label: { fontSize: 14, lineHeight: "20px", fontWeight: 500 },});export function CustomValue() {  const valueId = useId();  const minId = useId();  const maxId = useId();  const [value, setValue] = useState(750);  const [minValue, setMinValue] = useState(0);  const [maxValue, setMaxValue] = useState(1000);  const [format, setFormat] = useState("percent");  return (    <div {...stylex.props(styles.root)}>      <div {...stylex.props(styles.preview)}>        <ProgressBar          aria-label="Revenue"          xstyle={styles.progress}          format={formatOptionsMap[format]}          max={maxValue}          min={minValue}          value={value}        >          <ProgressBar.Label>Progress</ProgressBar.Label>          <ProgressBar.Output />          <ProgressBar.Track>            <ProgressBar.Fill />          </ProgressBar.Track>        </ProgressBar>      </div>      <Separator xstyle={styles.horizontal} />      <Separator xstyle={styles.vertical} orientation="vertical" />      <div {...stylex.props(styles.options)}>        <p {...stylex.props(styles.caption)}>Options</p>        <NumberField          id={valueId}          min={minValue}          max={maxValue}          value={value}          variant="secondary"          onValueChange={(next) => {            if (next !== null) setValue(next);          }}        >          <label htmlFor={valueId} {...stylex.props(styles.label)}>            Value          </label>          <NumberField.Group>            <NumberField.DecrementButton />            <NumberField.Input />            <NumberField.IncrementButton />          </NumberField.Group>        </NumberField>        <NumberField          id={minId}          min={0}          max={maxValue - 1}          value={minValue}          variant="secondary"          onValueChange={(next) => {            if (next === null) return;            setMinValue(next);            setValue((current) => Math.max(next, current));          }}        >          <label htmlFor={minId} {...stylex.props(styles.label)}>            Min Value          </label>          <NumberField.Group>            <NumberField.DecrementButton />            <NumberField.Input />            <NumberField.IncrementButton />          </NumberField.Group>        </NumberField>        <NumberField          id={maxId}          min={minValue + 1}          max={2000}          value={maxValue}          variant="secondary"          onValueChange={(next) => {            if (next === null) return;            setMaxValue(next);            setValue((current) => Math.min(next, current));          }}        >          <label htmlFor={maxId} {...stylex.props(styles.label)}>            Max Value          </label>          <NumberField.Group>            <NumberField.DecrementButton />            <NumberField.Input />            <NumberField.IncrementButton />          </NumberField.Group>        </NumberField>        <div {...stylex.props(styles.field)}>          <Select            variant="secondary"            value={format}            items={formatStyleOptions}            onValueChange={(next) => {              if (next !== null) setFormat(next);            }}          >            <Select.Label>Format</Select.Label>            <Select.Trigger>              <Select.Value />              <Select.Indicator />            </Select.Trigger>            <Select.Portal>              <Select.Positioner>                <Select.Popover>                  <Select.List>                    {formatStyleOptions.map((option) => (                      <Select.Item key={option.value} value={option.value}>                        <Select.ItemText>{option.label}</Select.ItemText>                        <Select.ItemIndicator />                      </Select.Item>                    ))}                  </Select.List>                </Select.Popover>              </Select.Positioner>            </Select.Portal>          </Select>        </div>      </div>    </div>  );}export default CustomValue;

Local adaptation source above. Derived from HeroUI v3.2.6 source.

自定义样式

Tailwind CSS

此预览复用英文版适配,不代表中文源示例已完成本地实现。

"use client";// Adapted from HeroUI v3.2.6 (Apache-2.0).import { ProgressBar } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";const styles = stylex.create({  progress: { width: 256 },  label: { fontWeight: 500, color: "var(--foreground)" },  output: {    fontSize: 12,    lineHeight: "16px",    color: "var(--muted)",    fontVariantNumeric: "tabular-nums",  },  track: { borderRadius: 9999, backgroundColor: "var(--default)" },  fill: { borderRadius: 9999, backgroundColor: "var(--accent)" },});export function CustomStyles() {  return (    <ProgressBar aria-label="Upload progress" xstyle={styles.progress} value={45}>      <ProgressBar.Label xstyle={styles.label}>Uploading resume.pdf</ProgressBar.Label>      <ProgressBar.Output xstyle={styles.output} />      <ProgressBar.Track xstyle={styles.track}>        <ProgressBar.Fill xstyle={styles.fill} />      </ProgressBar.Track>    </ProgressBar>  );}export default CustomStyles;

Local adaptation source above. Derived from HeroUI v3.2.6 source.

全局 CSS

若要自定义组件类,可使用 @layer components 指令。了解更多。

@layer components {  .progress-bar {    @apply w-full gap-2;  }
  .progress-bar__track {    @apply h-3 rounded-full;  }
  .progress-bar__fill {    @apply rounded-full;  }}

样式参考

HeroUI 遵循 BEM 方法论,确保组件变体与状态可复用且易于自定义。

CSS 类

ProgressBar 使用以下 CSS 类(查看源码样式):

基础与元素类 [!toc]

  • .progress-bar - 基础容器(网格布局)
  • .progress-bar__output - 数值文本展示
  • .progress-bar__track - 轨道背景
  • .progress-bar__fill - 轨道上已填充部分

尺寸类 [!toc]

  • .progress-bar--sm - 小尺寸变体(更细的轨道)
  • .progress-bar--md - 中等尺寸变体(默认)
  • .progress-bar--lg - 大尺寸变体(更粗的轨道)

颜色类 [!toc]

  • .progress-bar--default - 默认颜色变体
  • .progress-bar--accent - 强调色变体
  • .progress-bar--success - 成功色变体
  • .progress-bar--warning - 警告色变体
  • .progress-bar--danger - 危险色变体

API 参考

ProgressBar

继承自 React Aria ProgressBar。

Prop类型默认值描述
valuenumber0当前值
minValuenumber0最小值
maxValuenumber100最大值
isIndeterminatebooleanfalse是否为不确定进度
size"sm" | "md" | "lg""md"进度轨道尺寸
color"default" | "accent" | "success" | "warning" | "danger""accent"填充条颜色
formatOptionsIntl.NumberFormatOptions{style: 'percent'}数值展示的数字格式
valueLabelReactNode-自定义数值标签内容
childrenReactNode | (values: ProgressBarRenderProps) => ReactNode-内容或渲染 prop

ProgressBarRenderProps

使用渲染 prop 模式时,会提供以下值:

Prop类型描述
percentagenumber进度百分比(0–100)
valueTextstring格式化后的数值文本
isIndeterminateboolean是否为不确定进度

相关组件