Deployment List

Deployments

Redeploy
@use 'sprucecss/scss/spruce' as *;

.deployment-list {
  background-color: color('surface');
  border: config('border-width-base', $display) solid color('border');
  border-radius: radius('lg');
  overflow: hidden;

  &__header {
    align-items: center;
    border-block-end: config('border-width-base', $display) solid color('border');
    display: flex;
    gap: spacer('s');
    justify-content: space-between;
    padding: spacer('s') spacer('m');
  }

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

  &__list {
    list-style: none;
    margin: 0;
    padding: 0;
  }

  &__item {
    --status-color: #{color('success', 'alert')};
    align-items: center;
    border-block-end: config('border-width-base', $display) solid color('border');
    display: grid;
    gap: spacer('xxs') spacer('m');
    grid-template-columns: 7rem minmax(0, 1fr);
    margin: 0 !important;
    padding: spacer('s') spacer('m');

    &:last-child {
      border-block-end: 0;
    }

    @include breakpoint('md') {
      grid-template-columns: 7rem minmax(0, 1fr) 11rem;
    }

    &--building {
      --status-color: #{color('warning', 'alert')};
    }

    &--failed {
      --status-color: #{color('danger', 'alert')};
    }

    &--canceled {
      --status-color: #{color('muted')};
    }
  }

  &__status {
    align-items: center;
    color: color('heading');
    display: flex;
    font-size: config('font-size-sm', $typography);
    font-weight: 600;
    gap: spacer('xs');
  }

  &__dot {
    background-color: var(--status-color);
    block-size: 0.6rem;
    border-radius: radius('pill');
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--status-color) 20%, transparent);
    flex-shrink: 0;
    inline-size: 0.6rem;
  }

  &__item--building &__dot {
    @include motion-safe {
      animation: deployment-list-pulse 1.4s ease-in-out infinite;
    }
  }

  &__main {
    min-inline-size: 0;
    @include layout-stack('xxs');
  }

  &__message {
    color: color('heading');
    display: block;
    font-weight: 600;
    overflow: hidden;
    text-decoration: none;
    text-overflow: ellipsis;
    white-space: nowrap;

    &:hover {
      color: color('primary');
      text-decoration: underline;
    }
  }

  &__meta {
    align-items: center;
    color: color('muted');
    display: flex;
    flex-wrap: wrap;
    font-size: config('font-size-sm', $typography);
    gap: spacer('xxs') spacer('s');

    code {
      font-size: 0.8rem;
    }
  }

  &__env {
    border: config('border-width-base', $display) solid color('border');
    border-radius: radius('pill');
    color: color('heading');
    font-size: 0.75rem;
    font-weight: 600;
    padding: 0 spacer('xs');

    &--production {
      background-color: color-alpha('primary', 0.12);
      border-color: transparent;
      color: color('primary');
    }
  }

  &__branch {
    align-items: center;
    display: inline-flex;
    gap: spacer('xxs');

    svg {
      block-size: 0.9rem;
      inline-size: 0.9rem;
    }
  }

  &__time {
    color: color('muted');
    display: flex;
    flex-direction: column;
    font-size: config('font-size-sm', $typography);
    grid-column: 2;
    line-height: config('line-height-md', $typography);

    @include breakpoint('md') {
      grid-column: auto;
      text-align: end;
    }

    time {
      color: color('text');
    }
  }
}

