Manual DOM class toggling versus reactive state binding for Bulma interactive components
0 reputation · 22 Nov 2021, 12:40 UTC
0 reputation · 22 Nov 2021, 12:40 UTC
Bulma provides interactive component structures—modals, dropdowns, tabs—entirely through CSS classes such as is-active. Because the framework ships without JavaScript, every state change must be reflected in the DOM by the consuming application.
A single-page application built with a reactive framework (React, Vue, Svelte) already owns the source of truth for component visibility. The developer must decide whether to let the framework drive Bulma classes directly through declarative bindings or to imperatively toggle classes via refs and effect hooks.
Determine which approach yields a maintainable synchronization boundary between the framework's state layer and Bulma's CSS-only expectations without introducing duplicate state or timing mismatches.
34775 reputation · 23 Nov 2021, 00:30 UTC
Prefer declarative class bindings driven by the framework's state. Bind is-active from a single boolean such as isOpen, and reserve imperative ref toggling for rare cases where code outside the framework owns the element. This keeps one source of truth and prevents Bulma's CSS from falling out of sync with the component lifecycle.
This assumes a React, Vue, or Svelte SPA using Bulma 0.9.x or 1.x, where Bulma supplies only CSS and the framework owns visibility. If a third-party Bulma JavaScript plugin also toggles is-active, the two writers will conflict regardless of the binding method.
Confirmed: Bulma ships no JavaScript, so modal, dropdown, and tab visibility depends entirely on classes such as is-active. Reactive frameworks reconcile the DOM from state, so declarative binding makes the DOM a pure reflection of that state.
Likely explanation: Imperative toggling through refs works for isolated clicks, but during rapid updates the framework's next render can overwrite manually set classes. During server-side rendering hydration, client-side imperative changes before hydration completes can cause class flicker or hydration mismatches.
Bulma's CSS does not manage focus, ARIA attributes, or keyboard behavior. After the framework applies is-active, run focus management in a lifecycle hook that executes after mount and after isOpen changes—for example, useEffect in React, onMounted in Vue, or onMount in Svelte. Ensure the modal or dropdown node exists in the DOM before attaching listeners or moving focus. Conditional rendering or a portal can guarantee DOM presence before the hook runs.
Yes. Refs bypass the framework's reconciliation cycle. If a rapid state update triggers a re-render while a ref-based handler is pending, the framework may restore the class derived from state and overwrite the manual toggle. With SSR, the server HTML reflects server state; imperative client toggles before hydration can produce a mismatch between the hydrated DOM and the client's first render, causing flicker or a hydration error. Declarative bindings eliminate this because the class is computed during every render pass.
Community practice wraps Bulma markup in a framework component that accepts isOpen or value and conditionally renders is-active. The wrapper centralizes ARIA attributes, focus management, and class logic so consumers treat it as a controlled component. Example pattern:
function BulmaModal({ isOpen, onClose, children }) {
return (
{children}
);
}
const [isOpen, setIsOpen] = useState(false).is-active declaratively from that state on every render.isOpen changes.If you are using server-side rendering with hydration, imperative toggling can cause hydration flicker before the client takes over. This does not change the core recommendation, but it raises the risk of manual DOM writes.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.