Banner

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

.banner {
  align-items: center;
  background-color: color-tint('primary', 90%);
  border: config('border-width-base', $display) solid color-alpha('primary', 0.25);
  border-radius: radius('md');
  color: color('heading');
  display: flex;
  gap: spacer('s');
  justify-content: space-between;
  padding: spacer('xs') spacer('xs') spacer('xs') spacer('m');

  &__message {
    align-items: center;
    display: flex;
    flex-wrap: wrap;
    gap: spacer('xs');
    line-height: config('line-height-md', $typography);
    margin: 0;
  }

  &__label {
    background-color: color('primary');
    border-radius: radius('pill');
    color: color('primary-foreground', 'btn');
    font-size: config('font-size-sm', $typography);
    font-weight: 700;
    padding: 0 spacer('xs');
  }

  a {
    color: color('heading');
    font-weight: 700;
  }
}

@include dark-mode {
  .banner {
    background-color: color-alpha('primary', 0.15);
  }
}
<div class="banner" role="region" aria-label="Announcement" data-banner="spruce-v3">
    <p class="banner__message">
        <span class="banner__label">New</span>
        Spruce CSS 3.0 brings design styles and dark mode. <a href="#">See what’s new</a>
    </p>
    <button class="btn btn--ghost-secondary btn--icon btn--sm banner__close" type="button" aria-label="Dismiss announcement" data-banner-dismiss>
        <svg class="btn__icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true" focusable="false"><path d="M18 6 6 18M6 6l12 12"/></svg>
    </button>
</div>
(() => {
  document.querySelectorAll('[data-banner]').forEach((banner) => {
    const key = `banner-dismissed-${banner.dataset.banner}`;

    try {
      if (localStorage.getItem(key)) {
        banner.remove();
        return;
      }
    } catch (error) {
      // Storage can be unavailable (private mode); the banner just stays visible.
    }

    banner.querySelector('[data-banner-dismiss]')?.addEventListener('click', () => {
      try {
        localStorage.setItem(key, 'true');
      } catch (error) {}

      banner.remove();
      document.querySelector('main, #content')?.focus({ preventScroll: true });
    });
  });
})();

Banner

On this page

A dismissible announcement bar for the top of the page.

Technical Details

  • It is a labelled region (role="region" with aria-label), so it is easy to find and skip.
  • The dismissal is remembered in localStorage by the data-banner key; change the key for a new announcement to show it again.
  • After the banner is removed, the focus moves to the main content, so keyboard users don't lose their place.
  • The background uses color-tint('primary', 90%) in light mode and color-alpha('primary', 0.15) in dark mode (through the dark-mode mixin).

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.