@keyframes deployment-list-pulse {
  50% {
    box-shadow: 0 0 0 6px color-mix(in srgb, var(--status-color) 0%, transparent);
  }
}
<section class="deployment-list" aria-labelledby="deployment-list-title">
    <header class="deployment-list__header">
        <h2 class="deployment-list__title" id="deployment-list-title">Deployments</h2>
        <a class="btn btn--secondary btn--sm" href="#">Redeploy</a>
    </header>
    <ul class="deployment-list__list" role="list">
        <li class="deployment-list__item deployment-list__item--building">
            <span class="deployment-list__status">
                <span class="deployment-list__dot" aria-hidden="true"></span>
                Building
            </span>
            <div class="deployment-list__main">
                <a class="deployment-list__message" href="#">Add the express checkout buttons</a>
                <p class="deployment-list__meta">
                    <span class="deployment-list__env">Preview</span>
                    <span class="deployment-list__branch"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><circle cx="6" cy="6" r="2.5"/><circle cx="6" cy="18" r="2.5"/><circle cx="18" cy="8" r="2.5"/><path d="M6 8.5v7"/><path d="M18 10.5c0 4-6 3-11 5.5"/></svg><span class="sr-only">Branch: </span>feat/checkout-v2</span>
                    <code><span class="sr-only">Commit: </span>a1f9c3e</code>
                </p>
            </div>
            <p class="deployment-list__time">
                <time datetime="2026-10-04T10:02">Just now</time>
                <span>In progress · Priya Raman</span>
            </p>
        </li>
        <li class="deployment-list__item deployment-list__item--ready">
            <span class="deployment-list__status">
                <span class="deployment-list__dot" aria-hidden="true"></span>
                Ready
            </span>
            <div class="deployment-list__main">
                <a class="deployment-list__message" href="#">Merge pull request #412 from fix/cart-rounding</a>
                <p class="deployment-list__meta">
                    <span class="deployment-list__env deployment-list__env--production">Production</span>
                    <span class="deployment-list__branch"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><circle cx="6" cy="6" r="2.5"/><circle cx="6" cy="18" r="2.5"/><circle cx="18" cy="8" r="2.5"/><path d="M6 8.5v7"/><path d="M18 10.5c0 4-6 3-11 5.5"/></svg><span class="sr-only">Branch: </span>main</span>
                    <code><span class="sr-only">Commit: </span>7d04b21</code>
                </p>
            </div>
            <p class="deployment-list__time">
                <time datetime="2026-10-04T09:44">18 minutes ago</time>
                <span><span class="sr-only">Duration: </span>1m 42s · Noah Fischer</span>
            </p>
        </li>
        <li class="deployment-list__item deployment-list__item--failed">
            <span class="deployment-list__status">
                <span class="deployment-list__dot" aria-hidden="true"></span>
                Failed
            </span>
            <div class="deployment-list__main">
                <a class="deployment-list__message" href="#">Upgrade the build tooling</a>
                <p class="deployment-list__meta">
                    <span class="deployment-list__env">Preview</span>
                    <span class="deployment-list__branch"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><circle cx="6" cy="6" r="2.5"/><circle cx="6" cy="18" r="2.5"/><circle cx="18" cy="8" r="2.5"/><path d="M6 8.5v7"/><path d="M18 10.5c0 4-6 3-11 5.5"/></svg><span class="sr-only">Branch: </span>chore/upgrade-deps</span>
                    <code><span class="sr-only">Commit: </span>e3b8a90</code>
                </p>
            </div>
            <p class="deployment-list__time">
                <time datetime="2026-10-04T09:01">1 hour ago</time>
                <span><span class="sr-only">Duration: </span>38s · Lucas Moreau</span>
            </p>
        </li>
        <li class="deployment-list__item deployment-list__item--ready">
            <span class="deployment-list__status">
                <span class="deployment-list__dot" aria-hidden="true"></span>
                Ready
            </span>
            <div class="deployment-list__main">
                <a class="deployment-list__message" href="#">Round the cart total after the discounts</a>
                <p class="deployment-list__meta">
                    <span class="deployment-list__env">Preview</span>
                    <span class="deployment-list__branch"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><circle cx="6" cy="6" r="2.5"/><circle cx="6" cy="18" r="2.5"/><circle cx="18" cy="8" r="2.5"/><path d="M6 8.5v7"/><path d="M18 10.5c0 4-6 3-11 5.5"/></svg><span class="sr-only">Branch: </span>fix/cart-rounding</span>
                    <code><span class="sr-only">Commit: </span>c52e6d7</code>
                </p>
            </div>
            <p class="deployment-list__time">
                <time datetime="2026-10-04T08:10">2 hours ago</time>
                <span><span class="sr-only">Duration: </span>1m 37s · Noah Fischer</span>
            </p>
        </li>
        <li class="deployment-list__item deployment-list__item--canceled">
            <span class="deployment-list__status">
                <span class="deployment-list__dot" aria-hidden="true"></span>
                Canceled
            </span>
            <div class="deployment-list__main">
                <a class="deployment-list__message" href="#">WIP</a>
                <p class="deployment-list__meta">
                    <span class="deployment-list__env">Preview</span>
                    <span class="deployment-list__branch"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><circle cx="6" cy="6" r="2.5"/><circle cx="6" cy="18" r="2.5"/><circle cx="18" cy="8" r="2.5"/><path d="M6 8.5v7"/><path d="M18 10.5c0 4-6 3-11 5.5"/></svg><span class="sr-only">Branch: </span>fix/cart-rounding</span>
                    <code><span class="sr-only">Commit: </span>9be1f04</code>
                </p>
            </div>
            <p class="deployment-list__time">
                <time datetime="2026-10-04T08:02">2 hours ago</time>
                <span><span class="sr-only">Duration: </span>12s · Noah Fischer</span>
            </p>
        </li>
    </ul>
</section>

Deployment List

A list of deployments with their status, environment, branch, commit, author, time and build duration, like on a hosting dashboard.

Anatomy

  • .deployment-list__item: a status modifier (--ready, --building, --failed, --canceled) sets the --status-color of the __dot.
  • .deployment-list__main: the commit __message (a link to the deployment) and the __meta row with the __env pill (--production is highlighted), the __branch and the commit hash.
  • .deployment-list__time: the time, the duration and the author.

Accessibility and Usability

  • The status is a word next to the dot ("Failed"); the color and the pulsing dot of a running build only repeat it.
  • The icon and the hash have hidden labels ("Branch:", "Commit:"), so they make sense when read aloud.
  • The pulse animation only runs when the user doesn't prefer reduced motion.
  • Long commit messages are truncated with an ellipsis; the link goes to the deployment, where the full message is.

Technical Details

  • The dot's halo is a box-shadow with color-mix() of the status color, so one custom property colors both.
  • From the md breakpoint, the time moves to a third column aligned to the end; below it, it sits under the message.
  • Update a building item with your API (polling or server-sent events) and announce the result in a live region if the user is waiting for it.

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.