@meui-creative/cookies
v6.0.1
Published
GDPR-compliant cookie consent management for React with centralized Payload CMS configuration
Maintainers
Readme
@meui-creative/cookies
GDPR-compliant cookie consent management for React and Next.js with 5 preset layouts, script blocking, built-in integrations, and full Google Consent Mode V2 support.
Features
- 5 Preset Layouts — From minimal bars to full sidebars
- Fully Customizable — Override colors, position, spacing, typography, animations
- Multi-language — Built-in translations (EN, CS, DE)
- Google Consent Mode V2 — Automatic setup with all required parameters
- Script Blocking — Blocks scripts/iframes until consent via
data-cookie-category - Built-in Integrations — Google Analytics, GTM, Facebook Pixel, Hotjar, Clarity
- Remote Config — Optional Payload CMS plugin for centralized management
- Headless Mode — Use the hook only, build your own UI (zero UI dependencies)
- TypeScript — Full type safety
- SSR-safe — Portal-based rendering,
"use client"directive for Next.js App Router - GDPR Compliant — Strict mode, consent versioning, audit-ready export
Installation
npm install @meui-creative/cookies framer-motion lucide-reactframer-motion and lucide-react are only needed if using the built-in component/presets. For headless usage (hook only), install just the main package.
Entry Points
| Import | What you get |
|--------|-------------|
| @meui-creative/cookies | Full library: CookieConsent component + useCookieConsent hook + API |
| @meui-creative/cookies/headless | Hook + API only (no framer-motion/lucide-react dependency) |
| @meui-creative/cookies/presets | Individual preset components: BannerDefault, BannerMinimal, BannerCard, BannerSidebar, BannerMeui |
| @meui-creative/cookies/styles | CSS stylesheet |
| @meui-creative/cookies/payload | Payload CMS plugin |
Quick Start
import { CookieConsent } from '@meui-creative/cookies'
import '@meui-creative/cookies/styles'
export default function Layout({ children }) {
return (
<>
{children}
<CookieConsent
preset="default"
language="en"
version="1.0.0"
mode="strict"
links={{
privacyPolicy: '/privacy',
cookiePolicy: '/cookies',
}}
onAccept={(categories) => console.log('Accepted:', categories)}
onDecline={() => console.log('Declined')}
/>
</>
)
}The component renders via a React Portal, checks localStorage for existing consent on mount, shows/hides the banner automatically, and handles script blocking + Google Consent Mode out of the box.
Integrations
Pass integration IDs and the library loads them automatically when the user consents to the mapped category:
<CookieConsent
integrations={{
googleAnalytics: 'G-XXXXXXXXXX', // category: analytics
googleTagManager: 'GTM-XXXXXXX', // category: analytics
facebookPixel: '123456789', // category: marketing
hotjar: '1234567', // category: analytics
clarity: 'xxxxxxxxxx', // category: analytics
}}
/>Important: Remove existing Google tags
If you have Google Analytics or GTM script tags in your <head>, remove them and use the integrations prop instead. The library ensures the correct order: consent defaults (denied) -> load tag -> config -> consent update.
// Don't do this — bypasses consent
<script async src="https://www.googletagmanager.com/gtag/js?id=G-XXX"></script>
// Do this instead
<CookieConsent integrations={{ googleAnalytics: 'G-XXX' }} />Script & Iframe Blocking
For scripts not covered by built-in integrations, mark them with type="text/plain" and data-cookie-category:
<!-- Only runs when "analytics" category is consented -->
<script type="text/plain" data-cookie-category="analytics" src="https://example.com/analytics.js"></script>
<!-- Inline scripts work too -->
<script type="text/plain" data-cookie-category="marketing">
console.log('Runs only after marketing consent');
</script>
<!-- Iframes — src is auto-stripped until consent -->
<iframe data-cookie-category="marketing" src="https://www.youtube.com/embed/VIDEO_ID"></iframe>The library also uses a MutationObserver to handle dynamically added scripts/iframes.
Categories: strictly-necessary (always on), functional, analytics, marketing
Google Consent Mode V2
The library automatically manages Google Consent Mode V2. No extra configuration needed.
On page load: all signals set to denied. On consent: signals updated to granted for consented categories.
| Category | Consent Mode signals |
|----------|---------------------|
| strictly-necessary | functionality_storage |
| functional | functionality_storage, personalization_storage |
| analytics | analytics_storage |
| marketing | ad_storage, ad_user_data, ad_personalization |
| (always) | security_storage |
Optional configuration
<CookieConsent
consentModeOptions={{
region: ['EU', 'US-CA'], // Geographic regions
urlPassthrough: true, // Pass ad click info through URLs
adsDataRedaction: true, // Redact ads data when consent denied
}}
/>Verify in GTM Preview
- Open GTM Preview Mode
- Click the "Consent" tab
- Before accept: all signals show Denied
- After accept: consented signals show Granted
// Check in browser console
window.dataLayer.filter(e => e[0] === 'consent')Design Presets
Choose from 5 professionally designed layouts, each with unique UX:
default - Classic Card
Color: Blue (#3b82f6) | Position: Bottom-left
Clean, professional design with large cookie icon. Perfect for corporate websites.
<CookieConsent />meui - Compact with Inline Settings
Color: Green (#4A6953) | Position: Bottom-left
Original Meui design with expandable settings directly in banner. Saves modal interactions.
<CookieConsent preset="meui" />minimal - Bottom Bar
Color: Black (#000) | Position: Full-width bottom
Horizontal bar spanning full width. Non-intrusive, great for blogs and content sites.
<CookieConsent preset="minimal" />card - Accent Header
Color: Violet (#8b5cf6) | Position: Bottom-right
Modern card with colored header stripe and shield icon. Bold and eye-catching.
<CookieConsent preset="card" />sidebar - Full-Height Panel
Color: Emerald (#10b981) | Position: Right sidebar
Full-height sidebar with detailed information and trust indicators. Best for complex consent needs.
<CookieConsent preset="sidebar" />Customization
Every preset can be customized. Override color, position, language, or any style property:
Change Color
<CookieConsent
preset="default"
accentColor="#ec4899" // Pink
/>Change Position
<CookieConsent
preset="card"
style={{
position: 'top-center', // Move to top
}}
/>Change Language
<CookieConsent
preset="meui"
language="cs" // Czech
/>Multiple Overrides
<CookieConsent
preset="minimal"
accentColor="#f97316"
language="de"
style={{
position: 'top-center',
animation: {
direction: 'down',
duration: 0.5,
},
}}
/>Full Style Override
<CookieConsent
preset="default"
accentColor="#ff6600"
borderRadius="sharp"
style={{
position: 'top-right',
maxWidth: 'lg', // 'sm' | 'md' | 'lg' | 'xl' or custom string
spacing: 'comfortable', // 'compact' | 'normal' | 'comfortable'
background: '#1a1a1a',
shadow: '2xl', // 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'
border: { width: '2', color: '#333' },
fontSize: { heading: 'lg', body: 'sm' },
button: { shape: 'pill', size: 'lg' },
modal: { shadow: 'xl' },
animation: { direction: 'right', duration: 0.4, enabled: true },
}}
/>Position Options
All presets support 6 positions:
bottom-left|bottom-center|bottom-righttop-left|top-center|top-right
All Configuration Options
<CookieConsent
// Design
preset="default" // 'default' | 'meui' | 'minimal' | 'card' | 'sidebar'
accentColor="#3b82f6" // Any CSS color
borderRadius="rounded" // 'rounded' | 'sharp'
style={{ ... }} // See Full Style Override above
// Content & Language
language="en" // 'en' | 'cs' | 'de'
descriptionMode="short" // 'short' | 'long'
// Behavior
mode="strict" // 'strict' (closing = decline) | 'soft' (closing = nothing)
showSettingsButton={true} // Show settings gear button in banner
closeButton={true} // Show X close button
showRejectLink={true} // Show reject all link
version="1.0.0" // Bump to force re-consent
ttl={365} // Consent expiry in days
domain=".example.com" // Cookie domain for subdomain sharing
// Legal Links
links={{
privacyPolicy: '/privacy',
cookiePolicy: '/cookies',
}}
// Custom Categories (replaces defaults entirely)
customCategories={[
{ id: 'essential', label: 'Essential', description: '...', required: true, enabled: true },
{ id: 'analytics', label: 'Analytics', description: '...', required: false, enabled: false },
]}
// Integrations
integrations={{
googleAnalytics: 'G-XXXXXXXXXX',
googleTagManager: 'GTM-XXXXXXX',
facebookPixel: '123456789',
hotjar: '1234567',
clarity: 'xxxxxxxxxx',
}}
// Google Consent Mode V2
consentModeOptions={{
region: ['EU'],
urlPassthrough: true,
adsDataRedaction: true,
}}
// Remote Config (Payload CMS)
apiUrl="https://your-cms.com/api/cookie-config"
// Callbacks
onAccept={(choices) => console.log('Accepted:', choices)}
onDecline={() => console.log('Declined')}
onChange={(choices) => console.log('Changed:', choices)}
onReady={() => console.log('Consent loaded from storage')}
onBlock={(src) => console.log('Script unblocked:', src)}
onVersionChange={(prev) => console.log('Version changed from:', prev)}
// Debug
debug={false}
/>Headless Mode
Import from @meui-creative/cookies/headless to use the hook without any UI dependencies:
import { useCookieConsent } from '@meui-creative/cookies/headless'
function CustomCookieBanner() {
const {
consent, // { 'strictly-necessary': true, analytics: false, ... }
hasConsent, // Has the user made any choice?
isReady, // Initialization complete?
categories, // CategoryDefinition[]
acceptAll,
declineAll,
setConsent, // Granular: setConsent({ analytics: true, marketing: false })
revokeConsent,
exportConsent,
showSettings, // Dispatches event to open settings modal
} = useCookieConsent({
version: '1.0.0',
language: 'en',
integrations: { googleAnalytics: 'G-XXXXXXXXXX' },
})
if (!isReady || hasConsent) return null
return (
<div className="my-custom-banner">
<h2>We use cookies</h2>
<button onClick={acceptAll}>Accept All</button>
<button onClick={declineAll}>Decline</button>
</div>
)
}The hook handles all core logic — storage, script blocking, integrations, Google Consent Mode — you just provide the UI.
Programmatic API
import { showCookieSettings, revokeConsent, exportConsent } from '@meui-creative/cookies'
// Open settings modal from anywhere (e.g., footer link)
showCookieSettings()
// Revoke all consent
revokeConsent()
// Export consent record for GDPR data subject requests
const record = exportConsent()
// { version, timestamp, choices, userAgent, language, consentMethod, sourceUrl }"Manage cookies" footer link
import { showCookieSettings } from '@meui-creative/cookies'
function Footer() {
return <button onClick={showCookieSettings}>Cookie Settings</button>
}Version Management
Set version on the component. When you bump it, all users are prompted to re-consent:
<CookieConsent version="2.0.0" />Bump the version when you:
- Add or remove cookie categories
- Add a new integration that requires consent
- Change what data a category covers
- Need to comply with updated regulations
Consent also expires automatically after ttl days (default: 365).
Events
The library dispatches DOM events on window for integration with non-React code:
window.addEventListener('meui:consent:given', (e) => {
console.log('Consent given:', e.detail.consent)
})
window.addEventListener('meui:consent:revoked', () => {
console.log('Consent revoked')
})
window.addEventListener('meui:consent:version-changed', (e) => {
console.log('Re-consent needed, previous version:', e.detail.previousVersion)
})Events: meui:consent:given, meui:consent:revoked, meui:consent:changed, meui:consent:version-changed, meui:settings:opened
Remote Configuration (Payload CMS)
Manage consent texts and categories through a Payload CMS admin panel instead of hardcoding them.
1. Install plugin
// payload.config.ts
import { cookieConsentPlugin } from '@meui-creative/cookies/payload'
export default buildConfig({
plugins: [
cookieConsentPlugin({
enabled: true,
defaultVersion: '1.0.0',
}),
],
})This adds a cookie-config collection (version, texts in en/cs/de, categories, legal links) and a public GET /api/cookie-config endpoint.
2. Use in frontend
<CookieConsent
preset="default"
apiUrl="https://your-cms.com/api/cookie-config"
/>The component fetches the remote config (cached for 24h with background refresh), using it for texts and categories. Styling remains controlled locally via props.
Storage
Consent is stored in two places:
- localStorage (
meui_cookie_consent) — Full record: version, timestamp, choices, userAgent, language, consentMethod, sourceUrl - Cookie (
meui_cookie_consent) — Simplified comma-separated list of consented category IDs (for server-side reading)
Use exportConsent() to retrieve the full record for GDPR Article 7(1) compliance.
License
MIT
