Bulma Modals: CSS Structure, Manual JavaScript Behavior
Bulma's modal classes provide the markup, but show/hide logic and keyboard handling are yours to implement.
12 Sept 2026, 22:41 UTC

The problem: Bulma gives you the look, not the behavior
You add Bulma to a project and need a dialog. The documentation shows a modal built from four CSS classes—modal, modal-background, modal-content, and modal-close. Copy the markup, open the page, and nothing happens. The modal stays hidden because Bulma only styles it; it does not add or remove the is-active class that makes the wrapper visible.
The useful takeaway: treat Bulma's modal as a CSS skeleton. You write the small JavaScript that toggles state, closes on backdrop or Escape, and handles the accessibility details Bulma omits.
1. The markup Bulma expects
A Bulma modal needs a wrapper with class='modal'. When is-active is present, the wrapper and its backdrop display. Inside, modal-background is the clickable overlay behind the dialog, modal-content holds your form or message, and modal-close is the × button.
2. A minimal toggle script
Save this as modal.html and open it directly in Chrome, Firefox, or Safari. No build step, npm package, or administrator permissions are required.
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/bulma@VERSION/css/bulma.min.css'>
<button class='button is-primary' id='open-modal'>Open dialog</button>
<div class='modal' id='target-modal'>
<div class='modal-background' id='modal-backdrop'></div>
<div class='modal-content'>
<div class='box'>
<p>This is a Bulma modal.</p>
</div>
</div>
<button class='modal-close is-large' id='close-modal' aria-label='Close'></button>
</div>
<script>
const modal = document.getElementById('target-modal');
const openBtn = document.getElementById('open-modal');
const closeBtn = document.getElementById('close-modal');
const backdrop = document.getElementById('modal-backdrop');
function openModal() { modal.classList.add('is-active'); }
function closeModal() { modal.classList.remove('is-active'); }
openBtn.addEventListener('click', openModal);
closeBtn.addEventListener('click', closeModal);
backdrop.addEventListener('click', closeModal);
document.addEventListener('keydown', (event) => {
if (event.key === 'Escape' && modal.classList.contains('is-active')) {
closeModal();
}
});
</script>
Where to run: save the file locally and open it in a browser. No server or elevated permissions are needed. Replace VERSION with the Bulma release your project uses.
Expected checks: open DevTools, inspect #target-modal, click 'Open dialog', and confirm is-active appears on the wrapper. Click the backdrop or the × button and confirm the class disappears. Press Escape while open and confirm the same.
Risk: if you omit the backdrop listener, clicking outside the modal does nothing and the dialog can appear stuck open.
3. What Bulma does not provide
Bulma's CSS handles visibility and layout, not interaction. Focus trapping, ARIA attributes such as aria-modal='true' (which tell assistive technologies that an element is a dialog), and returning focus to the trigger after close are not included. For a production dialog, add those yourself or the modal may fail keyboard-only and screen-reader testing.
Trade-off: animation and state management
Bulma modals do not animate by default. Adding a fade transition means custom CSS or Sass overrides, which increases your stylesheet slightly. In single-page applications, also watch for modal state that survives navigation; if a route changes while is-active remains, the dialog can linger over the new page.
How to verify the result
- Open the HTML file in a browser.
- Open DevTools and select the modal wrapper.
- Click the trigger and confirm
is-activeis added. - Click the backdrop, click the close button, and press Escape; confirm
is-activeis removed each time. - Tab through the page with the modal open and note whether focus escapes the dialog.
If focus leaves the modal or the backdrop click fails, add the missing listener or ARIA attributes before deploying.
Closing
Bulma's modal is deliberately unopinionated about JavaScript. The CSS classes give you a responsive, centered dialog; the is-active toggle, backdrop dismissal, Escape handling, and focus management are engineering decisions you make. Start with the snippet above, verify the class toggles in DevTools, then add the accessibility behavior your audience needs.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.