Video

Watch

See Spruce in two minutes

A quick tour of the styles, the components and the blocks.

A laptop with code on the screen.
  • Eight design styles
  • 100+ components and blocks
  • 9 KB of core CSS
@use 'sprucecss/scss/spruce' as *;

.video-block {
  padding-block: spacer-clamp('xl', 'xxl');

  &__inner {
    display: flex;
    flex-direction: column;
    gap: spacer('l');
  }

  &__player {
    aspect-ratio: 16 / 9;
    background-color: color('heading');
    border-radius: radius('lg');
    box-shadow: shadow('xl');
    inline-size: 100%;
    margin-inline: auto;
    max-inline-size: 64rem;
    overflow: hidden;
    position: relative;

    iframe {
      block-size: 100%;
      border: 0;
      inline-size: 100%;
    }
  }

  &__poster {
    block-size: 100%;
    inline-size: 100%;
    object-fit: cover;
    opacity: 0.8;
  }

  &__play {
    @include clear-btn;
    align-items: center;
    color: hsl(0deg 0% 100%);
    display: flex;
    flex-direction: column;
    font-weight: 700;
    gap: spacer('s');
    inset: 0;
    justify-content: center;
    position: absolute;
    text-shadow: 0 1px 4px hsl(0deg 0% 0% / 50%);

    &:focus-visible .video-block__play-icon {
      outline: 3px solid hsl(0deg 0% 100%);
      outline-offset: 4px;
    }

    &:hover .video-block__play-icon {
      scale: 1.08;
    }
  }

  &__play-icon {
    align-items: center;
    background-color: color('primary-background', 'btn');
    block-size: 5rem;
    border-radius: 50%;
    box-shadow: 0 0 0 0.6rem color-alpha('primary-background', 0.3, 'btn');
    color: color('primary-foreground', 'btn');
    display: flex;
    inline-size: 5rem;
    justify-content: center;
    @include transition($property: 'scale');

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

  &__duration {
    font-weight: 400;
  }

  &__points {
    @include clear-list;
    @include layout-cluster('m:l', center);

    li {
      align-items: center;
      color: color('heading');
      display: flex;
      font-weight: 600;
      gap: spacer('xs');
      margin: 0 !important;
    }

    svg {
      block-size: 1.25rem;
      color: color('primary');
      inline-size: 1.25rem;
    }

    // The items sit side by side: clear the stack margins of the base list style.
    > li {
      margin-block: 0;
      padding-block: 0;
    }
  }
}
<section class="video-block" aria-labelledby="video-title" data-video>
    <div class="container">
        <div class="video-block__inner">
            <header class="block-heading">
                <p class="block-heading__eyebrow">Watch</p>
                <h2 class="block-heading__title" id="video-title">See Spruce in two minutes</h2>
                <p class="block-heading__text">A quick tour of the styles, the components and the blocks.</p>
            </header>
            <div class="video-block__player">
                <img class="video-block__poster" src="https://images.unsplash.com/photo-1498050108023-c5249f4df085?auto=format&amp;fit=crop&amp;w=1600&amp;q=70" alt="A laptop with code on the screen." width="1600" height="900" loading="lazy">
                <button class="video-block__play" type="button" data-video-play data-embed="https://www.youtube-nocookie.com/embed/-6Xl9tBWt54?autoplay=1">
                    <span class="video-block__play-icon" aria-hidden="true"><svg viewBox="0 0 24 24" fill="currentColor" focusable="false"><path d="M8 5.1v13.8c0 .8.9 1.3 1.6.8l10.6-6.9c.6-.4.6-1.3 0-1.7L9.6 4.3C8.9 3.8 8 4.3 8 5.1z"/></svg></span>
                    <span>Play video <span class="video-block__duration">(2:14)</span></span>
                </button>
            </div>
            <ul class="video-block__points" role="list">
                <li><svg class="block-icon" 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="13.5" cy="6.5" r="1"/><circle cx="17.5" cy="10.5" r="1"/><circle cx="8.5" cy="7.5" r="1"/><circle cx="6.5" cy="12.5" r="1"/><path d="M12 2a10 10 0 0 0 0 20 1.7 1.7 0 0 0 1.2-2.9 1.6 1.6 0 0 1 1.2-2.8h2A5.6 5.6 0 0 0 22 10.8C22 6 17.5 2 12 2z"/>
</svg>
 Eight design styles</li>
                <li><svg class="block-icon" 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">
<path d="m12 2 10 5-10 5L2 7l10-5z"/><path d="m2 17 10 5 10-5"/><path d="m2 12 10 5 10-5"/>
</svg>
 100+ components and blocks</li>
                <li><svg class="block-icon" 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">
<path d="M13 2 3 14h9l-1 8 10-12h-9l1-8z"/>
</svg>
 9 KB of core CSS</li>
            </ul>
        </div>
    </div>
</section>
(() => {
  document.querySelectorAll('[data-video-play]').forEach((button) => {
    button.addEventListener('click', () => {
      const player = button.parentElement;
      const iframe = document.createElement('iframe');

      iframe.src = button.dataset.embed;
      iframe.title = button.textContent.trim();
      iframe.allow = 'autoplay; encrypted-media; picture-in-picture; fullscreen';
      iframe.allowFullscreen = true;

      player.replaceChildren(iframe);
      iframe.focus();
    });
  });
})();

Video

On this page

A featured video with a poster image and highlights below.

Technical Details

  • The embed loads only after the click (a "facade"), so the page doesn't load a heavy third-party player upfront. The player replaces the poster in place and receives the focus.
  • The play button has a visible label with the duration; its focus ring is drawn around the icon.
  • The default embed uses youtube-nocookie.com; any embeddable URL works through the embed value.
  • Override the content with videoBlock.

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.