@c15t/nextjs 2.0.0-rc.0 → 2.0.0-rc.10

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.
Files changed (98) hide show
  1. package/README.md +10 -3
  2. package/client/components/consent-dialog-link.js +3 -0
  3. package/dist/headless.cjs +1 -1
  4. package/dist/iab/styles.css +12 -0
  5. package/dist/iab/styles.tw3.css +14 -0
  6. package/dist/index.cjs +1 -1
  7. package/dist/index.js +1 -1
  8. package/dist/libs/browser-initial-data.cjs +1 -0
  9. package/dist/libs/browser-initial-data.js +1 -0
  10. package/dist/libs/initial-data.cjs +1 -1
  11. package/dist/libs/initial-data.js +1 -1
  12. package/dist/styles.css +10 -0
  13. package/dist/styles.tw3.css +13 -0
  14. package/dist/types.cjs +1 -1
  15. package/dist/version.cjs +1 -1
  16. package/dist/version.js +1 -1
  17. package/{dist → dist-types}/headless.d.ts +0 -1
  18. package/{dist → dist-types}/index.d.ts +3 -2
  19. package/dist-types/libs/browser-initial-data.d.ts +9 -0
  20. package/{dist → dist-types}/libs/initial-data.d.ts +7 -2
  21. package/dist-types/types.d.ts +38 -0
  22. package/dist-types/version.d.ts +1 -0
  23. package/docs/README.md +73 -0
  24. package/docs/building-headless-components.md +377 -0
  25. package/docs/callbacks.md +184 -0
  26. package/docs/components/consent-banner.md +269 -0
  27. package/docs/components/consent-dialog-link.md +59 -0
  28. package/docs/components/consent-dialog-trigger.md +103 -0
  29. package/docs/components/consent-dialog.md +177 -0
  30. package/docs/components/consent-manager-provider.md +425 -0
  31. package/docs/components/consent-widget.md +133 -0
  32. package/docs/components/dev-tools.md +63 -0
  33. package/docs/components/frame.md +73 -0
  34. package/docs/concepts/client-modes.md +175 -0
  35. package/docs/concepts/consent-categories.md +97 -0
  36. package/docs/concepts/consent-models.md +116 -0
  37. package/docs/concepts/cookie-management.md +122 -0
  38. package/docs/concepts/glossary.md +23 -0
  39. package/docs/concepts/initialization-flow.md +148 -0
  40. package/docs/concepts/policy-packs.md +229 -0
  41. package/docs/headless.md +190 -0
  42. package/docs/hooks/use-color-scheme.md +40 -0
  43. package/docs/hooks/use-consent-manager/checking-consent.md +94 -0
  44. package/docs/hooks/use-consent-manager/location-info.md +95 -0
  45. package/docs/hooks/use-consent-manager/overview.md +420 -0
  46. package/docs/hooks/use-consent-manager/setting-consent.md +92 -0
  47. package/docs/hooks/use-draggable.md +57 -0
  48. package/docs/hooks/use-focus-trap.md +41 -0
  49. package/docs/hooks/use-reduced-motion.md +35 -0
  50. package/docs/hooks/use-ssr-status.md +31 -0
  51. package/docs/hooks/use-text-direction.md +49 -0
  52. package/docs/hooks/use-translations.md +118 -0
  53. package/docs/iab/consent-banner.md +94 -0
  54. package/docs/iab/consent-dialog.md +134 -0
  55. package/docs/iab/overview.md +126 -0
  56. package/docs/iab/use-gvl-data.md +20 -0
  57. package/docs/iframe-blocking.md +107 -0
  58. package/docs/integrations/building-integrations.md +405 -0
  59. package/docs/integrations/databuddy.md +203 -0
  60. package/docs/integrations/google-tag-manager.md +153 -0
  61. package/docs/integrations/google-tag.md +122 -0
  62. package/docs/integrations/linkedin-insights.md +109 -0
  63. package/docs/integrations/meta-pixel.md +342 -0
  64. package/docs/integrations/microsoft-uet.md +112 -0
  65. package/docs/integrations/overview.md +105 -0
  66. package/docs/integrations/posthog.md +199 -0
  67. package/docs/integrations/tiktok-pixel.md +113 -0
  68. package/docs/integrations/x-pixel.md +143 -0
  69. package/docs/internationalization.md +197 -0
  70. package/docs/network-blocker.md +178 -0
  71. package/docs/optimization.md +234 -0
  72. package/docs/policy-packs.md +246 -0
  73. package/docs/quickstart.md +161 -0
  74. package/docs/script-loader.md +321 -0
  75. package/docs/server-side.md +176 -0
  76. package/docs/styling/classnames.md +92 -0
  77. package/docs/styling/color-scheme.md +82 -0
  78. package/docs/styling/css-variables.md +92 -0
  79. package/docs/styling/overview.md +456 -0
  80. package/docs/styling/slots.md +127 -0
  81. package/docs/styling/tailwind.md +113 -0
  82. package/docs/styling/tokens.md +216 -0
  83. package/docs/troubleshooting.md +146 -0
  84. package/iab/styles.css +1 -0
  85. package/package.json +38 -17
  86. package/readme.json +4 -0
  87. package/src/iab/styles.css +12 -0
  88. package/src/iab/styles.tw3.css +14 -0
  89. package/src/styles.css +10 -0
  90. package/src/styles.tw3.css +13 -0
  91. package/styles.css +1 -0
  92. package/dist/headless.d.ts.map +0 -1
  93. package/dist/index.d.ts.map +0 -1
  94. package/dist/libs/initial-data.d.ts.map +0 -1
  95. package/dist/types.d.ts +0 -16
  96. package/dist/types.d.ts.map +0 -1
  97. package/dist/version.d.ts +0 -2
  98. package/dist/version.d.ts.map +0 -1
