Guide · June 17, 2026
Is a DIY HTML/CSS/JS cookie banner PDPL-compliant?
How to build a DIY HTML/CSS/JS cookie banner: structure, store choices, block scripts, and PDPL notes for Vietnamese SMEs.
Quick answer
Does a DIY HTML CSS cookie banner meet PDPL requirements?
Yes—if your banner isn’t just for show but actually gives users a choice before enabling non-essential cookies. Under the Personal Data Protection Law (Law 91/2025/QH15), businesses must have an appropriate legal basis for processing, be transparent about purposes, and respect the right to withdraw/not consent as provided by law.
For SME websites in Vietnam, a cookie banner typically comes with three practical obligations: clearly disclose cookie categories, store the choice status, and run analytics/remarketing scripts only after consent. If done wrong, the risk isn’t just poor UX but potential compliance obligations and internal checks when there are complaints or inspections.
What should the HTML cookie banner structure include?
A minimal banner should have four parts: short explanatory text, an “Accept” button, a “Reject” button, and a “Customize” button. If your website uses analytics, pixels, heatmaps, or third-party chat widgets, clearly separate essential cookies from non-essential cookies.
Prioritize short, plain language that doesn’t mislead users. For example: “We use essential cookies to operate the website and analytics cookies to measure traffic. You can accept, reject, or customize.”
| Component | Should have | Purpose | |
|---|---|---|---|
| Short notice | Yes | State what cookies the website uses | |
| Accept button | Yes | Record consent | |
| Reject button | Yes | Allow opting out of non-essential cookies | |
| Customize | Should have | Choose each cookie category | |
| Policy link | Yes | Detailed explanation for transparency |
How to build a DIY HTML CSS JS cookie banner?
The safest approach is to build the banner with HTML/CSS, then use JS to store the choice in localStorage or a first-party cookie, and block all non-essential scripts until consent is given. This is a common pattern, easy for SMEs to implement, and good enough if you control all tags on the site.
Create the HTML frame:
place the banner at the end of the body, with content, accept/reject/customize buttons, and a policy link.
Create clear CSS:
make the banner fixed at the bottom, with good contrast, and not covering critical content.
Store the choice:
when a user clicks a button, store the status in localStorage or a technical cookie to remember it next time.
Block scripts before consent:
don’t load Google Analytics, Meta Pixel, TikTok Pixel, Hotjar… until consent is given for the corresponding category.
Activate after consent:
if the user accepts, load scripts dynamically via JavaScript and mark the state as allowed.
Allow changing mind:
add a “Manage cookies” button in the footer so users can reopen the banner and change their choices.
Plain HTML/CSS/JS cookie banner example code
Below is a minimal template you can use right away. You should adjust the content, cookie categories, and third-party scripts according to your actual setup.
<!-- HTML -->
<div id="cookie-banner" class="cookie-banner" hidden>
<div class="cookie-banner__content">
<p><strong>We use cookies</strong> to operate the website, measure traffic, and improve your experience. You can accept, reject, or customize to your needs.</p>
<a href="/chinh-sach-cookie" class="cookie-banner__link">View cookie policy</a>
</div>
<div class="cookie-banner__actions">
<button id="cookie-reject" class="btn btn--ghost">Reject</button>
<button id="cookie-manage" class="btn btn--secondary">Customize</button>
<button id="cookie-accept" class="btn btn--primary">Accept</button>
</div>
</div>
<!-- Placeholder for analytics/pixel -->
<script>
window.loadAnalytics = function () {
if (window.__analyticsLoaded) return;
window.__analyticsLoaded = true;
const s = document.createElement('script');
s.src = 'https://www.googletagmanager.com/gtag/js?id=G-XXXXXXX';
s.async = true;
document.head.appendChild(s);
};
</script>
/* CSS */
.cookie-banner {
position: fixed;
left: 16px;
right: 16px;
bottom: 16px;
z-index: 9999;
display: flex;
gap: 16px;
justify-content: space-between;
align-items: center;
padding: 16px;
background: #111827;
color: #fff;
border-radius: 12px;
box-shadow: 0 10px 30px rgba(0,0,0,.2);
}
.cookie-banner__content { max-width: 70%; }
.cookie-banner__link { color: #93c5fd; }
.cookie-banner__actions { display: flex; gap: 8px; flex-wrap: wrap; }
.btn { padding: 10px 14px; border: 0; border-radius: 8px; cursor: pointer; }
.btn--ghost { background: transparent; color: #fff; border: 1px solid #6b7280; }
.btn--secondary { background: #374151; color: #fff; }
.btn--primary { background: #2563eb; color: #fff; }
@media (max-width: 640px) {
.cookie-banner { flex-direction: column; }
.cookie-banner__content { max-width: 100%; }
.cookie-banner__actions { width: 100%; }
}
// JS
const STORAGE_KEY = 'cookie_consent_v1';
const banner = document.getElementById('cookie-banner');
const acceptBtn = document.getElementById('cookie-accept');
const rejectBtn = document.getElementById('cookie-reject');
function saveConsent(value) {
localStorage.setItem(STORAGE_KEY, JSON.stringify({ value, ts: new Date().toISOString() }));
}
function getConsent() {
const raw = localStorage.getItem(STORAGE_KEY);
return raw ? JSON.parse(raw) : null;
}
function showBanner() { banner.hidden = false; }
function hideBanner() { banner.hidden = true; }
function applyConsent(value) {
if (value === 'accepted') {
window.loadAnalytics?.();
}
}
const consent = getConsent();
if (!consent) showBanner();
else applyConsent(consent.value);
acceptBtn.addEventListener('click', () => {
saveConsent('accepted');
hideBanner();
applyConsent('accepted');
});
rejectBtn.addEventListener('click', () => {
saveConsent('rejected');
hideBanner();
});
What should you watch out for when blocking scripts based on consent?
The important point isn’t just hiding the banner, but preventing scripts from loading until a suitable choice is made. If you install Google Analytics, Meta Pixel, TikTok Pixel, or chat widgets, treat them as scripts that should only run after consent if they are not “essential”.
A practical approach: leave tags in an “inactive” state, then call loadAnalytics() after the user accepts. If you use Google Tag Manager, configure triggers based on consent state instead of firing all tags up front. This is a step many Vietnamese websites overlook.
How should you store user choices properly?
At a minimum you should store: the accept/reject status, timestamp, the version of the cookie policy, and the cookie categories the user selected. This data is useful to prove your website recorded choices according to internal procedures.
If it’s a sales system, SaaS, or a logged-in app, bind consent to a hashed user ID or internal code, but still minimize data and only store what’s necessary. With localStorage, make sure users can change their choice at any time.
FAQ about DIY HTML CSS cookie banners
- It can be sufficient for a simple website if the banner is transparent, has clear choice buttons, and only runs non-essential scripts after consent. But you should still review your cookie policy, tag manager, and the evidence capture flow.
- It should have one. If there’s only an “Accept” button without a clear reject option, you increase compliance risk and create a poor experience.
- Yes, if the goal is to store the display choice and enable scripts in the browser. But if you need administrative evidence or cross-device sync, also store it on the server according to your internal process.
- When a personal data breach is detected, businesses must notify within 72 hours as required. If an incident related to cookies/analytics leads to data leakage, handle it under your incident process and consult legal counsel.
If you want to move faster, consent.vn can help standardize your banner, retain evidence of consent, and set up DSAR flows to avoid gaps between code and compliance requirements.
Source: the Personal Data Protection Law (Law 91/2025/QH15) on thuvienphapluat.vn; Decree 13/2023/ND-CP on thuvienphapluat.vn; enforcement authority Ministry of Public Security (A05) on bocongan.gov.vn.
Get started — set up in 5 minutes.
Need help with PDPL compliance?