wb-card, layout primitives, buttons, form controls, and one shipped wb-modal.Use this pattern when a public site, CMS surface, or product landing page needs one consistent consent flow that can be reopened later from a footer or settings link. Keep the markup explicit, keep the copy legal-reviewable, and keep script loading decisions in the host project.
Close does not save consent. Accept, Reject, or Save preferences stores the user choice.
Live demo
This page ships one live consent demo: the bottom banner plus one shared preference modal. Use the footer-style button below after you save consent.
When to use
- Public websites that need a reusable consent banner
- Products that need one shared preference center modal
- Projects that must reopen cookie settings from the footer
- Teams that want consent state stored consistently in localStorage
Static previews
Static previews are inert; only the Live demo section contains active consent hooks. Copy the markup examples below when you need the real hooks.
Bottom banner preview
Recommended default for most public pages.
Floating card preview
Compact alternative for calmer marketing pages.
1. Bottom banner + preference modal
This is the recommended default. The banner owns the first decision, while one shared modal handles category-level preferences.
<div class="wb-cookie-consent wb-cookie-consent-banner"
data-wb-cookie-consent
hidden>
<section class="wb-card wb-cookie-consent-card" aria-label="Cookie consent">
<div class="wb-card-header wb-cluster wb-cluster-between wb-cluster-2 wb-items-start">
<div class="wb-stack-1">
<strong>We use cookies</strong>
</div>
<button class="wb-btn wb-btn-secondary wb-btn-icon wb-btn-sm" type="button" data-wb-cookie-consent-close aria-label="Close cookie settings"><i class="wb-icon wb-icon-x" aria-hidden="true"></i></button>
</div>
<div class="wb-card-body">
<div class="wb-cluster wb-cluster-between wb-cluster-3 wb-items-center">
<p class="wb-text-sm wb-text-muted wb-m-0">
Necessary cookies keep the site running. Optional cookies help us remember preferences and understand usage.
</p>
<div class="wb-cluster wb-cluster-2">
<button class="wb-btn wb-btn-secondary wb-btn-sm" type="button" data-wb-cookie-consent-reject>Reject</button>
<button class="wb-btn wb-btn-secondary wb-btn-sm" type="button" data-wb-cookie-consent-open data-wb-target="#siteCookiePreferences">Customize</button>
<button class="wb-btn wb-btn-primary wb-btn-sm" type="button" data-wb-cookie-consent-accept>Accept all</button>
</div>
</div>
</div>
</section>
</div>
<div class="wb-modal wb-cookie-consent-modal" id="siteCookiePreferences" data-wb-cookie-consent role="dialog" aria-modal="true" aria-labelledby="siteCookiePreferencesTitle">
<div class="wb-modal-dialog">
<div class="wb-modal-header">
<h2 class="wb-modal-title" id="siteCookiePreferencesTitle">Cookie preferences</h2>
<button class="wb-btn wb-btn-secondary wb-btn-icon wb-btn-sm" type="button" data-wb-cookie-consent-close aria-label="Close cookie settings"><i class="wb-icon wb-icon-x" aria-hidden="true"></i></button>
</div>
<div class="wb-modal-body">
<div class="wb-stack-1">
<p class="wb-text-sm wb-text-muted">
Necessary cookies are always on. Optional categories can be changed at any time.
</p>
</div>
<div class="wb-stack-3">
<div class="wb-card wb-card-muted">
<div class="wb-card-body wb-cluster wb-cluster-between wb-cluster-3 wb-items-center">
<div class="wb-stack-1">
<strong>Necessary</strong>
<p class="wb-text-sm wb-text-muted wb-m-0">Required for core site behavior.</p>
</div>
<label class="wb-switch">
<input type="checkbox" data-wb-cookie-category="necessary" data-wb-cookie-required="true" checked disabled>
<span class="wb-switch-track"></span>
<span>Always on</span>
</label>
</div>
</div>
<div class="wb-card wb-card-muted">
<div class="wb-card-body wb-cluster wb-cluster-between wb-cluster-3 wb-items-center">
<div class="wb-stack-1">
<strong>Preferences</strong>
<p class="wb-text-sm wb-text-muted wb-m-0">Remember language and interface choices.</p>
</div>
<label class="wb-switch">
<input type="checkbox" data-wb-cookie-category="preferences">
<span class="wb-switch-track"></span>
<span>Allow</span>
</label>
</div>
</div>
<div class="wb-card wb-card-muted">
<div class="wb-card-body wb-cluster wb-cluster-between wb-cluster-3 wb-items-center">
<div class="wb-stack-1">
<strong>Analytics</strong>
<p class="wb-text-sm wb-text-muted wb-m-0">Measure usage and content performance.</p>
</div>
<label class="wb-switch">
<input type="checkbox" data-wb-cookie-category="analytics">
<span class="wb-switch-track"></span>
<span>Allow</span>
</label>
</div>
</div>
<div class="wb-card wb-card-muted">
<div class="wb-card-body wb-cluster wb-cluster-between wb-cluster-3 wb-items-center">
<div class="wb-stack-1">
<strong>Marketing</strong>
<p class="wb-text-sm wb-text-muted wb-m-0">Support campaign attribution and ad measurement.</p>
</div>
<label class="wb-switch">
<input type="checkbox" data-wb-cookie-category="marketing">
<span class="wb-switch-track"></span>
<span>Allow</span>
</label>
</div>
</div>
</div>
</div>
<div class="wb-modal-footer">
<button class="wb-btn wb-btn-secondary" type="button" data-wb-cookie-consent-reject>Reject all</button>
<div class="wb-cluster wb-cluster-2">
<button class="wb-btn wb-btn-secondary" type="button" data-wb-cookie-consent-save>Save preferences</button>
<button class="wb-btn wb-btn-primary" type="button" data-wb-cookie-consent-accept>Accept all</button>
</div>
</div>
</div>
</div>
2. Floating card + preference modal
Use the same modal and behavior hooks, but swap the entry surface to a smaller floating card for promotional or editorial pages.
<div class="wb-cookie-consent wb-cookie-consent-floating"
data-wb-cookie-consent
hidden>
<section class="wb-card wb-cookie-consent-card" aria-label="Cookie settings">
<div class="wb-card-header wb-cluster wb-cluster-between wb-cluster-2 wb-items-start">
<div class="wb-stack-1">
<strong>Cookie settings</strong>
<p class="wb-text-sm wb-text-muted wb-m-0">
Necessary cookies keep the site working. Optional cookies help personalize and measure the experience.
</p>
</div>
<button class="wb-btn wb-btn-secondary wb-btn-icon wb-btn-sm" type="button" data-wb-cookie-consent-close aria-label="Close cookie settings"><i class="wb-icon wb-icon-x" aria-hidden="true"></i></button>
</div>
<div class="wb-card-body wb-stack-3">
<div class="wb-cluster wb-cluster-2">
<button class="wb-btn wb-btn-secondary wb-btn-sm" type="button" data-wb-cookie-consent-reject>Reject</button>
<button class="wb-btn wb-btn-secondary wb-btn-sm" type="button" data-wb-cookie-consent-open data-wb-target="#marketingCookiePreferences">Customize</button>
<button class="wb-btn wb-btn-primary wb-btn-sm" type="button" data-wb-cookie-consent-accept>Accept all</button>
</div>
</div>
</section>
</div>
<div class="wb-modal wb-cookie-consent-modal" id="marketingCookiePreferences" data-wb-cookie-consent role="dialog" aria-modal="true" aria-labelledby="marketingCookiePreferencesTitle" hidden>
<div class="wb-modal-dialog">
<div class="wb-modal-header">
<h2 class="wb-modal-title" id="marketingCookiePreferencesTitle">Cookie preferences</h2>
<button class="wb-btn wb-btn-secondary wb-btn-icon wb-btn-sm" type="button" data-wb-cookie-consent-close aria-label="Close cookie settings"><i class="wb-icon wb-icon-x" aria-hidden="true"></i></button>
</div>
<div class="wb-modal-body">...same category rows...</div>
</div>
</div>
Close dismisses the card or modal for the current view only when no consent has been saved yet.
Storage keys and emitted event
Stored keys
wb-cookie-consentStores accepted, rejected, or custom.
wb-cookie-consent-preferencesStores a JSON object with necessary, preferences, analytics, and marketing.
Change event
Whenever consent changes, WebBlocks emits wb:cookie-consent:change on document.documentElement.
document.documentElement.addEventListener('wb:cookie-consent:change', function (event) {
var state = event.detail;
if (state.preferences.analytics) {
// Load analytics here.
}
});
Public API
WBCookieConsent.open()
WBCookieConsent.close()
WBCookieConsent.get()
WBCookieConsent.set({
necessary: true,
preferences: true,
analytics: false,
marketing: false
})
WBCookieConsent.clear()
WBCookieConsent.hasConsent()
Integration guidance
- Necessary cookies cannot be disabled
- Site owners must adapt the legal copy for their own jurisdiction and policy text
- Use layout primitives such as
wb-stack,wb-cluster,wb-grid, andwb-splitinside the pattern - Use the shipped modal primitive for the preference center instead of creating a second overlay family
WBCookieConsent.clear() from the console to remove the stored keys and force the first-entry consent UI to appear again.