Tutorials / / 3 min read
How to create a dismissible cookie banner with Tailwind CSS: JavaScript and Alpine.js
Build an accessible, dismissible cookie banner with Tailwind CSS, two ways: vanilla JavaScript or Alpine.js, with focus management for keyboard users.
Cookies, here we come! Today we are building a dismissible cookie banner, twice: first with vanilla JavaScript, then with Alpine.js, so you can pick whichever fits your stack.
What is a cookie banner?
A cookie banner is the little dialog that tells visitors your site uses cookies and asks for their consent. It’s more than a formality: privacy laws like GDPR and CCPA make it a legal necessity, and a clear, accessible banner builds trust by letting users make informed choices about their data.
Use cases
- Educating users: explain in plain language how their data is collected and used.
- Legal compliance: meet GDPR, CCPA and other privacy laws that require consent.
- Empowering choices: let visitors distinguish essential from non-essential cookies.
- Building trust: a clear, user-friendly banner leaves a better impression and can even help conversion.
The markup
id="cookie-banner": the id of the cookie banner.role="dialog": tells assistive technology the banner is a dialog window.aria-labelledby="cookieBannerTitle"andaria-describedby="cookieBannerDesc": link the dialog to its title and description for screen readers.id="accept-cookies": the button JavaScript uses to dismiss the banner.
<div
id="cookie-banner"
role="dialog"
aria-labelledby="cookieBannerTitle"
aria-describedby="cookieBannerDesc"
>
<!-- Cookie banner content container -->
<div>
<img src="..." alt="Cookies" />
<h2>Our website uses cookies</h2>
<p>
Our website uses cookies. By continuing, we assume your permission to
deploy cookies as detailed in our <a href="#">Privacy Policy.</a>
</p>
<!-- Accept cookies button -->
<div class="mt-8">
<button id="accept-cookies">Accept all cookies</button>
</div>
<!-- Manage cookies link -->
<div>
<a href="#">Manage cookies</a>
</div>
</div>
</div>The script
document.addEventListener("DOMContentLoaded", () => {: waits for the page, then grabs the banner and the accept button.acceptButton.focus();: sets focus on the accept button as soon as the banner is displayed, which keyboard users will thank you for.acceptButton.addEventListener("click", function () {: hides the banner withcookieBanner.style.display = "none";when the button is clicked.
document.addEventListener("DOMContentLoaded", function () {
const cookieBanner = document.getElementById("cookie-banner");
const acceptButton = document.getElementById("accept-cookies");
// Set focus on the accept button once the banner is displayed
acceptButton.focus();
// Hide the cookie banner when the accept button is clicked
acceptButton.addEventListener("click", function () {
cookieBanner.style.display = "none";
});
});The Alpine.js version
Same component, no separate script: the state lives in x-data and the focus management happens right in the markup.
x-data="{ showAlert: true }": initializes the component’s state.x-init="$nextTick(() => { if (showAlert) $refs.firstButton.focus() })": focuses the “Accept all cookies” button as soon as the banner shows, for keyboard navigation.x-show="showAlert": controls the visibility of the banner based on user consent.x-ref="firstButton"with@click="showAlert = false": dismisses the banner.
<div
x-data="{ showAlert: true }"
x-init="$nextTick(() => { if (showAlert) $refs.firstButton.focus() })"
x-show="showAlert"
role="dialog"
aria-labelledby="cookieBannerTitle"
aria-describedby="cookieBannerDesc"
class="..."
>
<div class="...">
<img src="..." alt="Cookies" class="..." />
<h2 id="cookieBannerTitle" class="...">...</h2>
<p id="cookieBannerDesc" class="...">...</p>
<button x-ref="firstButton" @click="showAlert = false" class="...">
...
</button>
<a href="#_" class="...">...</a>
</div>
</div>You can try the Alpine version separately: live demo and source code.
Which one should you use?
If Alpine is already on the page, x-show and x-init handle visibility and focus with no script at all. If not, the vanilla version is a handful of lines and no dependency.
Conclusion
Whichever flavor you pick, keep the banner accessible: clear, jargon-free text, keyboard navigation, and content screen readers can interpret. It’s about making the internet a welcoming place for all.
Hope you enjoyed this tutorial and have a great day!
/Michael Andreuzza