@c15t/nextjs 2.2.1 → 3.0.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +102 -142
- package/README.md +4 -4
- package/dist/api.js +1 -0
- package/dist/config.js +1 -0
- package/dist/devtools.js +2 -0
- package/dist/headers.js +1 -0
- package/dist/iab/styles.css +1 -1
- package/dist/iab/styles.tw3.css +133 -19
- package/dist/index.js +1 -1
- package/dist/middleware.js +1 -0
- package/dist/node-bridge.js +1 -0
- package/dist/pages.js +1 -0
- package/dist/proxy.js +1 -0
- package/dist/root.js +2 -0
- package/dist/server.js +1 -0
- package/dist/static.js +1 -0
- package/dist/styles.css +1 -1
- package/dist/styles.tw3.css +173 -29
- package/dist/version.js +1 -1
- package/dist-types/api.d.ts +88 -0
- package/dist-types/config.d.ts +110 -0
- package/dist-types/devtools.d.ts +1 -0
- package/dist-types/headers.d.ts +4 -0
- package/dist-types/index.d.ts +28 -10
- package/dist-types/middleware.d.ts +15 -0
- package/dist-types/node-bridge.d.ts +57 -0
- package/dist-types/pages.d.ts +88 -0
- package/dist-types/proxy.d.ts +34 -0
- package/dist-types/root.d.ts +86 -0
- package/dist-types/server.d.ts +164 -0
- package/dist-types/static.d.ts +42 -0
- package/dist-types/types.d.ts +5 -36
- package/dist-types/version.d.ts +1 -1
- package/docs/README.md +102 -142
- package/docs/assets/v3/brand-bar.png +0 -0
- package/docs/assets/v3/brand-card.png +0 -0
- package/docs/assets/v3/choice-wall.png +0 -0
- package/docs/assets/v3/mobile-card.png +0 -0
- package/docs/assets/v3/preferences.png +0 -0
- package/docs/customization/overview.md +45 -0
- package/docs/customization/recipes.md +79 -0
- package/docs/customization/slots.md +55 -0
- package/docs/customization/tokens.md +76 -0
- package/docs/customization/translations.md +49 -0
- package/docs/frameworks/next/api-reference/data-fetching.md +416 -0
- package/docs/frameworks/next/app-router.md +403 -0
- package/docs/frameworks/next/client-side.md +118 -0
- package/docs/frameworks/next/components/consent-banner.md +251 -211
- package/docs/frameworks/next/components/consent-dialog-link.md +96 -35
- package/docs/frameworks/next/components/consent-dialog-trigger.md +74 -149
- package/docs/frameworks/next/components/consent-dialog.md +189 -134
- package/docs/frameworks/next/components/consent-manager-provider.md +60 -318
- package/docs/frameworks/next/components/consent-widget.md +172 -114
- package/docs/frameworks/next/components/dev-tools.md +199 -40
- package/docs/frameworks/next/components/frame.md +137 -42
- package/docs/frameworks/next/concepts/consent-categories.md +24 -89
- package/docs/frameworks/next/concepts/policy-presets.md +142 -0
- package/docs/frameworks/next/content-security-policy.md +189 -0
- package/docs/frameworks/next/data-fetching.md +74 -0
- package/docs/frameworks/next/geography-headers.md +251 -0
- package/docs/frameworks/next/headless.md +95 -185
- package/docs/frameworks/next/hooks/use-consent-manager/overview.md +42 -163
- package/docs/frameworks/next/iab/overview.md +37 -107
- package/docs/frameworks/next/optimization.md +158 -194
- package/docs/frameworks/next/pages-router.md +296 -0
- package/docs/frameworks/next/quickstart.md +31 -132
- package/docs/frameworks/next/script-loader.md +134 -467
- package/docs/frameworks/next/server-side.md +97 -130
- package/docs/frameworks/next/static-export.md +164 -0
- package/docs/frameworks/next/styling/overview.md +166 -250
- package/docs/frameworks/next/troubleshooting.md +134 -144
- package/docs/guides/consent-state.md +60 -0
- package/docs/guides/data-fetching.md +163 -0
- package/docs/guides/deployment-modes.md +63 -0
- package/docs/guides/troubleshooting.md +68 -0
- package/docs/guides/verify-consent.md +62 -0
- package/docs/integrations/adobe-analytics.md +239 -105
- package/docs/integrations/ahrefs-analytics.md +238 -104
- package/docs/integrations/amplitude.md +219 -157
- package/docs/integrations/building-integrations.md +32 -224
- package/docs/integrations/clearbit.md +247 -86
- package/docs/integrations/cloudflare-web-analytics.md +250 -84
- package/docs/integrations/crisp.md +251 -97
- package/docs/integrations/databuddy.md +259 -153
- package/docs/integrations/fathom-analytics.md +239 -96
- package/docs/integrations/google-maps.md +328 -207
- package/docs/integrations/google-tag-manager.md +248 -96
- package/docs/integrations/google-tag.md +261 -90
- package/docs/integrations/heap.md +222 -149
- package/docs/integrations/hightouch.md +225 -131
- package/docs/integrations/hotjar.md +239 -90
- package/docs/integrations/intercom.md +239 -98
- package/docs/integrations/linkedin-insights.md +243 -113
- package/docs/integrations/logrocket.md +241 -123
- package/docs/integrations/matomo-analytics.md +256 -111
- package/docs/integrations/meta-pixel.md +197 -324
- package/docs/integrations/microsoft-clarity.md +233 -114
- package/docs/integrations/microsoft-uet.md +245 -110
- package/docs/integrations/mixpanel-analytics.md +252 -87
- package/docs/integrations/openai-pixel.md +441 -0
- package/docs/integrations/overview.md +95 -133
- package/docs/integrations/pirsch.md +249 -96
- package/docs/integrations/plausible-analytics.md +241 -100
- package/docs/integrations/posthog.md +353 -214
- package/docs/integrations/promptwatch.md +251 -81
- package/docs/integrations/reddit-pixel.md +226 -173
- package/docs/integrations/rudderstack.md +244 -187
- package/docs/integrations/rybbit-analytics.md +244 -91
- package/docs/integrations/segment.md +238 -92
- package/docs/integrations/snapchat-pixel.md +240 -110
- package/docs/integrations/tiktok-pixel.md +249 -81
- package/docs/integrations/umami-analytics.md +242 -95
- package/docs/integrations/vercel-analytics.md +242 -90
- package/docs/integrations/x-pixel.md +238 -104
- package/docs/integrations/youtube.md +354 -142
- package/docs/upgrade-v3.md +334 -0
- package/iab/styles.css +1 -1
- package/iab/styles.tw3.css +1 -1
- package/package.json +106 -65
- package/readme.json +3 -3
- package/src/iab/styles.css +1 -1
- package/src/iab/styles.tw3.css +1 -1
- package/src/styles.css +1 -1
- package/src/styles.tw3.css +1 -1
- package/styles.css +1 -1
- package/styles.tw3.css +1 -1
- package/client/components/consent-dialog-link.js +0 -3
- package/client/components/integrations.js +0 -3
- package/dist/components/integrations/index.cjs +0 -1
- package/dist/components/integrations/index.js +0 -1
- package/dist/headless.cjs +0 -1
- package/dist/index.cjs +0 -1
- package/dist/libs/browser-initial-data.cjs +0 -1
- package/dist/libs/browser-initial-data.js +0 -1
- package/dist/libs/initial-data.cjs +0 -1
- package/dist/libs/initial-data.js +0 -1
- package/dist/types.cjs +0 -1
- package/dist/version.cjs +0 -1
- package/dist-types/components/integrations/index.d.ts +0 -1
- package/dist-types/libs/browser-initial-data.d.ts +0 -9
- package/dist-types/libs/initial-data.d.ts +0 -33
- package/docs/frameworks/next/building-headless-components.md +0 -379
- package/docs/frameworks/next/callbacks.md +0 -186
- package/docs/frameworks/next/concepts/client-modes.md +0 -177
- package/docs/frameworks/next/concepts/consent-models.md +0 -117
- package/docs/frameworks/next/concepts/cookie-management.md +0 -122
- package/docs/frameworks/next/concepts/glossary.md +0 -24
- package/docs/frameworks/next/concepts/initialization-flow.md +0 -149
- package/docs/frameworks/next/concepts/policy-packs.md +0 -230
- package/docs/frameworks/next/hooks/use-color-scheme.md +0 -41
- package/docs/frameworks/next/hooks/use-consent-manager/checking-consent.md +0 -96
- package/docs/frameworks/next/hooks/use-consent-manager/location-info.md +0 -97
- package/docs/frameworks/next/hooks/use-consent-manager/setting-consent.md +0 -94
- package/docs/frameworks/next/hooks/use-draggable.md +0 -59
- package/docs/frameworks/next/hooks/use-focus-trap.md +0 -42
- package/docs/frameworks/next/hooks/use-reduced-motion.md +0 -37
- package/docs/frameworks/next/hooks/use-ssr-status.md +0 -32
- package/docs/frameworks/next/hooks/use-text-direction.md +0 -50
- package/docs/frameworks/next/hooks/use-translations.md +0 -55
- package/docs/frameworks/next/iab/consent-banner.md +0 -91
- package/docs/frameworks/next/iab/consent-dialog.md +0 -129
- package/docs/frameworks/next/iab/use-gvl-data.md +0 -21
- package/docs/frameworks/next/iframe-blocking.md +0 -106
- package/docs/frameworks/next/internationalization.md +0 -207
- package/docs/frameworks/next/network-blocker.md +0 -140
- package/docs/frameworks/next/policy-packs.md +0 -248
- package/docs/frameworks/next/styling/classnames.md +0 -94
- package/docs/frameworks/next/styling/color-scheme.md +0 -84
- package/docs/frameworks/next/styling/css-variables.md +0 -53
- package/docs/frameworks/next/styling/slots.md +0 -94
- package/docs/frameworks/next/styling/tailwind.md +0 -137
- package/docs/frameworks/next/styling/tokens.md +0 -156
- package/docs/shared/concepts/client-modes.md +0 -103
- package/docs/shared/concepts/consent-categories.md +0 -41
- package/docs/shared/concepts/consent-models.md +0 -72
- package/docs/shared/concepts/cookie-management.md +0 -88
- package/docs/shared/concepts/glossary.md +0 -24
- package/docs/shared/concepts/initialization-flow.md +0 -105
- package/docs/shared/concepts/policy-packs.md +0 -225
- package/docs/shared/react/components/consent-banner.md +0 -242
- package/docs/shared/react/components/consent-dialog-link.md +0 -45
- package/docs/shared/react/components/consent-dialog-trigger.md +0 -185
- package/docs/shared/react/components/consent-dialog.md +0 -119
- package/docs/shared/react/components/consent-manager-provider.md +0 -225
- package/docs/shared/react/components/consent-widget.md +0 -121
- package/docs/shared/react/components/dev-tools.md +0 -81
- package/docs/shared/react/components/frame.md +0 -52
- package/docs/shared/react/guides/building-headless-components.md +0 -110
- package/docs/shared/react/guides/callbacks.md +0 -89
- package/docs/shared/react/guides/headless.md +0 -31
- package/docs/shared/react/guides/iframe-blocking.md +0 -65
- package/docs/shared/react/guides/internationalization.md +0 -123
- package/docs/shared/react/guides/network-blocker.md +0 -72
- package/docs/shared/react/guides/optimization.md +0 -44
- package/docs/shared/react/guides/policy-packs.md +0 -173
- package/docs/shared/react/guides/script-loader.md +0 -311
- package/docs/shared/react/hooks/use-color-scheme.md +0 -31
- package/docs/shared/react/hooks/use-consent-manager/checking-consent.md +0 -95
- package/docs/shared/react/hooks/use-consent-manager/location-info.md +0 -96
- package/docs/shared/react/hooks/use-consent-manager/overview.md +0 -74
- package/docs/shared/react/hooks/use-consent-manager/setting-consent.md +0 -93
- package/docs/shared/react/hooks/use-draggable.md +0 -30
- package/docs/shared/react/hooks/use-focus-trap.md +0 -20
- package/docs/shared/react/hooks/use-reduced-motion.md +0 -33
- package/docs/shared/react/hooks/use-ssr-status.md +0 -16
- package/docs/shared/react/hooks/use-text-direction.md +0 -38
- package/docs/shared/react/hooks/use-translations.md +0 -15
- package/docs/shared/react/iab/consent-banner.md +0 -60
- package/docs/shared/react/iab/consent-dialog.md +0 -76
- package/docs/shared/react/iab/overview.md +0 -80
- package/docs/shared/react/iab/use-gvl-data.md +0 -21
- package/docs/shared/react/styling/classnames.md +0 -93
- package/docs/shared/react/styling/color-scheme.md +0 -35
- package/docs/shared/react/styling/css-variables.md +0 -53
- package/docs/shared/react/styling/overview.md +0 -261
- package/docs/shared/react/styling/slots.md +0 -93
- package/docs/shared/react/styling/stylesheet-entrypoint.md +0 -8
- package/docs/shared/react/styling/tailwind.md +0 -88
- package/docs/shared/react/styling/tokens.md +0 -155
- package/docs/shared/troubleshooting.md +0 -82
|
@@ -1,169 +1,224 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: ConsentDialog
|
|
3
|
-
description:
|
|
3
|
+
description: Mount ConsentDialog as a Client Component inside a Next.js
|
|
4
|
+
ConsentRoot to open the preference center from the banner, links and triggers.
|
|
4
5
|
group: frameworks
|
|
5
6
|
---
|
|
6
|
-
`ConsentDialog` is a modal that shows toggles for each consent category. In **opt-in jurisdictions**, it typically opens when users click "Customize" on `ConsentBanner`. It can also be controlled programmatically for use on settings pages regardless of jurisdiction.
|
|
7
7
|
|
|
8
|
-
##
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
## Open the preference center
|
|
9
|
+
|
|
10
|
+
`ConsentDialog` is the modal preference center. It is a Client Component, so
|
|
11
|
+
it lives in the `components/consent.tsx` wrapper from the
|
|
12
|
+
[App Router](../app-router.md) or
|
|
13
|
+
[Pages Router](../pages-router.md) setup, inside the
|
|
14
|
+
`ConsentRoot` that already provides the consent runtime. Mount it once,
|
|
15
|
+
next to the banner; it opens whenever something makes `dialog` the active
|
|
16
|
+
surface: the banner's Customize button, a `ConsentDialogLink` in your footer,
|
|
17
|
+
a `ConsentDialogTrigger`, or your own code.
|
|
18
|
+
|
|
19
|
+
```tsx title="components/consent.tsx"
|
|
20
|
+
'use client';
|
|
21
|
+
|
|
22
|
+
import type { ReactNode } from 'react';
|
|
23
|
+
import {
|
|
24
|
+
ConsentBanner,
|
|
25
|
+
ConsentDialog,
|
|
26
|
+
ConsentDialogLink,
|
|
27
|
+
ConsentRoot,
|
|
28
|
+
} from 'c15t/next';
|
|
29
|
+
import type { ConsentRootProps } from 'c15t/next';
|
|
30
|
+
import { consentConfig } from '../c15t.config';
|
|
31
|
+
|
|
32
|
+
export function Consent({
|
|
33
|
+
children,
|
|
34
|
+
state,
|
|
35
|
+
}: {
|
|
36
|
+
children: ReactNode;
|
|
37
|
+
state: ConsentRootProps['state'];
|
|
38
|
+
}) {
|
|
14
39
|
return (
|
|
15
|
-
<
|
|
40
|
+
<ConsentRoot state={state} config={consentConfig}>
|
|
41
|
+
{children}
|
|
16
42
|
<ConsentBanner />
|
|
17
|
-
<ConsentDialog />
|
|
18
|
-
|
|
43
|
+
<ConsentDialog hideBranding />
|
|
44
|
+
<footer>
|
|
45
|
+
<ConsentDialogLink>Privacy settings</ConsentDialogLink>
|
|
46
|
+
</footer>
|
|
47
|
+
</ConsentRoot>
|
|
19
48
|
);
|
|
20
49
|
}
|
|
21
50
|
```
|
|
22
51
|
|
|
23
|
-
|
|
52
|
+
The root layout renders `Consent` with the `state` from
|
|
53
|
+
`resolveConsent`, as in the router guides. The dialog itself renders
|
|
54
|
+
nothing on the server: it mounts through a portal after hydration, so the
|
|
55
|
+
server HTML and the streamed shell are unaffected by it. If the visitor owes
|
|
56
|
+
a choice or notice, routes that await `resolveConsent` can render the
|
|
57
|
+
banner on the server. Pages Router pages without `getServerSideProps` show it
|
|
58
|
+
after browser policy resolution. No banner appears when the policy requires
|
|
59
|
+
no prompt or an existing record already satisfies it.
|
|
24
60
|
|
|
25
|
-
|
|
61
|
+
To open it from another Client Component inside the boundary, set the active
|
|
62
|
+
surface:
|
|
26
63
|
|
|
27
|
-
```tsx
|
|
28
|
-
|
|
64
|
+
```tsx title="components/privacy-menu-item.tsx"
|
|
65
|
+
'use client';
|
|
29
66
|
|
|
30
|
-
|
|
31
|
-
const [open, setOpen] = useState(false);
|
|
67
|
+
import { useSetActiveUI } from 'c15t/next';
|
|
32
68
|
|
|
69
|
+
export function PrivacyMenuItem() {
|
|
70
|
+
const setActiveUI = useSetActiveUI();
|
|
33
71
|
return (
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
<ConsentDialog open={open} />
|
|
37
|
-
</>
|
|
38
|
-
);
|
|
39
|
-
}
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
Or use the hook to open it programmatically:
|
|
43
|
-
|
|
44
|
-
```tsx
|
|
45
|
-
import { useConsentManager } from '@c15t/nextjs';
|
|
46
|
-
|
|
47
|
-
function PrivacyLink() {
|
|
48
|
-
const { setActiveUI } = useConsentManager();
|
|
49
|
-
|
|
50
|
-
return (
|
|
51
|
-
<button onClick={() => setActiveUI('dialog')}>
|
|
52
|
-
Manage cookies
|
|
72
|
+
<button type="button" onClick={() => setActiveUI('dialog')}>
|
|
73
|
+
Cookie preferences
|
|
53
74
|
</button>
|
|
54
75
|
);
|
|
55
76
|
}
|
|
56
77
|
```
|
|
57
78
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
{/* Default trigger */}
|
|
64
|
-
<ConsentDialog showTrigger />
|
|
65
|
-
|
|
66
|
-
{/* Custom trigger */}
|
|
67
|
-
<ConsentDialog
|
|
68
|
-
showTrigger={{
|
|
69
|
-
icon: 'settings',
|
|
70
|
-
defaultPosition: 'bottom-left',
|
|
71
|
-
showWhen: 'after-consent',
|
|
72
|
-
size: 'sm',
|
|
73
|
-
}}
|
|
74
|
-
/>
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
## Branding
|
|
78
|
-
|
|
79
|
-
Hide the c15t branding tag:
|
|
80
|
-
|
|
81
|
-
```tsx
|
|
82
|
-
<ConsentDialog hideBranding />
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
## Styling First
|
|
86
|
-
|
|
87
|
-
> ℹ️ **Info:**
|
|
88
|
-
> If you are only changing visuals, stay with the stock dialog and use the theme system first. Start with tokens and slots such as consentDialogCard, consentWidgetFooter, and consentDialogTag. See Styling Overview.
|
|
89
|
-
|
|
90
|
-
```tsx
|
|
91
|
-
<ConsentManagerProvider
|
|
92
|
-
options={{
|
|
93
|
-
theme: {
|
|
94
|
-
colors: {
|
|
95
|
-
surface: '#fffdf8',
|
|
96
|
-
surfaceHover: '#f6f3ee',
|
|
97
|
-
},
|
|
98
|
-
slots: {
|
|
99
|
-
consentDialogCard: 'rounded-[32px] shadow-xl',
|
|
100
|
-
consentDialogHeader: 'gap-3',
|
|
101
|
-
consentWidgetFooter: 'gap-3 pt-6',
|
|
102
|
-
consentDialogTag: 'shadow-none',
|
|
103
|
-
},
|
|
104
|
-
},
|
|
105
|
-
}}
|
|
106
|
-
>
|
|
107
|
-
<ConsentDialog />
|
|
108
|
-
</ConsentManagerProvider>
|
|
109
|
-
```
|
|
79
|
+
`ConsentDialogLink` does the same with the policy's rights exposed for
|
|
80
|
+
styling; see [ConsentDialogLink](./consent-dialog-link.md). For a floating
|
|
81
|
+
button, see [ConsentDialogTrigger](./consent-dialog-trigger.md). Under an IAB
|
|
82
|
+
policy, mount `IABConsentDialog` from the [IAB guide](../iab/overview.md)
|
|
83
|
+
instead; this dialog stays closed for the `iab` model.
|
|
110
84
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
## Advanced: Compound Components
|
|
85
|
+
## Props
|
|
114
86
|
|
|
115
|
-
|
|
87
|
+
| Prop | Type | Default | Description |
|
|
88
|
+
| ------------------------- | ------------------------------------- | ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
89
|
+
| `open` | `boolean` | follows the active surface | Controls the open state. When set, Escape and the dialog's own Save, Accept all and Reject all buttons no longer close it; change the prop instead. A missing policy or an unlisted model still keeps it closed. |
|
|
90
|
+
| `showTrigger` | `boolean \|ConsentDialogTriggerProps` | `false` | Renders a floating `ConsentDialogTrigger` next to the dialog. Pass an object to configure that trigger. |
|
|
91
|
+
| `models` | `Model[]` | `['opt-in', 'opt-out', 'none']` | Policy models the dialog responds to. Under a model that is not listed, such as `iab`, it stays closed. |
|
|
92
|
+
| `legalLinks` | `(keyof LegalLinks)[] \|null` | none | Which of the links configured in the provider `options.legalLinks` render after the description. Omitting the prop renders none. `null` hides them. |
|
|
93
|
+
| `hideBranding` | `boolean` | `false` | Hides the "Secured by" tag in the card. |
|
|
94
|
+
| `uiSource` | `string` | `'dialog'` | Source identifier recorded with saves made from this dialog. |
|
|
95
|
+
| `scrollLock`, `trapFocus` | `boolean` | from `blocking` | Deprecated. Either one set to `false` makes the dialog non-blocking, unless the provider sets `presentation.preferences.blocking` explicitly, which wins. Prefer the provider option. |
|
|
96
|
+
| `disableAnimation` | `boolean` | `false` | Skips the enter and exit animation of the backdrop and the card. |
|
|
97
|
+
| `noStyle` | `boolean` | `false` | Removes the built-in styling from every part. |
|
|
98
|
+
|
|
99
|
+
## Behavior
|
|
100
|
+
|
|
101
|
+
The dialog is a modal wrapper around the preference center. Its card has a
|
|
102
|
+
header with the title `consentManagerDialog.title` and the description
|
|
103
|
+
`consentManagerDialog.description` followed by the legal links, then the
|
|
104
|
+
same category accordion and Reject all, Accept all and Save actions that
|
|
105
|
+
`ConsentWidget` renders, then the branding tag. It mounts through a portal
|
|
106
|
+
into `document.body` after hydration, so it is never part of the server
|
|
107
|
+
HTML.
|
|
108
|
+
|
|
109
|
+
Without an `open` prop, the dialog follows the active surface and opens while
|
|
110
|
+
it is `dialog`. These set that surface:
|
|
111
|
+
|
|
112
|
+
* The Customize button on a `ConsentBanner`, and the "Manage preferences"
|
|
113
|
+
or "Do not sell or share my data" button a notice renders.
|
|
114
|
+
* `ConsentDialogLink` and `ConsentDialogTrigger`.
|
|
115
|
+
* The button in a `Frame` placeholder.
|
|
116
|
+
* `useSetActiveUI()('dialog')` in your own component, or `openDialog()`
|
|
117
|
+
from `useHeadlessConsentUI()` on the headless subpath.
|
|
118
|
+
|
|
119
|
+
The component code is split into its own chunk. It downloads when the
|
|
120
|
+
dialog first opens or when a visitor hovers or focuses a Customize button,
|
|
121
|
+
and renders nothing until that chunk is ready. Passing `open={true}` or
|
|
122
|
+
`showTrigger` loads it on mount.
|
|
123
|
+
|
|
124
|
+
Without an `open` prop, Escape closes the dialog. Save, Accept all and
|
|
125
|
+
Reject all close it after the save succeeds; a save that fails keeps it
|
|
126
|
+
open. With `open={true}`, these actions leave the dialog visible; the
|
|
127
|
+
parent must set `open={false}` to close it. Clicking the backdrop does not
|
|
128
|
+
close it. Closing discards toggles that were not saved: the next open starts
|
|
129
|
+
from the recorded choice again. After a save from an uncontrolled dialog,
|
|
130
|
+
every consent surface hides unless the policy still owes a prompt, in which
|
|
131
|
+
case the banner returns.
|
|
132
|
+
|
|
133
|
+
The preference center is blocking by default: a backdrop, body scroll lock
|
|
134
|
+
and focus trap, all as one value. Set `presentation.preferences.blocking`
|
|
135
|
+
to `false` in the provider options to remove all three; the deprecated
|
|
136
|
+
`scrollLock` and `trapFocus` props do the same for one dialog. `variant`
|
|
137
|
+
and `position` are prompt options. Setting them under
|
|
138
|
+
`presentation.preferences` logs an `invalid-variant` diagnostic in
|
|
139
|
+
development and changes nothing; the dialog is always centered.
|
|
140
|
+
|
|
141
|
+
The dialog never opens without a resolved policy rule, even when the
|
|
142
|
+
active surface is already `dialog`; it appears as soon as a rule resolves,
|
|
143
|
+
without a remount. A rule with `model: 'none'` and no rights owes no consent
|
|
144
|
+
UI, so the dialog stays closed under it. When such a rule lists any right,
|
|
145
|
+
for example `rights: ['disclosure']` or `rights: ['preferences']`, the dialog
|
|
146
|
+
can open as a settings route and Save completes without writing a consent
|
|
147
|
+
record.
|
|
148
|
+
|
|
149
|
+
Copy comes from these translation keys: `consentManagerDialog.title`,
|
|
150
|
+
`consentManagerDialog.description`, `common.acceptAll`, `common.rejectAll`,
|
|
151
|
+
`common.save`, and `consentTypes.<category>.title` and `.description` for
|
|
152
|
+
each row.
|
|
153
|
+
|
|
154
|
+
## Accessibility
|
|
155
|
+
|
|
156
|
+
The panel carries `role="dialog"`, `aria-labelledby="consent-dialog-title"`
|
|
157
|
+
and `aria-describedby="consent-dialog-description"`, plus `aria-modal="true"`
|
|
158
|
+
while it is blocking. Its `dir` attribute follows the active language.
|
|
159
|
+
|
|
160
|
+
While blocking, focus moves on open to the panel itself rather than to a
|
|
161
|
+
button, so a screen reader announces the title and description first; Tab
|
|
162
|
+
then enters the legal links and category switches, Tab and Shift+Tab wrap
|
|
163
|
+
inside the panel, and on close focus returns to the element that opened the
|
|
164
|
+
dialog. A non-blocking dialog manages no focus: nothing moves focus into the
|
|
165
|
+
panel or back to the opener. The backdrop is `aria-hidden` and is not
|
|
166
|
+
focusable.
|
|
167
|
+
|
|
168
|
+
Each category switch has the category title as its accessible name. The
|
|
169
|
+
`necessary` switch is disabled and always on. A saved grant that the current
|
|
170
|
+
policy or a privacy signal overrides gets a note under its row, linked to
|
|
171
|
+
the switch through `aria-describedby`.
|
|
172
|
+
|
|
173
|
+
## Composition
|
|
174
|
+
|
|
175
|
+
Every part is available as `ConsentDialog.<Part>`: `Root`, `Overlay`,
|
|
176
|
+
`Card`, `Header`, `HeaderTitle`, `HeaderDescription`, `Content`, `Footer`
|
|
177
|
+
and `ConsentCustomizationCard`, the stock card. `Root` provides the portal,
|
|
178
|
+
open state, focus trap, scroll lock and backdrop, and accepts `open`,
|
|
179
|
+
`models`, `noStyle`, `disableAnimation`, `scrollLock`, `trapFocus`,
|
|
180
|
+
`uiSource` and `overlay`. Pass `overlay={false}` to render no backdrop, or a
|
|
181
|
+
node to replace the built-in one.
|
|
116
182
|
|
|
117
183
|
```tsx
|
|
118
184
|
<ConsentDialog.Root>
|
|
119
|
-
<ConsentDialog.Overlay />
|
|
120
185
|
<ConsentDialog.Card>
|
|
121
186
|
<ConsentDialog.Header>
|
|
122
|
-
<ConsentDialog.HeaderTitle
|
|
123
|
-
<ConsentDialog.HeaderDescription />
|
|
187
|
+
<ConsentDialog.HeaderTitle>Your privacy choices</ConsentDialog.HeaderTitle>
|
|
188
|
+
<ConsentDialog.HeaderDescription legalLinks={['privacyPolicy']} />
|
|
124
189
|
</ConsentDialog.Header>
|
|
125
190
|
<ConsentDialog.Content>
|
|
126
|
-
<ConsentWidget
|
|
127
|
-
<ConsentWidget.Accordion type="single">
|
|
128
|
-
<ConsentWidget.AccordionItems />
|
|
129
|
-
</ConsentWidget.Accordion>
|
|
130
|
-
<ConsentWidget.PolicyActions />
|
|
131
|
-
</ConsentWidget.Root>
|
|
191
|
+
<ConsentWidget />
|
|
132
192
|
</ConsentDialog.Content>
|
|
133
|
-
<ConsentDialog.Footer />
|
|
193
|
+
<ConsentDialog.Footer hideBranding />
|
|
134
194
|
</ConsentDialog.Card>
|
|
135
195
|
</ConsentDialog.Root>
|
|
136
196
|
```
|
|
137
197
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|:--|:--|
|
|
166
|
-
|Type Name|\`ConsentDialogProps\`|
|
|
167
|
-
|Source Path|\`./packages/react/src/components/consent-dialog/consent-dialog.tsx\`|
|
|
168
|
-
|
|
169
|
-
\*ExtractedTypeTable: Could not extract "ConsentDialogProps" from "./packages/react/src/components/consent-dialog/consent-dialog.tsx" using base path "/home/runner/work/c15t/c15t". Verify the path/name and that the file is included by your tsconfig.\*
|
|
198
|
+
Keep `ConsentWidget` inside `Content`: it owns the draft, the switches and
|
|
199
|
+
the policy actions, and inherits the dialog's `uiSource`. `Footer` renders
|
|
200
|
+
the branding tag unless you pass children or `hideBranding`.
|
|
201
|
+
|
|
202
|
+
The positioner carries `data-slot="dialog-positioner"`, and both it and the
|
|
203
|
+
panel carry `data-blocking="true"` while blocking. Provider component slots
|
|
204
|
+
for the stock structure are `dialog.root`, `dialog.container`,
|
|
205
|
+
`dialog.card`, `dialog.header`, `dialog.title`, `dialog.content`,
|
|
206
|
+
`dialog.overlay`, `description.dialog`, `manager.footer` and `tag.dialog`.
|
|
207
|
+
|
|
208
|
+
The compound parts import from `c15t/next` as properties of `ConsentDialog`,
|
|
209
|
+
and `ConsentWidget` from the same module. Server Components cannot render
|
|
210
|
+
them: keep the composition in a file with `'use client'`. See
|
|
211
|
+
[Styling](../styling/overview.md) for slots and tokens.
|
|
212
|
+
|
|
213
|
+
## Verify
|
|
214
|
+
|
|
215
|
+
Use the default blocking, uncontrolled dialog and an optional in-scope
|
|
216
|
+
category that is not restricted by policy or privacy signals such as GPC.
|
|
217
|
+
Open the dialog from the banner's Customize button or a preferences link.
|
|
218
|
+
A centered card appears over a dimmed backdrop, the page behind it stops
|
|
219
|
+
scrolling, and Tab stays inside the card. Press Escape: the card closes and
|
|
220
|
+
focus returns to the button you used. Open it again, turn a category on and
|
|
221
|
+
choose Save. The dialog closes and `useConsent('<category>')` reports
|
|
222
|
+
`true` in your components; under a choice prompt the banner does not return,
|
|
223
|
+
while a `notice` prompt keeps its banner until it is acknowledged. Reload the
|
|
224
|
+
page and reopen the dialog: the switch reflects the saved choice.
|