Tessera UI

Components

Progress

How far along something is. Give it a value from 0 to max, or leave the value out when the length of the wait is not known.

The preview needs JavaScript. The code is in the Code tab.

Progress-0.tess
<template>
  <div>
    <Progress value="40" label="Uploading photo" />
    <Progress value="80" tone="neutral" size="sm" label="Storage used" />
    <Progress label="Waiting for the server" />
  </div>
</template>

Installation

npx @pixelscriptio/tessera add Progress
pnpm exec tessera add Progress
yarn tessera add Progress
bunx @pixelscriptio/tessera add Progress
  • Works with Tessera 0.9.0 or newer.
  1. Copy and paste the code into your project

    Put it in system/components.

    system/components/Progress.tess
    <contract>
    {
      "name": "Progress",
      "role": "progressbar",
      "description": "How far along something is. Give it a value from 0 to max, or leave the value out when the length of the wait is not known.",
      "since": "0.8.0",
      "parts": ["root", "bar"],
      "variants": {
        "size": ["md", "sm"], // first value is the default
        "tone": ["primary", "neutral", "danger"]
      },
      "preview": {
        "props": {
          "value": 60,
          "label": "Uploading photo"
        }
      }
    }
    </contract>
    
    <script>
    const { value, max, label } = props({ value: null, max: 100, label: 'Progress' })
    
    const percent = derived(() => {
      if (value.value === null) return 0
      return Math.round(Math.min(Math.max(value.value / max.value, 0), 1) * 100)
    })
    </script>
    
    <template>
      <div
        class="root"
        role="progressbar"
        :aria-label="label"
        aria-valuemin="0"
        :aria-valuemax="max"
        :aria-valuenow="value === null ? null : value"
        :data-indeterminate="value === null ? 'true' : null"
        >
        <div class="bar" :style="value === null ? null : 'width: ' + percent + '%'"></div>
      </div>
    </template>
    
    <style>
    .root {
      position: relative;
      width: 100%;
      height: $space.2;
      overflow: hidden;
      border-radius: $radius.full;
      background: $color.surface.hover;
    
      &[data-size='sm'] {
        height: $space.1;
      }
    }
    
    .bar {
      height: 100%;
      border-radius: $radius.full;
      background: $color.action.primary.bg;
      transition-duration: $motion.duration.fast;
    }
    
    .root[data-tone='neutral'] .bar {
      background: $color.text.muted;
    }
    
    .root[data-tone='danger'] .bar {
      background: $color.action.danger.bg;
    }
    
    .root[data-indeterminate='true'] .bar {
      width: 40%;
      animation: slide 1.2s ease-in-out infinite;
    }
    
    @keyframes slide {
      from {
        transform: translateX(-100%);
      }
      to {
        transform: translateX(250%);
      }
    }
    
    @media (prefers-reduced-motion: reduce) {
      .root[data-indeterminate='true'] .bar {
        animation: none;
        width: 100%;
        opacity: $opacity.disabled;
      }
    }
    </style>
    
  2. Check your design tokens

    Your design system needs these. tessera add reports the ones that are missing; by hand, run npx @pixelscriptio/tessera check.

    color.action.danger.bg color.action.primary.bg color.surface.hover color.text.muted motion.duration.fast opacity.disabled radius.full space.1 space.2

Usage

Using Progress

How far along something is.

  • value runs from 0 to max (100 unless you set it). The bar's width and what a screen reader hears are both set from it.
  • Leave value out when you do not know how long it will take: the bar moves back and forth, and the progress bar is announced without a value.
  • Give it a label that says what is progressing, such as Uploading photo. The default is Progress.
  • tone="danger" is for a failed upload that stays on screen. size="sm" is a thinner bar.

The preview needs JavaScript. The code is in the Code tab.

Progress-0.tess
<template>
  <div>
    <Progress value="40" label="Uploading photo" />
    <Progress value="80" tone="neutral" size="sm" label="Storage used" />
    <Progress label="Waiting for the server" />
  </div>
</template>

API reference

Variants

VariantValues
sizemd default sm
toneprimary default neutral danger

Anatomy

Roleprogressbar
Partsroot bar
Since0.8.0

Design tokens it uses

Your design system needs these. tessera add checks that it has them, and can add the ones it lacks.

color.action.danger.bg color.action.primary.bg color.surface.hover color.text.muted motion.duration.fast opacity.disabled radius.full space.1 space.2

Checksum

6f6fe2f23130a727357aac86bedb1e6334ef1a045474051dd604fed57bd6455f