React adapter
Compose Boobstrap’s visual system with SSR-safe headless hooks while React owns state, markup, refs, and lifecycle.
Install and import
Install the core framework, React adapter, and React peer together. Import the compiled stylesheet once at your application entry point, then import only the hooks used by a component.
npm install @boobstrap/boobstrap @boobstrap/react react react-domimport "@boobstrap/boobstrap/dist/boobstrap.css";
import { useCollapse } from "@boobstrap/react";initBoobstrap on React-owned markup. The hook supplies state, ARIA attributes, event handlers, and refs; your JSX supplies the semantic elements and bs-* classes.Compose a component
Prop getters merge consumer handlers with the adapter contract. The preview is the rendered result of the JSX directly below it: the hook supplies the button type, relationship, expanded state, panel ID, visibility, and public state while your component supplies the content and classes.
import { useCollapse } from "@boobstrap/react";
export function Details() {
const details = useCollapse({ id: "account-details", defaultOpen: true });
return (
<>
<button className="bs-btn bs-btn-secondary"
{...details.getTriggerProps()}>
Account details
</button>
<div className="bs-collapse bs-card bs-mt-4"
{...details.getPanelProps()}>
<div className="bs-card-body">Profile and security settings.</div>
</div>
</>
);
}Controlled and uncontrolled state
Use defaultOpen, defaultLoading, or defaultSelectedId when the hook should own state. Pass the corresponding controlled value and change callback when application state is authoritative.
import { useState } from "react";
import { useDialog } from "@boobstrap/react";
export function AccountDialog() {
const [open, setOpen] = useState(false);
const dialog = useDialog({
id: "account-dialog",
open,
onOpenChange: setOpen,
});
return (
<>
<button className="bs-btn" {...dialog.getTriggerProps()}>Edit account</button>
<dialog className="bs-dialog" aria-labelledby="account-dialog-title"
{...dialog.getDialogProps()}>
<header className="bs-dialog-header">
<h2 className="bs-dialog-title" id="account-dialog-title">Account</h2>
<button className="bs-dialog-close" aria-label="Close account"
{...dialog.getDismissProps()}>×</button>
</header>
<div className="bs-dialog-body">Account settings.</div>
</dialog>
</>
);
}Events, cancelation, and SSR
Hooks emit the same cancelable before-events and completed lifecycle events as core controllers. Change callbacks receive the next value plus a detail object containing adapter: "react", a transition reason, and the source event when one exists.
- Prevent a
bs:*:show,bs:*:hide,bs:tabs:change, or button before-event to cancel its transition. - Hooks avoid DOM reads during render. Stable generated IDs come from React’s
useId, so server output can hydrate without replacing relationships. - DOM work such as native dialog synchronization, focus restoration, outside-click handling, and floating placement runs after mounting and cleans up with the component.
const menu = useDropdown({
onOpenChange(nextOpen, detail) {
console.log(nextOpen, detail.adapter, detail.reason);
},
});One owner
Use React hooks or core controllers on a subtree, never both. Hooks do not initialize or search the document.
SSR
Render-time work is DOM-free. Effects synchronize dialogs, focus, listeners, timers, and floating placement after mount.
State
Choose uncontrolled default* options for local ownership or controlled values plus change callbacks for application ownership.
Props
Pass consumer handlers into a prop getter so the adapter can compose them. Preserve the returned refs, IDs, ARIA attributes, and keyboard handlers.
Component guides
Use the adapter reference for shared ownership rules, then use each component guide for copy-ready JSX and its component-specific semantics.
Hook API
| Hook | Public contract |
|---|---|
useAccordion | Open ID collection, single-open or always-open coordination, item options, and root props. |
useButton | Loading state, start/stop/toggle methods, busy semantics, and composed button props. |
useCollapse | Open state, stable panel ID, show/hide/toggle methods, and trigger/panel props. |
useDialog | Native modal synchronization, dismissal, Escape handling, focus restoration, and dialog props. |
useDropdown | Menu state, outside dismissal, action-menu keyboard behavior, focus restoration, and root/trigger/menu props. |
useCombobox | Query, selection, filtered options, active index, keyboard behavior, and input/listbox/option props. |
useTabs | Selected tab state, activation, roving focus, and synchronized tablist/tab/panel props. |
useToast | Open state, pause-aware autohide, trigger/dismiss props, and polite live-region defaults. |
useTooltip | Hover/focus visibility, Escape dismissal, placement, and descriptive relationships. |
usePopover | Activation state, outside/Escape dismissal, placement, and trigger/panel relationships. |