Goal Tracker

Q4 goals

October 1 – December 31

Grow the self-serve revenue

On track
78%78% Owner: Growth
  • Monthly recurring revenue 182k$ / 240k$
  • Trial to paid conversion 9.2% / 12%
  • New paying teams 410 / 500

Make onboarding effortless

At risk
48%48% Owner: Product
  • Activation in the first week 38% / 60%
  • Time to first published page 2 / 6 of 6 steps shipped
@use 'sprucecss/scss/spruce' as *;

.goal-tracker {
  @include layout-stack('m');

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

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

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

  &__goal {
    --goal-color: #{color('success', 'alert')};
    background-color: color('surface');
    border: config('border-width-base', $display) solid color('border');
    border-radius: radius('lg');
    padding: spacer('m');
    @include layout-stack('s');

    &--at-risk {
      --goal-color: #{color('warning', 'alert')};
    }

    &--behind {
      --goal-color: #{color('danger', 'alert')};
    }
  }

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

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

  &__summary {
    align-items: center;
    display: flex;
    flex-wrap: wrap;
    gap: spacer('xxs') spacer('s');
  }

  &__progress {
    accent-color: var(--goal-color);
    block-size: 0.6rem;
    flex: 1 1 12rem;
  }

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

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

  &__results {
    border-block-start: config('border-width-base', $display) solid color('border');
    list-style: none;
    padding: spacer('s') 0 0;
    @include layout-stack('s');
  }

  &__result {
    align-items: baseline;
    display: grid;
    font-size: config('font-size-sm', $typography);
    gap: spacer('xxs') spacer('s');
    grid-template-columns: minmax(0, 1fr) auto;
  }

  &__result-value {
    color: color('heading');
    font-variant-numeric: tabular-nums;
    font-weight: 600;

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

  &__bar {
    background-color: color('surface-muted');
    block-size: 0.3rem;
    border-radius: radius('pill');
    grid-column: 1 / -1;
    overflow: hidden;

    &::before {
      background-color: var(--goal-color);
      block-size: 100%;
      border-radius: inherit;
      content: '';
      display: block;
      inline-size: var(--value);
    }
  }
}

// The progress element follows the goal color in every browser.
.goal-tracker__progress::-webkit-progress-value {
  background-color: var(--goal-color);
}

.goal-tracker__progress::-moz-progress-bar {
  background-color: var(--goal-color);
}
<section class="goal-tracker" aria-labelledby="goal-tracker-title">
    <header class="goal-tracker__header">
        <h2 class="goal-tracker__title" id="goal-tracker-title">Q4 goals</h2>
        <p class="goal-tracker__quarter">October 1 – December 31</p>
    </header>
    <article class="goal-tracker__goal goal-tracker__goal--on-track" aria-labelledby="goal-1">
        <header class="goal-tracker__goal-header">
            <h3 class="goal-tracker__goal-title" id="goal-1">Grow the self-serve revenue</h3>
            <span class="badge badge--success">On track</span>
        </header>
        <div class="goal-tracker__summary">
            <progress class="goal-tracker__progress" max="100" value="78" aria-labelledby="goal-1">78%</progress>
            <span class="goal-tracker__percent">78%</span>
            <span class="goal-tracker__owner">Owner: Growth</span>
        </div>
        <ul class="goal-tracker__results" role="list">
            <li class="goal-tracker__result">
                <span class="goal-tracker__result-text">Monthly recurring revenue</span>
                <span class="goal-tracker__result-value">182k$ <span>/ 240k$</span></span>
                <span class="goal-tracker__bar" style="--value: 76%;" aria-hidden="true"></span>
            </li>
            <li class="goal-tracker__result">
                <span class="goal-tracker__result-text">Trial to paid conversion</span>
                <span class="goal-tracker__result-value">9.2% <span>/ 12%</span></span>
                <span class="goal-tracker__bar" style="--value: 77%;" aria-hidden="true"></span>
            </li>
            <li class="goal-tracker__result">
                <span class="goal-tracker__result-text">New paying teams</span>
                <span class="goal-tracker__result-value">410 <span>/ 500</span></span>
                <span class="goal-tracker__bar" style="--value: 82%;" aria-hidden="true"></span>
            </li>
        </ul>
    </article>
    <article class="goal-tracker__goal goal-tracker__goal--at-risk" aria-labelledby="goal-2">
        <header class="goal-tracker__goal-header">
            <h3 class="goal-tracker__goal-title" id="goal-2">Make onboarding effortless</h3>
            <span class="badge badge--warning">At risk</span>
        </header>
        <div class="goal-tracker__summary">
            <progress class="goal-tracker__progress" max="100" value="48" aria-labelledby="goal-2">48%</progress>
            <span class="goal-tracker__percent">48%</span>
            <span class="goal-tracker__owner">Owner: Product</span>
        </div>
        <ul class="goal-tracker__results" role="list">
            <li class="goal-tracker__result">
                <span class="goal-tracker__result-text">Activation in the first week</span>
                <span class="goal-tracker__result-value">38% <span>/ 60%</span></span>
                <span class="goal-tracker__bar" style="--value: 63%;" aria-hidden="true"></span>
            </li>
            <li class="goal-tracker__result">
                <span class="goal-tracker__result-text">Time to first published page</span>
                <span class="goal-tracker__result-value">2 <span>/ 6 of 6 steps shipped</span></span>
                <span class="goal-tracker__bar" style="--value: 33%;" aria-hidden="true"></span>
            </li>
        </ul>
    </article>
</section>

Goal Tracker

Objectives and key results (OKRs) for a period: every goal with its status, overall progress, owner and the progress of its key results.

Anatomy

  • .goal-tracker__goal: one objective as an article, with a status modifier (--on-track, --at-risk, --behind) that sets the --goal-color.
  • .goal-tracker__summary: a progress element with the overall percentage and the owner.
  • .goal-tracker__results: the key results with their current value, target and a __bar.

Accessibility and Usability

  • The status is a Badge with a word ("At risk"); the color repeats it.
  • The overall progress is labeled by the goal title (aria-labelledby), so it's announced as "Grow the self-serve revenue, 72%".
  • The key result bars are decorative; the values next to them are the content.

Technical Details

  • The overall progress comes with the data: the average of the key results' progress, each capped at 100%, so an overachieved result can't hide a lagging one. The key result bars are capped the same way in the template.
  • The progress and the bars use the --goal-color custom property, set by the status modifier.
  • Units of up to two characters (%, k$) are attached to the numbers; longer ones ("of 6 steps shipped") follow the target.

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.