Progress

Visually represents the completion status of a task, process, or page load status.

Class name Type
.prs-progress Component Container
.prs-progress-radial Component Container
.prs-progress-label Component Container
.prs-loading Component Container
  • <div class="w-96 max-w-xs space-y-8"> <!-- <- this is just for demo purposes -->
      <!-- determinate -->
      <progress class="prs-progress" value="30" max="100">30%</progress>
    
      <!-- labels -->
      <div class="prs-progress-label">
        <label for="progress-1">Processing...</label>
        <progress id="progress-1" class="prs-progress" value="75" max="100">75%</progress>
        <label for="progress-1">75%</label>
      </div>
    
      <!-- aria-label alternative -->
      <progress class="prs-progress" value="75" max="100" aria-label="Loading...">75%</progress>
    
      <!-- indeterminate: remove value and max attr -->
      <progress class="prs-progress" aria-label="Content loading..."></progress>
    </div>
    
  • Radial

    For stat display or dashboard use cases.

    <div class="prs-progress-radial" style="--value: 75" role="progressbar" aria-valuenow="75">75%</div>
    
    <!-- color + thickness + size adjustment -->
    <div
      class="prs-progress-radial"
      style="
        --value: 33.3;
        --size: 9rem;
        --thickness: 0.125rem;
        --track: var(--prs-c-red-400);
        border: 0.5rem solid var(--prs-c-red);
        background-color: var(--prs-c-red);
        color: var(--prs-c-white);
      "
      role="progressbar"
      aria-valuenow="33.3"
    >33.3%</div>
    
  • <div class="prs-loading">
      <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 56 56" width="56" height="56" fill="currentColor">
        <g>
          <rect x="0" y="24" width="8" height="8">
            <animate attributeName="y" attributeType="XML" dur="1s" begin="0.0s" values="24; 0; 24; 24; 24" repeatCount="indefinite"></animate>
            <animate attributeName="height" attributeType="XML" dur="1s" begin="0.0s" values="8; 56; 8; 8; 8" repeatCount="indefinite"></animate>
          </rect>
          <rect x="12" y="24" width="8" height="8">
            <animate attributeName="y" attributeType="XML" dur="1s" begin="0.1s" values="24; 0; 24; 24; 24" repeatCount="indefinite"></animate>
            <animate attributeName="height" attributeType="XML" dur="1s" begin="0.1s" values="8; 56; 8; 8; 8" repeatCount="indefinite"></animate>
          </rect>
          <rect x="24" y="24" width="8" height="8">
            <animate attributeName="y" attributeType="XML" dur="1s" begin="0.2s" values="24; 0; 24; 24; 24" repeatCount="indefinite"></animate>
            <animate attributeName="height" attributeType="XML" dur="1s" begin="0.2s" values="8; 56; 8; 8; 8" repeatCount="indefinite"></animate>
          </rect>
          <rect x="36" y="24" width="8" height="8">
            <animate attributeName="y" attributeType="XML" dur="1s" begin="0.3s" values="24; 0; 24; 24; 24" repeatCount="indefinite"></animate>
            <animate attributeName="height" attributeType="XML" dur="1s" begin="0.3s" values="8; 56; 8; 8; 8" repeatCount="indefinite"></animate>
          </rect>
          <rect x="48" y="24" width="8" height="8">
            <animate attributeName="y" attributeType="XML" dur="1s" begin="0.4s" values="24; 0; 24; 24; 24" repeatCount="indefinite"></animate>
            <animate attributeName="height" attributeType="XML" dur="1s" begin="0.4s" values="8; 56; 8; 8; 8" repeatCount="indefinite"></animate>
          </rect>
          <rect x="60" y="24" width="8" height="8">
            <animate attributeName="y" attributeType="XML" dur="1s" begin="0.5s" values="24; 0; 24; 24; 24" repeatCount="indefinite"></animate>
            <animate attributeName="height" attributeType="XML" dur="1s" begin="0.5s" values="8; 56; 8; 8; 8" repeatCount="indefinite"></animate>
          </rect>
        </g>
      </svg>
    </div>
    

CSS

Full Library

Component Only

.prs-progress {
  appearance: none;
  width: 100%;
  height: 0.75rem;
  background-color: var(--prs-c-white);
  border: 1px solid var(--prs-c-gray-300);
  overflow: hidden;
  position: relative;
  border-radius: var(--prs-radius-input);

  &::-webkit-progress-bar {
    background-color: transparent;
  }

  &::-moz-progress-bar {
    background-color: var(--prs-c-red);
  }

  &::-webkit-progress-value {
    background-color: var(--prs-c-red);
    border-radius: var(--prs-radius-input);
    transition-property: width;
    transition-timing-function: var(--prs-transition-timing);
    transition-duration: var(--prs-transition-duration);
  }

  &:indeterminate {
    background-image: repeating-linear-gradient(90deg, rgba(0, 0, 0, 0.1) -1%, rgba(0, 0, 0, 0.1) 10%, transparent 10%, transparent 90%);
    background-size: 200%;
    background-position-x: 15%;
    animation: progress-loading 5s ease-in-out infinite;

    &::-moz-progress-bar {
      background-color: transparent;
      background-image: repeating-linear-gradient(90deg, rgba(0, 0, 0, 0.1) -1%, rgba(0, 0, 0, 0.1) 10%, transparent 10%, transparent 90%);
      background-size: 200%;
      background-position-x: 15%;
      animation: progress-loading 5s ease-in-out infinite;
    }
  }
}

.prs-progress-label {
  width: 100%;
  display: flex;
  gap: 0.25rem;
  flex-direction: column;

  progress + label {
    font-size: 0.75rem;
    line-height: 1.125rem;
  }
}

.prs-loading {
  color: var(--prs-c-red);
}

.prs-progress-radial {
  --value: 0;
  --size: 5rem;
  --thickness: calc(var(--size) / 10);
  --track: transparent;
  --radialprogress: calc(var(--value) * 1%);
  box-sizing: content-box;
  width: var(--size);
  height: var(--size);
  background-color: transparent;
  display: inline-grid;
  place-content: center;
  vertical-align: middle;
  position: relative;
  border-radius: 3.40282e38px;
  transition: --radialprogress 0.3s linear;

  &:before {
    background: conic-gradient(currentColor var(--radialprogress), var(--track, transparent) 0);
    -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - var(--thickness)), #000 calc(100% + 0.5px - var(--thickness)));
    mask: radial-gradient(farthest-side, transparent calc(100% - var(--thickness)), #000 calc(100% + 0.5px - var(--thickness)));
    position: absolute;
    inset: 0;
    content: '';
    border-radius: 3.40282e38px;
  }
}

@keyframes progress-loading {
  50% {
    background-position-x: -115%;
  }
}

Figma

Coming soon...