Usage Meter

Plan usage

Pro plan · Resets on

Upgrade
  • 8,420 / 10,000
    8,420 of 10,000

    84% used. Consider upgrading before the end of the month.

  • 98,100 / 100,000
    98,100 of 100,000

    98% used. At this rate, you’ll reach the limit in 2 days.

  • 3 / 5
    3 of 5

Storage

7.2 GB / 10 GB
  • Images 4.1 GB
  • Videos 2.3 GB
  • Documents 0.8 GB
  • Free 2.8 GB
@use 'sprucecss/scss/spruce' as *;

.usage-meter {
  --usage-meter-color-1: #{color('primary')};
  --usage-meter-color-2: #{color('info', 'alert')};
  --usage-meter-color-3: #{color('warning', 'alert')};
  background-color: color('surface');
  border: config('border-width-base', $display) solid color('border');
  border-radius: radius('lg');
  padding: spacer('m');
  @include layout-stack('m');

  &__header {
    align-items: flex-start;
    display: flex;
    gap: spacer('s');
    justify-content: space-between;
  }

  &__heading {
    @include layout-stack('xxs');
  }

  &__title {
    font-size: font-size('h5');
  }

  &__plan {
    color: color('muted');
    font-size: config('font-size-sm', $typography);
  }

  &__list {
    // The parent's layout-stack sets the margins.
    list-style: none;
    padding: 0;
    @include layout-stack('m');
  }

  &__item {
    @include layout-stack('xs');
  }

  &__row {
    align-items: baseline;
    display: flex;
    flex-wrap: wrap;
    gap: spacer('xxs') spacer('s');
    justify-content: space-between;
  }

  &__label {
    color: color('heading');
    font-family: inherit;
    font-size: config('font-size-base', $typography);
    font-weight: 600;
    margin: 0;
  }

  &__amount {
    color: color('heading');
    font-variant-numeric: tabular-nums;
    font-weight: 700;

    span {
      color: color('muted');
      font-weight: 400;
    }
  }

  &__meter {
    block-size: 0.5rem;
  }

  &__note {
    align-items: center;
    display: flex;
    font-size: config('font-size-sm', $typography);
    gap: spacer('xxs');

    &::before {
      aspect-ratio: 1;
      border-radius: 50%;
      content: '';
      flex-shrink: 0;
      inline-size: 0.5rem;
    }

    &--warning::before {
      background-color: color('warning', 'alert');
    }

    &--danger::before {
      background-color: color('danger', 'alert');
    }
  }

  &__storage {
    border-block-start: config('border-width-base', $display) solid color('border');
    padding-block-start: spacer('m');
    @include layout-stack('xs');
  }

  &__stack {
    background-color: color('progress-background', 'form');
    block-size: 0.5rem;
    border-radius: radius('pill');
    display: flex;
    gap: 2px;
    overflow: hidden;

    span {
      inline-size: var(--share);

      @for $i from 1 through 3 {
        &:nth-child(#{$i}) {
          background-color: var(--usage-meter-color-#{$i});
        }
      }
    }
  }

  &__legend {
    color: color('muted');
    font-size: config('font-size-sm', $typography);
    // The parent's layout-stack sets the margins.
    list-style: none;
    padding: 0;
    @include layout-cluster('xs:s');

    li {
      align-items: center;
      display: inline-flex;
      gap: spacer('xxs');
      margin: 0;

      &::before {
        background-color: color('progress-background', 'form');
        block-size: 0.625rem;
        border-radius: radius('sm');
        content: '';
        inline-size: 0.625rem;
      }

      @for $i from 1 through 3 {
        &:nth-child(#{$i})::before {
          background-color: var(--usage-meter-color-#{$i});
        }
      }
    }

    strong {
      color: color('heading');
    }

    // The items sit side by side: clear the stack margins of the base list style.
    > li {
      margin-block: 0;
      padding-block: 0;
    }
  }
}
<section class="usage-meter" aria-labelledby="usage-meter-title">
    <header class="usage-meter__header">
        <div class="usage-meter__heading">
            <h3 class="usage-meter__title" id="usage-meter-title">Plan usage</h3>
            <p class="usage-meter__plan">Pro plan · Resets on <time datetime="2026-11-01">November 1</time></p>
        </div>
        <a class="btn btn--primary btn--sm" href="#">Upgrade</a>
    </header>
    <ul class="usage-meter__list" role="list">
        <li class="usage-meter__item">
            <div class="usage-meter__row">
                <label class="usage-meter__label" for="usage-orders">Orders</label>
                <span class="usage-meter__amount">8,420 <span>/ 10,000</span></span>
            </div>
            <meter class="usage-meter__meter" id="usage-orders" min="0" max="10000" low="7500" high="9000" optimum="0" value="8420">8,420 of 10,000</meter>
            <p class="usage-meter__note usage-meter__note--warning">84% used. Consider upgrading before the end of the month.</p>
        </li>
        <li class="usage-meter__item">
            <div class="usage-meter__row">
                <label class="usage-meter__label" for="usage-api">API requests</label>
                <span class="usage-meter__amount">98,100 <span>/ 100,000</span></span>
            </div>
            <meter class="usage-meter__meter" id="usage-api" min="0" max="100000" low="75000" high="90000" optimum="0" value="98100">98,100 of 100,000</meter>
            <p class="usage-meter__note usage-meter__note--danger">98% used. At this rate, you’ll reach the limit in 2 days.</p>
        </li>
        <li class="usage-meter__item">
            <div class="usage-meter__row">
                <label class="usage-meter__label" for="usage-staff">Staff accounts</label>
                <span class="usage-meter__amount">3 <span>/ 5</span></span>
            </div>
            <meter class="usage-meter__meter" id="usage-staff" min="0" max="5" low="4" high="5" optimum="0" value="3">3 of 5</meter>
        </li>
    </ul>
    <div class="usage-meter__storage">
        <div class="usage-meter__row">
            <h4 class="usage-meter__label">Storage</h4>
            <span class="usage-meter__amount">7.2 GB <span>/ 10 GB</span></span>
        </div>
        <div class="usage-meter__stack" aria-hidden="true">
            <span style="--share: 41%;"></span>
            <span style="--share: 23%;"></span>
            <span style="--share: 8%;"></span>
        </div>
        <ul class="usage-meter__legend" role="list">
            <li>Images <strong>4.1 GB</strong></li>
            <li>Videos <strong>2.3 GB</strong></li>
            <li>Documents <strong>0.8 GB</strong></li>
            <li>Free <strong>2.8 GB</strong></li>
        </ul>
    </div>
</section>

Usage Meter

The usage of a subscription plan against its limits, with native meter elements that change color as the usage grows, and a stacked storage breakdown.

Anatomy

  • .usage-meter__item: a label, the amount, a meter and an optional __note (--warning or --danger).
  • .usage-meter__storage: a stacked bar (__stack, one span per category with its --share in percent) and its __legend.

Accessibility and Usability

  • A meter is a labelable element: the label names it, and screen readers announce its value ("Orders, 8,420 of 10,000"). The fallback text inside the element is shown in browsers without meter support.
  • The warning and danger notes say the percentage and the consequence in words; the color is only a hint.
  • The stacked bar is decorative (aria-hidden); its legend lists the exact values.

Technical Details

  • No JavaScript for the colors: the low, high and optimum attributes make the browser pick the state. With optimum="0" (low is good), a value below low is green, between low and high is yellow and above high is red. Spruce styles the three states with the alert colors.
  • Use <progress> instead of meter for a task that moves toward completion; a meter is a measurement within a known range.
  • The storage colors are --usage-meter-color-1 to --usage-meter-color-3; the empty part of the bar shows the track color (free space).

Documentation

Learn about Spruce CSS through our extensive documentation.

Components

Explore our UI library of accessible components built with Spruce CSS.

Blocks and Pages

Full-width page blocks and complete page templates, ready to copy.

Find us on GitHub

Did you find a bug? Have an idea or a question? Please open an issue to help us develop the project.