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'),
});