API
value · max(기본 100) · status(active/success/error/paused) · width · height
접근성
role=progressbar + aria-valuenow/min/max 자동 적용
상태 소유권
status는 막대 색만 제어하고 원인·복구 문구는 wrapper가 설명합니다.
권장
실제 완료율이 없으면 Spinner 사용 (허위 진행 금지)

기본

결정 진행률을 단계별로 비교

0%

50%

100%

코드 보기tsx
import { Progress } from "@olundot/ui";

// Progress는 role=progressbar + aria-valuenow/min/max를 자동 적용.
// max: 기본 100, width: 기본 120px, height: 기본 4px.
export function ProgressBasic() {
  return (
    <div style={{ display: "grid", gap: "16px" }}>
      <div>
        <p style={{ marginBottom: "8px", fontSize: "0.875rem", color: "var(--text-secondary)" }}>0%</p>
        <Progress value={0} width="100%" aria-label="0퍼센트 진행률" />
      </div>
      <div>
        <p style={{ marginBottom: "8px", fontSize: "0.875rem", color: "var(--text-secondary)" }}>50%</p>
        <Progress value={50} width="100%" aria-label="50퍼센트 진행률" />
      </div>
      <div>
        <p style={{ marginBottom: "8px", fontSize: "0.875rem", color: "var(--text-secondary)" }}>100%</p>
        <Progress value={100} width="100%" aria-label="100퍼센트 진행률" />
      </div>
    </div>
  );
}

조절 가능한 진행률

input range로 value 조정
문항 가져오기35%
코드 보기tsx
import { useState } from "react";
import { Progress } from "@olundot/ui";

export function ProgressLive() {
  const [value, setValue] = useState(35);
  return (
    <div style={{ display: "grid", gap: "12px" }}>
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
        <span style={{ fontSize: "0.875rem", color: "var(--text-secondary)" }}>
          문항 가져오기
        </span>
        <span style={{ fontSize: "0.875rem", fontVariantNumeric: "tabular-nums" }}>
          {value}%
        </span>
      </div>
      <Progress value={value} width="100%" height={6} aria-label="문항 가져오기 진행률" />
      <input
        type="range"
        min={0}
        max={100}
        value={value}
        onChange={(e) => setValue(Number(e.target.value))}
        style={{ width: "100%" }}
        aria-label="진행률 조절"
      />
    </div>
  );
}

두께 비교

표면 밀도에 맞춰 진행 막대 두께 선택

4px (기본)

6px

8px

코드 보기tsx
import { Progress } from "@olundot/ui";

export function ProgressSizes() {
  return (
    <div style={{ display: "grid", gap: "16px" }}>
      <div>
        <p style={{ marginBottom: "8px", fontSize: "0.875rem", color: "var(--text-secondary)" }}>4px (기본)</p>
        <Progress value={72} width="100%" height={4} />
      </div>
      <div>
        <p style={{ marginBottom: "8px", fontSize: "0.875rem", color: "var(--text-secondary)" }}>6px</p>
        <Progress value={72} width="100%" height={6} />
      </div>
      <div>
        <p style={{ marginBottom: "8px", fontSize: "0.875rem", color: "var(--text-secondary)" }}>8px</p>
        <Progress value={72} width="100%" height={8} />
      </div>
    </div>
  );
}

중단·오류·사용 불가

status는 막대 색, 원인과 복구 문구는 wrapper가 소유
문항 업로드일시 중지
네트워크 확인 후 이어서 진행합니다.
자동 채점오류
실패 원인을 확인하고 다시 실행합니다.
리포트 생성완료
모든 리포트가 생성되었습니다.
코드 보기tsx
import { Progress } from "@olundot/ui";

const PROGRESS_STATES = [
  {
    label: "문항 업로드",
    status: "일시 중지",
    progressStatus: "paused",
    value: 64,
    helper: "네트워크 확인 후 이어서 진행합니다.",
  },
  {
    label: "자동 채점",
    status: "오류",
    progressStatus: "error",
    value: 38,
    helper: "실패 원인을 확인하고 다시 실행합니다.",
  },
  {
    label: "리포트 생성",
    status: "완료",
    progressStatus: "success",
    value: 100,
    helper: "모든 리포트가 생성되었습니다.",
  },
];

export function ProgressStates() {
  return (
    <div style={{ display: "grid", gap: "16px" }}>
      {PROGRESS_STATES.map(({ label, status, progressStatus, value, helper }) => (
        <div
          key={label}
          style={{ display: "grid", gap: "8px" }}
        >
          <div style={{ display: "flex", justifyContent: "space-between", gap: "12px" }}>
            <span style={{ fontSize: "0.875rem", color: "var(--text-secondary)" }}>{label}</span>
            <span style={{ fontSize: "0.875rem", color: "var(--text-secondary)" }}>{status}</span>
          </div>
          <Progress status={progressStatus} value={value} width="100%" height={6} aria-label={`${label} ${status}`} />
          <span style={{ fontSize: "0.8125rem", color: "var(--text-tertiary)" }}>{helper}</span>
        </div>
      ))}
    </div>
  );
}