Zero-config Presets
Drop-in components with NDPA-compliant defaults. One import, one prop, one working flow.
Overview
Presets are thin wrappers around the toolkit's building-block components, pre-loaded with sensible defaults — default consent categories, default DSR request types, default DPIA sections, default breach categories. You drop them in and they work. When you outgrow the defaults, you swap one prop (an adapter, a category list, a piece of copy) instead of re-assembling the entire flow.
- Presets — fastest path. Defaults are NDPA-aware (Section 25, 34, 38…) out of the box.
- Compound components — keep the toolkit's state machine; control the markup.
- Headless hooks — pure state, no UI.
The nine presets
All presets live under @tantainnovative/ndpr-toolkit/presets. Each one ships its prop interface alongside the component (e.g. NDPRConsentProps).
NDPRConsent
Consent banner with four default categories (essential, analytics, marketing, preferences). Position top, bottom, centre, or inline. Accepts a typed copy override so you can brand the banner without dropping to the lower-level <ConsentBanner>.
import { NDPRConsent } from '@tantainnovative/ndpr-toolkit/presets';
import { localStorageAdapter } from '@tantainnovative/ndpr-toolkit/adapters';
<NDPRConsent
adapter={localStorageAdapter('ndpr_consent')}
position="bottom"
copy={{
title: 'Cookie preferences',
description: 'Acme uses cookies to keep you signed in and improve our store.',
acceptAll: 'Allow all',
rejectAll: 'Only essentials',
}}
onSave={(settings) => console.log(settings)}
/>NDPRSubjectRights
DSR submission form with the seven NDPA request types (access, rectification, erasure, portability, restrict, object, withdraw_consent) pre-loaded, each annotated with its NDPA section reference. See the Submission patterns section below for the full submitTo workflow.
import { NDPRSubjectRights } from '@tantainnovative/ndpr-toolkit/presets';
<NDPRSubjectRights
submitTo="/api/dsr"
onSubmitSuccess={({ body }) => {
const ref = (body as { referenceId?: string })?.referenceId;
if (ref) router.push(`/dsr/confirmation?ref=${ref}`);
}}
/>NDPRBreachReport
Breach reporting form with five default categories (unauthorized access, data loss, data theft, system breach, accidental disclosure), each with a default severity. Wire onSubmit to your incident-response backend.
import { NDPRBreachReport } from '@tantainnovative/ndpr-toolkit/presets';
<NDPRBreachReport
onSubmit={async (report) => {
await fetch('/api/breach', { method: 'POST', body: JSON.stringify(report) });
}}
/>NDPRPrivacyPolicy
Adaptive policy wizard. Pass a sector template ('saas', 'ecommerce', 'school', 'healthcare', 'procurement') and the wizard opens pre-populated with the right data categories, lawful-basis defaults, and cross-border / sensitive-data flags. Users can still override every field.
import { NDPRPrivacyPolicy } from '@tantainnovative/ndpr-toolkit/presets';
<NDPRPrivacyPolicy
template="healthcare"
templateOverrides={{ orgName: 'Lagos Heart Centre' }}
onComplete={(policy) => savePolicyDraft(policy)}
/>NDPRDPIA
DPIA questionnaire pre-loaded with four NDPA-aligned sections: project overview, necessity & proportionality, risk identification, and risk mitigation. Each question carries a risk weight that feeds the overall assessment.
import { NDPRDPIA } from '@tantainnovative/ndpr-toolkit/presets';
<NDPRDPIA onResult={(result) => saveDPIA(result)} />NDPRLawfulBasis
Processing-activity tracker. Persists the activity list through your adapter; the underlying tracker renders the table, add/edit forms, and per-activity lawful basis selector.
import { NDPRLawfulBasis } from '@tantainnovative/ndpr-toolkit/presets';
import { localStorageAdapter } from '@tantainnovative/ndpr-toolkit/adapters';
<NDPRLawfulBasis adapter={localStorageAdapter('ndpr_lawful_basis')} />NDPRCrossBorder
Cross-border transfer manager. Tracks each transfer destination, lawful basis, and safeguard. Async adapters (cookie, api) are rehydrated on mount.
import { NDPRCrossBorder } from '@tantainnovative/ndpr-toolkit/presets';
<NDPRCrossBorder adapter={localStorageAdapter('ndpr_cross_border')} />NDPRROPA
Records of Processing Activities register. Manages the full RecordOfProcessingActivities document — organisation metadata plus the per-activity record list.
import { NDPRROPA } from '@tantainnovative/ndpr-toolkit/presets';
<NDPRROPA adapter={localStorageAdapter('ndpr_ropa')} />NDPRComplianceDashboard
Compliance score dashboard. Pass raw ComplianceInput (counts and signals from your stack); the preset calls getComplianceScore() internally and renders the score, breakdown, and recommendations. No adapter — this preset is purely presentational over a computed score.
import { NDPRComplianceDashboard } from '@tantainnovative/ndpr-toolkit/presets';
<NDPRComplianceDashboard
input={{
consent: { hasBanner: true, totalUsers: 1200, consentedUsers: 1050 },
dsr: { totalRequests: 14, completedOnTime: 13 },
// …see ComplianceInput in /core for the full shape
}}
maxRecommendations={5}
/>Common props
Most presets share the same three props:
adapter?: StorageAdapter<T>— persists the preset's state.localStorageAdapter,cookieAdapter,apiAdapter, andmemoryAdapterall ship under/adapters. See the adapters guide for the full surface.classNames?: { … }— per-slot class overrides. Each preset forwards its ownClassNamestype from the underlying component (e.g.ConsentBannerClassNames,DSRRequestFormClassNames).unstyled?: boolean— strips every default class. Pair withclassNamesto plug the preset into your own design system.
A typed copy prop currently ships on NDPRConsent only (see NDPRConsentCopy). For other presets, copy is controlled through the underlying component's props (e.g. requestTypes on NDPRSubjectRights, sections on NDPRDPIA).
Submission patterns for NDPRSubjectRights
DSR is the one preset where most consumers reach for a public-form POST instead of a state-managed adapter. NDPRSubjectRights ships four extra props for this:
submitTo: string— URL the form POSTs the JSON-serialised submission to.submitOptions—{ headers?, credentials? }. Headers may be an object or a getter. Defaults tocredentials: 'same-origin'.onSubmitSuccess— fires on 2xx. Receives{ response, data, body }, wherebodyis the parsed JSON (orundefinedfor empty / non-JSON responses).onSubmitError— fires on network error or non-2xx. Receives{ error?, response? }.
The body field is intentionally typed unknown — narrow it yourself before reading server-issued reference numbers.
import { NDPRSubjectRights } from '@tantainnovative/ndpr-toolkit/presets';
import { useRouter } from 'next/navigation';
export function PublicDSRForm() {
const router = useRouter();
return (
<NDPRSubjectRights
submitTo="/api/dsr"
submitOptions={{
headers: () => ({ 'X-CSRF-Token': readCsrfCookie() }),
credentials: 'same-origin',
}}
onSubmitSuccess={({ response, data, body }) => {
const ref = (body as { referenceId?: string } | undefined)?.referenceId;
if (ref) router.push(`/dsr/confirmation?ref=${ref}`);
else console.warn('DSR POST returned no referenceId', response, data);
}}
onSubmitError={({ error, response }) => {
console.error('DSR submission failed', error ?? response);
}}
/>
);
}For complete control over headers, retries, or auth, build an apiAdapter (which supports CSRF, retry, and error hooks) and pass it as adapter instead. submitTo is the fire-and-forget shortcut for public forms.
Narrower subpath imports
The three most common presets each ship under a dedicated subpath. They're identical to the /presetsbarrel re-exports — use them when you want a tighter dependency graph for that page's bundle.
// Same export, narrower entry — bundler doesn't have to crawl the full barrel.
import { NDPRConsent } from '@tantainnovative/ndpr-toolkit/presets/consent';
import { NDPRSubjectRights } from '@tantainnovative/ndpr-toolkit/presets/dsr';
import { NDPRPrivacyPolicy } from '@tantainnovative/ndpr-toolkit/presets/policy';The remaining six presets (NDPRBreachReport, NDPRDPIA, NDPRLawfulBasis, NDPRCrossBorder, NDPRROPA, NDPRComplianceDashboard) are reachable only via the /presets barrel for now.
Going beyond presets
- Compound components — when you need to control the layout slot-by-slot but keep the toolkit's state machine.
- Headless / hooks-only API — when you need the consent / DSR / DPIA state but want zero UI from the toolkit.
- Styling & customization — the
classNamesslot API and theunstyledescape hatch in detail.