@@ -0,0 +1,269 @@
1
+ ---
2
+ title: ConsentBanner
3
+ description: A pre-built consent banner that appears when user consent is needed. Supports policy-aware layout, theming, and advanced composition when markup must change.
4
+ ---
5
+ `ConsentBanner` is a ready-to-use consent banner that appears automatically in **opt-in jurisdictions** (like GDPR) where explicit consent is required before tracking. In opt-out jurisdictions (like CCPA), the banner won't appear — users get an opt-out mechanism instead. It includes reject, accept, and customize buttons with configurable layout.
6
+
7
+ ## Basic Usage
8
+
9
+ ```tsx
10
+ import { ConsentManagerProvider, ConsentBanner } from '@c15t/nextjs';
11
+
12
+ export function ConsentManager() {
13
+ return (
14
+ <ConsentManagerProvider options={{ mode: 'hosted', backendURL: '/api/c15t' }}>
15
+ <ConsentBanner />
16
+ </ConsentManagerProvider>
17
+ );
18
+ }
19
+ ```
20
+
21
+ ## Button Layout
22
+
23
+ The `layout` prop controls button arrangement. Each item is either a button ID or an array of button IDs (which groups them together):
24
+
25
+ ```tsx
26
+ {/* Default: reject and accept grouped, customize separate */}
27
+ <ConsentBanner layout={[['reject', 'accept'], 'customize']} />
28
+
29
+ {/* All buttons in one group */}
30
+ <ConsentBanner layout={[['reject', 'customize', 'accept']]} />
31
+
32
+ {/* Accept first, then reject and customize grouped */}
33
+ <ConsentBanner layout={['accept', ['reject', 'customize']]} />
34
+ ```
35
+
36
+ To stack groups vertically, pair the same grouped layout with `direction="column"`:
37
+
38
+ ```tsx
39
+ <ConsentBanner
40
+ layout={['customize', ['reject', 'accept']]}
41
+ direction="column"
42
+ />
43
+ ```
44
+
45
+ ## Policy-Driven UI Profile
46
+
47
+ When using backend runtime policies, `policy.ui.uiProfile` can control banner action presentation:
48
+
49
+ * `compact` — default desktop sizing
50
+ * `balanced` — auto-fills compact and grouped layouts with moderate emphasis
51
+ * `strict` — always fills action controls for explicit, high-clarity layouts
52
+
53
+ ## Theme-Level Button Styling
54
+
55
+ Use the provider `theme` prop to control how stock consent actions look:
56
+
57
+ ```tsx
58
+ <ConsentManagerProvider
59
+ options={{
60
+ theme: {
61
+ consentActions: {
62
+ default: { mode: 'stroke' },
63
+ accept: { variant: 'primary', mode: 'stroke' },
64
+ customize: { variant: 'neutral', mode: 'ghost' },
65
+ },
66
+ },
67
+ }}
68
+ >
69
+ <ConsentBanner />
70
+ </ConsentManagerProvider>
71
+ ```
72
+
73
+ Policy packs control grouping, ordering, and direction. The theme controls button appearance.
74
+
75
+ ## Styling First
76
+
77
+ > ℹ️ **Info:**
78
+ > For pure theming, stay inside the pre-built banner. Start with layout props, theme.consentActions, design tokens, and theme.slots before reaching for compound components. See Styling Overview.
79
+
80
+ The stock banner maps common visual changes to the theme system:
81
+
82
+ * Card background -> `theme.colors.surface`
83
+ * Footer background -> `theme.colors.surfaceHover`
84
+ * Card, footer, and title tweaks -> `theme.slots.consentBannerCard`, `consentBannerFooter`, and `consentBannerTitle`
85
+
86
+ ```tsx
87
+ <ConsentManagerProvider
88
+ options={{
89
+ theme: {
90
+ colors: {
91
+ surface: '#fffdf8',
92
+ surfaceHover: '#f6f3ee',
93
+ },
94
+ slots: {
95
+ consentBannerCard: 'rounded-[28px] shadow-xl',
96
+ consentBannerFooter: 'border-t border-black/10 px-6',
97
+ consentBannerTitle: 'tracking-tight',
98
+ },
99
+ },
100
+ }}
101
+ >
102
+ <ConsentBanner />
103
+ </ConsentManagerProvider>
104
+ ```
105
+
106
+ ### Primary Button
107
+
108
+ Highlight specific button(s) as the primary action:
109
+
110
+ ```tsx
111
+ {/* Single primary */}
112
+ <ConsentBanner primaryButton="accept" />
113
+
114
+ {/* Multiple primaries */}
115
+ <ConsentBanner primaryButton={['accept', 'customize']} />
116
+ ```
117
+
118
+ ## Legal Links
119
+
120
+ Control which legal links appear in the banner description:
121
+
122
+ ```tsx
123
+ {/* Show all configured links (default) */}
124
+ <ConsentBanner legalLinks={undefined} />
125
+
126
+ {/* Show no links */}
127
+ <ConsentBanner legalLinks={null} />
128
+
129
+ {/* Show specific links */}
130
+ <ConsentBanner legalLinks={['privacyPolicy', 'cookiePolicy']} />
131
+ ```
132
+
133
+ > ℹ️ **Info:**
134
+ > Legal link URLs are configured in the ConsentManagerProvider options via the legalLinks prop, not on the banner itself.
135
+
136
+ ## Customizing Copy
137
+
138
+ Prefer provider `i18n` when you want to rename the stock banner content:
139
+
140
+ ```tsx
141
+ <ConsentManagerProvider
142
+ options={{
143
+ i18n: {
144
+ locale: 'en',
145
+ messages: {
146
+ en: {
147
+ cookieBanner: {
148
+ title: 'We value your privacy',
149
+ description: 'We use cookies to improve the site and measure performance.',
150
+ },
151
+ common: {
152
+ acceptAll: 'Accept all',
153
+ rejectAll: 'Reject all',
154
+ customize: 'Manage preferences',
155
+ },
156
+ },
157
+ },
158
+ },
159
+ }}
160
+ >
161
+ <ConsentBanner />
162
+ </ConsentManagerProvider>
163
+ ```
164
+
165
+ Direct text props such as `title`, `description`, and `acceptButtonText` are still supported for one-off overrides, but `i18n` is the preferred path for copy changes.
166
+
167
+ ## Advanced: Compound Components
168
+
169
+ Use compound components only when the stock banner structure is no longer enough and you need to rearrange existing c15t primitives while keeping policy-driven action grouping and emphasis:
170
+
171
+ ```tsx
172
+ <ConsentBanner.Root>
173
+ <ConsentBanner.Overlay />
174
+ <ConsentBanner.Card>
175
+ <ConsentBanner.Header>
176
+ <ConsentBanner.Title />
177
+ <ConsentBanner.Description />
178
+ </ConsentBanner.Header>
179
+ <ConsentBanner.PolicyActions />
180
+ </ConsentBanner.Card>
181
+ </ConsentBanner.Root>
182
+ ```
183
+
184
+ * `ConsentBanner.Root` — Outermost container, provides theme context
185
+ * `ConsentBanner.Card` — Main content card with optional focus trapping
186
+ * `ConsentBanner.Header` — Contains title and description
187
+ * `ConsentBanner.Title` — Heading, defaults to translation `consentBanner.title`
188
+ * `ConsentBanner.Description` — Description text, supports `legalLinks` prop
189
+ * `ConsentBanner.PolicyActions` — Renders policy-aware grouped actions inside the banner footer
190
+ * `ConsentBanner.Footer` — Action buttons container
191
+ * `ConsentBanner.FooterSubGroup` — Groups related buttons together
192
+ * `ConsentBanner.RejectButton` — Rejects all consent
193
+ * `ConsentBanner.CustomizeButton` — Opens the consent dialog
194
+ * `ConsentBanner.AcceptButton` — Accepts all consent
195
+ * `ConsentBanner.Overlay` — Optional backdrop overlay
196
+
197
+ For a fixed layout that intentionally ignores policy grouping, render the footer manually:
198
+
199
+ ```tsx
200
+ <ConsentBanner.Root>
201
+ <ConsentBanner.Card>
202
+ <ConsentBanner.Header>
203
+ <ConsentBanner.Title />
204
+ <ConsentBanner.Description />
205
+ </ConsentBanner.Header>
206
+ <ConsentBanner.Footer>
207
+ <ConsentBanner.FooterSubGroup>
208
+ <ConsentBanner.RejectButton />
209
+ <ConsentBanner.AcceptButton />
210
+ </ConsentBanner.FooterSubGroup>
211
+ <ConsentBanner.CustomizeButton />
212
+ </ConsentBanner.Footer>
213
+ </ConsentBanner.Card>
214
+ </ConsentBanner.Root>
215
+ ```
216
+
217
+ ## Using `renderAction` with c15t Defaults
218
+
219
+ `ConsentBanner.PolicyActions` renders stock c15t buttons and translations by default.
220
+
221
+ ```tsx
222
+ <ConsentBanner.PolicyActions />
223
+ ```
224
+
225
+ `renderAction` is optional. When you want custom mapping but still want the built-in c15t button behavior and copy, return the stock button compounds:
226
+
227
+ ```tsx
228
+ <ConsentBanner.PolicyActions
229
+ renderAction={(action, props) => {
230
+ const { key, ...buttonProps } = props
231
+
232
+ switch (action) {
233
+ case 'accept':
234
+ return <ConsentBanner.AcceptButton key={key} {...buttonProps} />
235
+ case 'reject':
236
+ return <ConsentBanner.RejectButton key={key} {...buttonProps} />
237
+ case 'customize':
238
+ return <ConsentBanner.CustomizeButton key={key} {...buttonProps} />
239
+ }
240
+ }}
241
+ />
242
+ ```
243
+
244
+ `renderAction` is still meant for stock button compounds. If you want completely custom button elements and click handling, use `useHeadlessConsentUI()` and render `banner.actionGroups` manually instead of `ConsentBanner.PolicyActions`.
245
+
246
+ If you only need styling changes, stay with tokens and slots instead of rebuilding the banner layout.
247
+
248
+ ## Props
249
+
250
+ ### ConsentBannerProps
251
+
252
+ |Property|Type|Description|Default|Required|
253
+ |:--|:--|:--|:--|:--:|
254
+ |noStyle|boolean \|undefined|When true, removes all default styling from the component|false|Optional|
255
+ |title|ReactNode|Content to display as the banner's title|undefined|Optional|
256
+ |description|ReactNode|Content to display as the banner's description|undefined|Optional|
257
+ |rejectButtonText|ReactNode|Content to display on the reject button|undefined|Optional|
258
+ |customizeButtonText|ReactNode|Content to display on the customize button|undefined|Optional|
259
+ |acceptButtonText|ReactNode|Content to display on the accept button|undefined|Optional|
260
+ |scrollLock|boolean \|undefined|When true, the consent banner will lock the scroll of the page|false|Optional|
261
+ |trapFocus|boolean \|undefined|When true, the consent banner will trap focus|true|Optional|
262
+ |disableAnimation|boolean \|undefined|When true, disables the entrance/exit animations|false|Optional|
263
+ |legalLinks|(keyof LegalLinksTranslations)\[] \|null \|undefined|Controls which legal links to display. Options: \`undefined\` (default): Shows all available legal links; \`null\`: Explicitly hides all legal links; Array of keys: Shows only the specified legal links|-|Optional|
264
+ |hideBranding|boolean \|undefined|When true, hides the branding tag on the banner.|false|Optional|
265
+ |layout|ConsentBannerLayout \|undefined|Defines the layout of buttons in the footer. Allows reordering and grouping of buttons.|-|Optional|
266
+ |direction|PolicyUiActionDirection \|undefined|Defines how footer button groups flow.|-|Optional|
267
+ |primaryButton|ConsentBannerButton \|undefined|Specifies which button(s) should be highlighted as the primary action.|-|Optional|
268
+ |models|Model \|undefined|Which consent models this banner responds to.|\['opt-in']|Optional|
269
+ |uiSource|string \|undefined|Override the UI source identifier sent with consent API calls.|'banner'|Optional|
@@ -0,0 +1,59 @@
1
+ ---
2
+ title: ConsentDialogLink
3
+ description: An inline trigger for opening the consent dialog from footers, legal pages, and account settings.
4
+ ---
5
+ `ConsentDialogLink` is an inline trigger for opening the consent dialog from places like site footers, legal pages, or account settings. It is unstyled by default, so it inherits your app's typography and link/button styles.
6
+
7
+ ## Basic Usage
8
+
9
+ ```tsx
10
+ import { ConsentDialogLink } from '@c15t/nextjs/components/consent-dialog-link';
11
+
12
+ export function SiteFooter() {
13
+ return (
14
+ <footer>
15
+ <ConsentDialogLink>
16
+ Your privacy settings
17
+ </ConsentDialogLink>
18
+ </footer>
19
+ );
20
+ }
21
+ ```
22
+
23
+ ## Footer Link (unstyled by default)
24
+
25
+ ```tsx
26
+ <footer>
27
+ <ConsentDialogLink>
28
+ Your privacy settings
29
+ </ConsentDialogLink>
30
+ </footer>
31
+ ```
32
+
33
+ ## Render as an Anchor
34
+
35
+ Use `asChild` to keep semantic anchor markup while still opening the dialog:
36
+
37
+ ```tsx
38
+ <ConsentDialogLink asChild>
39
+ <a href="#privacy-settings">Manage Preferences</a>
40
+ </ConsentDialogLink>
41
+ ```
42
+
43
+ ## Optional Styling Control
44
+
45
+ The component defaults to `noStyle={true}`. Set it to `false` if you want c15t button styles:
46
+
47
+ ```tsx
48
+ <ConsentDialogLink noStyle={false}>
49
+ Privacy Settings
50
+ </ConsentDialogLink>
51
+ ```
52
+
53
+ ## Props
54
+
55
+ ### ConsentDialogLinkProps
56
+
57
+ |Property|Type|Description|Default|Required|
58
+ |:--|:--|:--|:--|:--:|
59
+ |children|ReactNode|Custom trigger content, for example "Your privacy settings" or "Manage preferences".|-|✅ Required|
@@ -0,0 +1,103 @@
1
+ ---
2
+ title: ConsentDialogTrigger
3
+ description: A floating, draggable button that lets users re-open the consent dialog at any time.
4
+ ---
5
+ `ConsentDialogTrigger` is a floating button that opens the consent dialog when clicked. Users can drag it to any corner of the screen, and the position persists across sessions. Use it to give users a persistent way to manage their privacy settings.
6
+
7
+ ## Basic Usage
8
+
9
+ Use standalone or via the `showTrigger` prop on `ConsentDialog`:
10
+
11
+ ```tsx
12
+ import { ConsentDialogTrigger } from '@c15t/nextjs';
13
+
14
+ // Standalone
15
+ <ConsentDialogTrigger />
16
+
17
+ // Via ConsentDialog
18
+ <ConsentDialog showTrigger />
19
+ ```
20
+
21
+ For inline footer links (instead of a floating button), use [`ConsentDialogLink`](/docs/frameworks/next/components/consent-dialog-link).
22
+
23
+ ## Icon Options
24
+
25
+ ```tsx
26
+ {/* Built-in icons */}
27
+ <ConsentDialogTrigger icon="branding" /> {/* c15t logo (default) */}
28
+ <ConsentDialogTrigger icon="fingerprint" /> {/* Privacy icon */}
29
+ <ConsentDialogTrigger icon="settings" /> {/* Gear icon */}
30
+
31
+ {/* Custom icon */}
32
+ <ConsentDialogTrigger icon={<MyCustomIcon />} />
33
+ ```
34
+
35
+ ## Visibility
36
+
37
+ Control when the trigger is visible:
38
+
39
+ ```tsx
40
+ {/* Always visible (default) */}
41
+ <ConsentDialogTrigger showWhen="always" />
42
+
43
+ {/* Only after user has made a consent choice */}
44
+ <ConsentDialogTrigger showWhen="after-consent" />
45
+
46
+ {/* Hidden (control visibility programmatically) */}
47
+ <ConsentDialogTrigger showWhen="never" />
48
+ ```
49
+
50
+ ## Position
51
+
52
+ Set the default corner and control persistence:
53
+
54
+ ```tsx
55
+ <ConsentDialogTrigger
56
+ defaultPosition="bottom-left"
57
+ persistPosition={true} // Remembers user's drag position
58
+ onPositionChange={(position) => console.log('Moved to:', position)}
59
+ />
60
+ ```
61
+
62
+ ## Size
63
+
64
+ ```tsx
65
+ <ConsentDialogTrigger size="sm" /> {/* Small */}
66
+ <ConsentDialogTrigger size="md" /> {/* Medium (default) */}
67
+ <ConsentDialogTrigger size="lg" /> {/* Large */}
68
+ ```
69
+
70
+ ## Compound Components
71
+
72
+ Build fully custom trigger layouts using sub-components:
73
+
74
+ ```tsx
75
+ <ConsentDialogTrigger.Root defaultPosition="bottom-right">
76
+ <ConsentDialogTrigger.Button size="md">
77
+ <ConsentDialogTrigger.Icon icon="settings" />
78
+ <ConsentDialogTrigger.Text>Privacy</ConsentDialogTrigger.Text>
79
+ </ConsentDialogTrigger.Button>
80
+ </ConsentDialogTrigger.Root>
81
+ ```
82
+
83
+ * `ConsentDialogTrigger.Root` — Portal wrapper with drag handling and position persistence
84
+ * `ConsentDialogTrigger.Button` — Draggable button element with size variants
85
+ * `ConsentDialogTrigger.Icon` — Icon display (branding, fingerprint, settings, or custom)
86
+ * `ConsentDialogTrigger.Text` — Optional text label
87
+
88
+ ## Props
89
+
90
+ ### ConsentDialogTriggerProps
91
+
92
+ |Property|Type|Description|Default|Required|
93
+ |:--|:--|:--|:--|:--:|
94
+ |icon|TriggerIcon|Icon to display in the trigger button.|'branding'|Optional|
95
+ |defaultPosition|CornerPosition \|undefined|Default corner position for the trigger. User can drag to any corner and the position will be remembered.|'bottom-right'|Optional|
96
+ |persistPosition|boolean \|undefined|Whether to persist the user's position preference in localStorage.|true|Optional|
97
+ |ariaLabel|string \|undefined|Accessible label for the trigger button.|'Open privacy settings'|Optional|
98
+ |className|string \|undefined|Additional CSS class names.|-|Optional|
99
+ |noStyle|boolean \|undefined|When true, removes default styling.|false|Optional|
100
+ |showWhen|TriggerVisibility \|undefined|Controls when the trigger is visible.|'always'|Optional|
101
+ |size|TriggerSize \|undefined|Size of the trigger button.|'md'|Optional|
102
+ |onClick|(() => void) \|undefined|Callback fired when the trigger is clicked (before opening dialog).|-|Optional|
103
+ |onPositionChange|((position: CornerPosition) => void) \|undefined|Callback fired when the corner position changes.|-|Optional|
@@ -0,0 +1,177 @@
1
+ ---
2
+ title: ConsentDialog
3
+ description: A modal dialog where users can toggle individual consent categories.
4
+ ---
5
+ `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.
6
+
7
+ ## Basic Usage
8
+
9
+ ```tsx
10
+ import { ConsentManagerProvider, ConsentBanner, ConsentDialog } from '@c15t/nextjs';
11
+
12
+ export function ConsentManager() {
13
+ return (
14
+ <ConsentManagerProvider options={{ mode: 'hosted', backendURL: '/api/c15t' }}>
15
+ <ConsentBanner />
16
+ <ConsentDialog />
17
+ </ConsentManagerProvider>
18
+ );
19
+ }
20
+ ```
21
+
22
+ ## Controlled State
23
+
24
+ By default, the dialog follows `activeUI === 'dialog'` from the consent store. Use the `open` prop for manual control:
25
+
26
+ ```tsx
27
+ import { useState } from 'react';
28
+
29
+ function SettingsPage() {
30
+ const [open, setOpen] = useState(false);
31
+
32
+ return (
33
+ <>
34
+ <button onClick={() => setOpen(true)}>Privacy Settings</button>
35
+ <ConsentDialog open={open} />
36
+ </>
37
+ );
38
+ }
39
+ ```
40
+
41
+ Or use the hook to open it programmatically:
42
+
43
+ ```tsx
44
+ import { useConsentManager } from '@c15t/nextjs';
45
+
46
+ function PrivacyLink() {
47
+ const { setActiveUI } = useConsentManager();
48
+
49
+ return (
50
+ <button onClick={() => setActiveUI('dialog')}>
51
+ Manage cookies
52
+ </button>
53
+ );
54
+ }
55
+ ```
56
+
57
+ ## Floating Trigger
58
+
59
+ Add a floating button that lets users re-open the dialog after dismissing the banner:
60
+
61
+ ```tsx
62
+ {/* Default trigger */}
63
+ <ConsentDialog showTrigger />
64
+
65
+ {/* Custom trigger */}
66
+ <ConsentDialog
67
+ showTrigger={{
68
+ icon: 'settings',
69
+ defaultPosition: 'bottom-left',
70
+ showWhen: 'after-consent',
71
+ size: 'sm',
72
+ }}
73
+ />
74
+ ```
75
+
76
+ ## Branding
77
+
78
+ Hide the c15t branding tag:
79
+
80
+ ```tsx
81
+ <ConsentDialog hideBranding />
82
+ ```
83
+
84
+ ## Styling First
85
+
86
+ > ℹ️ **Info:**
87
+ > 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.
88
+
89
+ ```tsx
90
+ <ConsentManagerProvider
91
+ options={{
92
+ theme: {
93
+ colors: {
94
+ surface: '#fffdf8',
95
+ surfaceHover: '#f6f3ee',
96
+ },
97
+ slots: {
98
+ consentDialogCard: 'rounded-[32px] shadow-xl',
99
+ consentDialogHeader: 'gap-3',
100
+ consentWidgetFooter: 'gap-3 pt-6',
101
+ consentDialogTag: 'shadow-none',
102
+ },
103
+ },
104
+ }}
105
+ >
106
+ <ConsentDialog />
107
+ </ConsentManagerProvider>
108
+ ```
109
+
110
+ Dialog copy should be changed through `ConsentManagerProvider.options.i18n`, not by rebuilding the dialog structure.
111
+
112
+ ## Advanced: Compound Components
113
+
114
+ Use compound components only when you need custom dialog markup while still keeping c15t primitives and policy-aware footer actions:
115
+
116
+ ```tsx
117
+ <ConsentDialog.Root>
118
+ <ConsentDialog.Overlay />
119
+ <ConsentDialog.Card>
120
+ <ConsentDialog.Header>
121
+ <ConsentDialog.HeaderTitle />
122
+ <ConsentDialog.HeaderDescription />
123
+ </ConsentDialog.Header>
124
+ <ConsentDialog.Content>
125
+ <ConsentWidget.Root>
126
+ <ConsentWidget.Accordion type="single">
127
+ <ConsentWidget.AccordionItems />
128
+ </ConsentWidget.Accordion>
129
+ <ConsentWidget.PolicyActions />
130
+ </ConsentWidget.Root>
131
+ </ConsentDialog.Content>
132
+ <ConsentDialog.Footer />
133
+ </ConsentDialog.Card>
134
+ </ConsentDialog.Root>
135
+ ```
136
+
137
+ * `ConsentDialog.Root` — Portal container with focus trap, scroll lock, and animation
138
+ * `ConsentDialog.Card` — Main dialog card
139
+ * `ConsentDialog.Header` — Contains title and description
140
+ * `ConsentDialog.HeaderTitle` — Dialog title
141
+ * `ConsentDialog.HeaderDescription` — Description with optional `legalLinks`
142
+ * `ConsentDialog.Content` — Main content area (typically contains `ConsentWidget`)
143
+ * `ConsentDialog.Footer` — Footer with optional branding (`hideBranding` prop)
144
+ * `ConsentDialog.Overlay` — Backdrop overlay
145
+ * `ConsentWidget.PolicyActions` — Renders policy-aware grouped dialog actions
146
+
147
+ For a quick pre-composed layout, use the shorthand card:
148
+
149
+ ```tsx
150
+ <ConsentDialog.Root>
151
+ <ConsentDialog.ConsentCustomizationCard />
152
+ </ConsentDialog.Root>
153
+ ```
154
+
155
+ `ConsentWidget.PolicyActions` uses stock c15t widget buttons and translations by default. Pass `renderAction` only when you need to customize the action mapping, and return stock widget button compounds if you want to preserve built-in behavior and copy.
156
+
157
+ For fully manual control over dialog action rendering, use `useHeadlessConsentUI()` and map `dialog.actionGroups` yourself.
158
+
159
+ If the stock dialog structure still works, prefer tokens, slots, and provider configuration instead.
160
+
161
+ ## Props
162
+
163
+ ### ConsentDialogProps
164
+
165
+ |Property|Type|Description|Default|Required|
166
+ |:--|:--|:--|:--|:--:|
167
+ |theme|undefined|Theme configuration override (deprecated)|-|Optional|
168
+ |disableAnimation|boolean \|undefined|Disables all animations when true|-|Optional|
169
+ |noStyle|boolean \|undefined|Removes default styles when true|-|Optional|
170
+ |scrollLock|boolean \|undefined|Locks the scroll when true|-|Optional|
171
+ |trapFocus|boolean \|undefined|Traps keyboard focus within a dialog when true|-|Optional|
172
+ |open|boolean \|undefined|Control the open state. If omitted the dialog follows \`useConsentManager().activeUI === 'dialog'\`.|-|Optional|
173
+ |legalLinks|(keyof LegalLinksTranslations)\[] \|null \|undefined|Controls which legal links to display. Options: \`undefined\` (default): Shows all available legal links; \`null\`: Explicitly hides all legal links; Array of keys: Shows only the specified legal links|-|Optional|
174
+ |hideBranding|boolean \|undefined|Controls whether to hide the branding in the dialog footer.|-|Optional|
175
+ |showTrigger|ConsentDialogTriggerProps \|undefined|Show a floating trigger button to resurface the consent dialog. Useful for allowing users to re-open the dialog after dismissing. Options: \`true\` - Show trigger with default settings; \`false\` - Hide trigger (default); \`ConsentDialogTriggerProps\` - Show trigger with custom props|false|Optional|
176
+ |models|Model \|undefined|Which consent models this dialog responds to.|\['opt-in', 'opt-out']|Optional|
177
+ |uiSource|string \|undefined|Override the UI source identifier sent with consent API calls.|'dialog'|Optional|