@use 'sass:map';
@use 'sprucecss/scss/spruce' as *;
.alert {
--alert-color: #{color('primary')};
align-items: start;
background-color: color-mix(in srgb, var(--alert-color) 8%, #{color('background')});
border: config('border-width-base', $display) solid color-mix(in srgb, var(--alert-color) 30%, #{color('background')});
border-inline-start-width: 0.25rem;
border-radius: radius('md');
color: color('text');
display: flex;
gap: spacer('s');
line-height: config('line-height-md', $typography);
padding: 0.9em 1.1em;
+ .alert {
margin-block-start: spacer('s');
}
@each $name, $value in map.get($colors, 'alert') {
&--#{$name} {
--alert-color: #{color($name, 'alert')};
}
}
&__icon {
block-size: 1.25rem;
color: var(--alert-color);
flex-shrink: 0;
inline-size: 1.25rem;
margin-block-start: 0.1em;
}
&__text,
&__title {
color: color('heading');
font-weight: 700;
margin-block: 0;
}
&__caption {
@include layout-stack('xxs');
flex-grow: 1;
a {
color: inherit;
font-weight: 600;
}
}
&__close {
@include clear-btn;
@include transition($property: 'background-color');
align-items: center;
border-radius: radius('sm');
color: color('heading');
display: flex;
flex-shrink: 0;
justify-content: center;
margin-block: -0.25em;
margin-inline-start: auto;
padding: 0.4em;
&:hover {
background-color: color-mix(in srgb, var(--alert-color) 15%, transparent);
}
&:focus-visible {
outline: 2px solid color('focus-ring');
outline-offset: 1px;
}
svg {
block-size: 1rem;
inline-size: 1rem;
}
}
}
.alert-region:not(:empty) {
margin-block: spacer('m') spacer('s');
}
<div class="alert alert--info">
<svg class="alert__icon" aria-hidden="true" fill="none" focusable="false" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4M12 8h.01"/></svg>
<p class="alert__text">A new version is available.</p>
</div>
<div class="alert alert--info" data-alert>
<svg class="alert__icon" aria-hidden="true" fill="none" focusable="false" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4M12 8h.01"/></svg>
<div class="alert__caption">
<p class="alert__title">A new version is available.</p>
<p>Spruce CSS v3 brings design styles and a built-in dark mode. <a href="#">Read the upgrade guide</a>.</p>
</div>
<button class="alert__close" type="button" data-alert-close>
<span class="sr-only">Dismiss</span>
<svg aria-hidden="true" fill="none" focusable="false" stroke-linecap="round" stroke-linejoin="round" stroke-width="3" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M18 6 6 18M6 6l12 12"/></svg>
</button>
</div>
<div class="alert alert--success">
<svg class="alert__icon" aria-hidden="true" fill="none" focusable="false" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><circle cx="12" cy="12" r="10"/><path d="m9 12 2 2 4-4"/></svg>
<p class="alert__text">Your changes have been saved.</p>
</div>
<div class="alert alert--success" data-alert>
<svg class="alert__icon" aria-hidden="true" fill="none" focusable="false" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><circle cx="12" cy="12" r="10"/><path d="m9 12 2 2 4-4"/></svg>
<div class="alert__caption">
<p class="alert__title">Your changes have been saved.</p>
<p>Everyone on the team can see the new settings now.</p>
</div>
<button class="alert__close" type="button" data-alert-close>
<span class="sr-only">Dismiss</span>
<svg aria-hidden="true" fill="none" focusable="false" stroke-linecap="round" stroke-linejoin="round" stroke-width="3" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M18 6 6 18M6 6l12 12"/></svg>
</button>
</div>
<div class="alert alert--warning">
<svg class="alert__icon" aria-hidden="true" fill="none" focusable="false" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3"/><path d="M12 9v4M12 17h.01"/></svg>
<p class="alert__text">Your trial ends in 3 days.</p>
</div>
<div class="alert alert--warning" data-alert>
<svg class="alert__icon" aria-hidden="true" fill="none" focusable="false" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3"/><path d="M12 9v4M12 17h.01"/></svg>
<div class="alert__caption">
<p class="alert__title">Your trial ends in 3 days.</p>
<p>Add a payment method to keep your projects. <a href="#">Choose a plan</a>.</p>
</div>
<button class="alert__close" type="button" data-alert-close>
<span class="sr-only">Dismiss</span>
<svg aria-hidden="true" fill="none" focusable="false" stroke-linecap="round" stroke-linejoin="round" stroke-width="3" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M18 6 6 18M6 6l12 12"/></svg>
</button>
</div>
<div class="alert alert--danger">
<svg class="alert__icon" aria-hidden="true" fill="none" focusable="false" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><circle cx="12" cy="12" r="10"/><path d="m15 9-6 6M9 9l6 6"/></svg>
<p class="alert__text">We couldn’t process your payment.</p>
</div>
<div class="alert alert--danger" data-alert>
<svg class="alert__icon" aria-hidden="true" fill="none" focusable="false" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><circle cx="12" cy="12" r="10"/><path d="m15 9-6 6M9 9l6 6"/></svg>
<div class="alert__caption">
<p class="alert__title">We couldn’t process your payment.</p>
<p>Your card was declined. Check the details or try another card.</p>
</div>
<button class="alert__close" type="button" data-alert-close>
<span class="sr-only">Dismiss</span>
<svg aria-hidden="true" fill="none" focusable="false" stroke-linecap="round" stroke-linejoin="round" stroke-width="3" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M18 6 6 18M6 6l12 12"/></svg>
</button>
</div>
<div class="alert-region" role="status" data-alert-region></div>
<button class="btn btn--primary btn--sm" type="button" data-alert-demo>Save changes</button>
(() => {
document.addEventListener('click', (event) => {
const close = event.target.closest('[data-alert-close]');
if (!close) return;
const alert = close.closest('[data-alert]');
const next = alert.nextElementSibling?.querySelector('a, button') ?? alert.parentElement.querySelector('[data-alert-demo]');
alert.remove();
next?.focus();
});
const region = document.querySelector('[data-alert-region]');
document.querySelector('[data-alert-demo]')?.addEventListener('click', () => {
region.innerHTML = '<div class="alert alert--success"><p class="alert__text">Your changes have been saved.</p></div>';
});
})();