UI Components Easy
Announcement Banner
Full-width dismissable announcement banner with icon, message, optional CTA link, and localStorage persistence. No libraries.
Open in Lab
MCP
vanilla-js css
Targets: JS HTML
Code
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
background: #f9fafb;
color: #111;
}
/* Announcement banner */
.announcement-banner {
background: #6366f1;
color: #fff;
position: sticky;
top: 0;
z-index: 50;
transition: max-height 0.3s ease, opacity 0.3s ease;
overflow: hidden;
max-height: 80px;
}
.announcement-banner.dismissed {
max-height: 0;
opacity: 0;
pointer-events: none;
}
.announcement-banner--warning {
background: #d97706;
}
.announcement-banner--error {
background: #dc2626;
}
.announcement-banner--dark {
background: #111827;
}
.announcement-banner--static {
position: static;
border-radius: 10px;
margin-bottom: 12px;
}
.banner-inner {
display: flex;
align-items: center;
gap: 10px;
padding: 10px 20px;
max-width: 1080px;
margin: 0 auto;
}
.banner-icon {
font-size: 16px;
flex-shrink: 0;
}
.banner-text {
flex: 1;
font-size: 14px;
line-height: 1.5;
}
.banner-link {
color: rgba(255, 255, 255, 0.9);
text-decoration: none;
font-weight: 600;
margin-left: 4px;
border-bottom: 1px solid rgba(255, 255, 255, 0.5);
transition: border-color 0.15s;
}
.banner-link:hover {
border-color: #fff;
}
.banner-close {
background: none;
border: none;
color: rgba(255, 255, 255, 0.7);
cursor: pointer;
padding: 4px;
border-radius: 6px;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
transition: color 0.15s, background 0.15s;
}
.banner-close:hover {
color: #fff;
background: rgba(255, 255, 255, 0.15);
}
/* Page shell */
.page-shell {
min-height: 100vh;
}
.site-header {
display: flex;
align-items: center;
gap: 32px;
padding: 16px 40px;
background: #fff;
border-bottom: 1px solid #e5e7eb;
position: sticky;
top: 0;
z-index: 40;
}
.logo {
font-size: 18px;
font-weight: 800;
}
nav {
display: flex;
gap: 20px;
flex: 1;
}
nav a {
font-size: 14px;
color: #6b7280;
text-decoration: none;
}
.nav-cta {
background: #6366f1;
color: #fff;
border: none;
padding: 8px 18px;
border-radius: 8px;
font-size: 14px;
font-weight: 600;
cursor: pointer;
}
.main-content {
max-width: 640px;
margin: 48px auto;
padding: 0 24px;
}
.demo-card {
background: #fff;
border: 1px solid #e5e7eb;
border-radius: 16px;
padding: 32px;
margin-bottom: 32px;
}
.demo-card h1 {
font-size: 22px;
font-weight: 800;
margin-bottom: 10px;
}
.demo-card p {
font-size: 14px;
color: #6b7280;
line-height: 1.7;
margin-bottom: 20px;
}
.demo-actions {
display: flex;
gap: 10px;
}
.btn-primary {
padding: 10px 20px;
background: #f3f4f6;
color: #374151;
border: none;
border-radius: 8px;
font-size: 14px;
font-weight: 600;
cursor: pointer;
transition: background 0.15s;
}
.btn-primary:hover {
background: #e5e7eb;
}
.variants-title {
font-size: 12px;
font-weight: 700;
color: #9ca3af;
text-transform: uppercase;
letter-spacing: 0.06em;
margin-bottom: 12px;
}const STORAGE_KEY = "acme_banner_dismissed";
const banner = document.getElementById("banner");
const bannerClose = document.getElementById("bannerClose");
const resetBtn = document.getElementById("resetBtn");
// Restore dismissed state on load
if (localStorage.getItem(STORAGE_KEY) === "true") {
banner.classList.add("dismissed");
}
bannerClose.addEventListener("click", () => {
banner.classList.add("dismissed");
localStorage.setItem(STORAGE_KEY, "true");
});
resetBtn.addEventListener("click", () => {
banner.classList.remove("dismissed");
localStorage.removeItem(STORAGE_KEY);
});<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Announcement Banner</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<!-- Announcement banner -->
<div class="announcement-banner" id="banner" role="banner">
<div class="banner-inner">
<span class="banner-icon">🎉</span>
<p class="banner-text">
<strong>New feature:</strong> Real-time collaboration is now available on all plans.
<a href="#" class="banner-link">Learn more →</a>
</p>
<button class="banner-close" id="bannerClose" aria-label="Dismiss banner">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round">
<line x1="18" y1="6" x2="6" y2="18"/>
<line x1="6" y1="6" x2="18" y2="18"/>
</svg>
</button>
</div>
</div>
<!-- Page -->
<div class="page-shell" id="pageShell">
<header class="site-header">
<span class="logo">Acme</span>
<nav>
<a href="#">Features</a>
<a href="#">Pricing</a>
<a href="#">Docs</a>
</nav>
<button class="nav-cta">Get started</button>
</header>
<main class="main-content">
<div class="demo-card">
<h1>Announcement Banner Demo</h1>
<p>The banner sits above the header and pushes page content down. Dismiss it to see the page shift up smoothly. Dismissed state is saved to localStorage.</p>
<div class="demo-actions">
<button class="btn-primary" id="resetBtn">Reset banner</button>
</div>
</div>
<!-- Variant banners -->
<div class="variants">
<h2 class="variants-title">Color Variants</h2>
<div class="announcement-banner announcement-banner--warning announcement-banner--static">
<div class="banner-inner">
<span class="banner-icon">⚠️</span>
<p class="banner-text"><strong>Scheduled maintenance</strong> on March 10 from 2–4 AM UTC. Service may be briefly unavailable.</p>
</div>
</div>
<div class="announcement-banner announcement-banner--error announcement-banner--static">
<div class="banner-inner">
<span class="banner-icon">🚨</span>
<p class="banner-text"><strong>Incident in progress:</strong> API latency elevated. Our team is investigating. <a href="#" class="banner-link">Status page</a></p>
</div>
</div>
<div class="announcement-banner announcement-banner--dark announcement-banner--static">
<div class="banner-inner">
<span class="banner-icon">⚡</span>
<p class="banner-text">Black Friday — <strong>40% off</strong> all plans this week only. <a href="#" class="banner-link">Claim deal →</a></p>
</div>
</div>
</div>
</main>
</div>
<script src="script.js"></script>
</body>
</html>Full-width announcement banner that sits above the page header. Includes icon, message text, optional CTA link, and an X dismiss button. Dismissed state persists to localStorage so it stays closed on reload.