Headless / hooks-only API
Build a completely custom UI on top of the toolkit's compliance state machines. The /headless subpath ships every hook with zero UI surface, perfect for headless component libraries and bespoke design systems.
Overview
The toolkit ships React hooks for every compliance module — consent, DSR, DPIA, breach, lawful basis, cross-border, ROPA, and policy. New in 3.10.0, you can import them from @tantainnovative/ndpr-toolkit/headless — an alias of the existing /hooks subpath, named for discoverability.
The two subpaths export exactly the same surface — they re-export the same identifiers from the same source. Pick whichever name fits your mental model:
/hooks— if your codebase speaks "React hooks"./headless— if you're building a headless component library or pairing with Radix / Ariakit / Headless UI.
Quickstart
import { useConsent } from '@tantainnovative/ndpr-toolkit/headless';
function MyCustomConsentBanner() {
const {
settings,
hasInteracted,
shouldShowBanner,
acceptAll,
rejectAll,
updateOption,
} = useConsent({
options: [
{ id: 'analytics', label: 'Analytics', description: '...', required: false, purpose: 'Product analytics' },
{ id: 'marketing', label: 'Marketing', description: '...', required: false, purpose: 'Outreach' },
],
});
if (!shouldShowBanner) return null;
return (
<aside role="dialog" aria-labelledby="consent-title">
<h2 id="consent-title">Your privacy</h2>
{/* …entirely your UI… */}
<button onClick={acceptAll}>Accept all</button>
<button onClick={rejectAll}>Reject all</button>
</aside>
);
}You own every DOM node and every class name. The hook just owns state, persistence (via the configured adapter), and the consent lifecycle invariants.
Available hooks
Every compliance module has a hook. They're identical to the hooks the bundled UI components consume internally:
import {
useConsent,
useDSR,
useDPIA,
useBreach,
useLawfulBasis,
useCrossBorderTransfer,
useROPA,
useComplianceScore,
useAdaptivePolicyWizard,
useFocusTrap, // shared a11y primitive
} from '@tantainnovative/ndpr-toolkit/headless';Each hook's argument and return types are exported alongside it — TypeScript autocomplete tells you exactly what each hook offers.
Bundle size
The /headless entry has no UI components or styling importsin its dependency graph. A bundler that supports tree-shaking will drop everything you don't use, so you pay only for the hooks you actually import — typically a few KB minified for a single module.
If you also import '@tantainnovative/ndpr-toolkit/styles' for some pages and use /headless on others, the stylesheet ships only on the pages that import it. Headless pages stay style-free.
Wiring storage adapters
Hooks accept the same adapter prop the preset components do. Mix-and-match adapters per hook — for example, persist consent to a cookie (server-readable) and DSR drafts to localStorage:
import { useConsent, useDSR } from '@tantainnovative/ndpr-toolkit/headless';
import { cookieAdapter, localStorageAdapter } from '@tantainnovative/ndpr-toolkit/adapters';
const consent = useConsent({
options,
adapter: cookieAdapter('ndpr_consent', { expires: 365 }),
});
const dsr = useDSR({
adapter: localStorageAdapter('ndpr_dsr_draft'),
});