@c15t/react 3.0.0-alpha.9 → 3.0.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 +7 -9
- package/README.md +41 -70
- package/SKILL.md +1 -1
- package/dist/aggregate-components.js +1 -1
- package/dist/components/consent-gate/atoms.js +1 -1
- package/dist/components/consent-gate/frame.js +2 -0
- package/dist/components/consent-gate/index.js +1 -1
- package/dist/components/iab-panel/atoms/root.js +1 -1
- package/dist/components/iab-panel/iab-panel.js +1 -1
- package/dist/components/iab-prompt/atoms/root.js +1 -1
- package/dist/components/iab-prompt/iab-prompt.js +1 -1
- package/dist/components/panel/atoms/root.js +1 -1
- package/dist/components/panel-trigger/atoms/root.js +1 -1
- package/dist/components/panel-trigger/panel-trigger.js +1 -1
- package/dist/components/panel-trigger/toolbar-loader.js +2 -0
- package/dist/components/preferences/atoms/root.js +1 -1
- package/dist/components/prompt/atoms/early-tap-script.js +2 -0
- package/dist/components/prompt/atoms/root.js +1 -1
- package/dist/components/shared/primitives/button.js +1 -1
- package/dist/components/shared/surface-styles.js +1 -1
- package/dist/consent-gate.js +1 -1
- package/dist/context/index.js +1 -1
- package/dist/devtools.js +1 -1
- package/dist/iab/styles.tw3.css +2 -2
- package/dist/iab-dialog-deferred.js +2 -0
- package/dist/iab.js +1 -1
- package/dist/index-parts/consent-gate.js +1 -1
- package/dist/index-parts/core.js +1 -1
- package/dist/index-parts/frame.js +1 -0
- package/dist/index-parts/hosted.js +1 -0
- package/dist/index-parts/offline.js +1 -0
- package/dist/index-parts/presets.js +1 -0
- package/dist/index.js +1 -1
- package/dist/modes.js +1 -0
- package/dist/panel-link.js +1 -1
- package/dist/panel-trigger.js +1 -1
- package/dist/provider.js +1 -1
- package/dist/styles.tw3.css +2 -2
- package/dist/transports/hosted.js +1 -0
- package/dist/transports/manifest.js +1 -0
- package/dist/utils/deferred-module.js +1 -1
- package/dist/version.js +1 -1
- package/dist-types/chunk-warming.d.ts +7 -6
- package/dist-types/components/consent-gate/frame.d.ts +19 -0
- package/dist-types/components/consent-gate/index.d.ts +3 -19
- package/dist-types/components/iab-prompt/iab-prompt.d.ts +1 -1
- package/dist-types/components/panel/index.d.ts +1 -1
- package/dist-types/components/panel-trigger/toolbar-loader.d.ts +34 -0
- package/dist-types/components/preferences/index.d.ts +1 -1
- package/dist-types/components/prompt/atoms/early-tap-script.d.ts +17 -0
- package/dist-types/components/prompt/index.d.ts +1 -1
- package/dist-types/components/shared/surface-styles.d.ts +26 -2
- package/dist-types/consent-gate.d.ts +1 -1
- package/dist-types/context/index.d.ts +3 -3
- package/dist-types/context.d.ts +2 -0
- package/dist-types/gpp.d.ts +1 -1
- package/dist-types/iab-dialog-deferred.d.ts +36 -0
- package/dist-types/iab.d.ts +3 -2
- package/dist-types/index-parts/consent-gate.d.ts +1 -1
- package/dist-types/index-parts/core.d.ts +1 -2
- package/dist-types/index-parts/frame.d.ts +7 -0
- package/dist-types/index-parts/hosted.d.ts +7 -0
- package/dist-types/index-parts/offline.d.ts +7 -0
- package/dist-types/index-parts/presets.d.ts +7 -0
- package/dist-types/index.d.ts +5 -1
- package/dist-types/modes.d.ts +26 -0
- package/dist-types/panel-link.d.ts +1 -1
- package/dist-types/panel-trigger.d.ts +1 -1
- package/dist-types/provider.d.ts +3 -3
- package/dist-types/transports/hosted.d.ts +36 -0
- package/dist-types/transports/manifest.d.ts +48 -0
- package/dist-types/version.d.ts +1 -1
- package/docs/README.md +7 -9
- package/docs/concepts/choose-your-setup.md +45 -10
- package/docs/concepts/consent-categories.md +1 -1
- package/docs/concepts/consent-state.md +5 -2
- package/docs/concepts/data-fetching.md +100 -42
- package/docs/concepts/modes.md +281 -0
- package/docs/customization/dark-mode.md +1 -1
- package/docs/customization/motion.md +2 -2
- package/docs/customization/recipes.md +4 -4
- package/docs/customization/slots.md +25 -25
- package/docs/customization/stylesheets.md +12 -14
- package/docs/customization/tailwind.md +17 -11
- package/docs/customization/tokens.md +36 -7
- package/docs/frameworks/react/components/consent-banner.md +14 -10
- package/docs/frameworks/react/components/consent-dialog.md +14 -10
- package/docs/frameworks/react/components/consent-provider.md +51 -44
- package/docs/frameworks/react/components.md +14 -10
- package/docs/frameworks/react/content-security-policy.md +21 -12
- package/docs/frameworks/react/hooks.md +2 -2
- package/docs/frameworks/react/iab.md +20 -2
- package/docs/frameworks/react/quickstart.md +63 -97
- package/docs/frameworks/react/rendering.md +168 -94
- package/docs/frameworks/react/scripts.md +19 -28
- package/docs/frameworks/react/troubleshooting.md +57 -25
- package/docs/frameworks/react/upgrade-v3.md +110 -62
- package/docs/guides/banner-experiments.md +21 -6
- package/docs/guides/troubleshooting.md +89 -25
- package/docs/guides/verify-consent.md +23 -8
- package/docs/integrations/adobe-analytics.md +60 -64
- package/docs/integrations/ahrefs-analytics.md +58 -63
- package/docs/integrations/amplitude.md +60 -64
- package/docs/integrations/clearbit.md +59 -63
- package/docs/integrations/cloudflare-web-analytics.md +56 -60
- package/docs/integrations/cloudflare-zaraz.md +55 -57
- package/docs/integrations/crisp.md +64 -69
- package/docs/integrations/databuddy.md +62 -64
- package/docs/integrations/fathom-analytics.md +56 -60
- package/docs/integrations/front-chat.md +56 -60
- package/docs/integrations/google-maps.md +25 -13
- package/docs/integrations/google-tag-manager.md +153 -77
- package/docs/integrations/google-tag.md +134 -78
- package/docs/integrations/heap.md +56 -60
- package/docs/integrations/hightouch.md +55 -60
- package/docs/integrations/hotjar.md +60 -64
- package/docs/integrations/intercom.md +55 -60
- package/docs/integrations/klaviyo.md +65 -66
- package/docs/integrations/linkedin-insights.md +58 -63
- package/docs/integrations/logrocket.md +55 -60
- package/docs/integrations/matomo-analytics.md +58 -60
- package/docs/integrations/meta-pixel.md +56 -60
- package/docs/integrations/microsoft-clarity.md +57 -60
- package/docs/integrations/microsoft-uet.md +58 -61
- package/docs/integrations/mixpanel-analytics.md +73 -75
- package/docs/integrations/one-dollar-stats.md +53 -59
- package/docs/integrations/openai-pixel.md +58 -60
- package/docs/integrations/overview.md +59 -42
- package/docs/integrations/pinterest-tag.md +56 -60
- package/docs/integrations/pirsch.md +54 -60
- package/docs/integrations/plausible-analytics.md +55 -60
- package/docs/integrations/posthog.md +56 -60
- package/docs/integrations/promptwatch.md +57 -63
- package/docs/integrations/reddit-pixel.md +57 -60
- package/docs/integrations/rudderstack.md +65 -67
- package/docs/integrations/rybbit-analytics.md +70 -75
- package/docs/integrations/segment.md +56 -60
- package/docs/integrations/sentry.md +65 -60
- package/docs/integrations/snapchat-pixel.md +54 -60
- package/docs/integrations/tiktok-pixel.md +59 -63
- package/docs/integrations/umami-analytics.md +54 -60
- package/docs/integrations/vercel-analytics.md +53 -59
- package/docs/integrations/vercel-speed-insights.md +317 -0
- package/docs/integrations/x-pixel.md +57 -63
- package/docs/integrations/youtube.md +25 -13
- package/package.json +18 -8
- package/docs/upgrade-v3.md +0 -429
|
@@ -12,15 +12,15 @@ Each framework has one way to add classes, inline styles or attributes to a
|
|
|
12
12
|
single part of a stock component. The keys differ between the two
|
|
13
13
|
vocabularies, so a configuration from one does not work in the other.
|
|
14
14
|
|
|
15
|
-
| Framework | Part API
|
|
16
|
-
| ----------------------- |
|
|
17
|
-
| Next.js, TanStack Start | `options.components` on `ConsentRoot`
|
|
18
|
-
| React | `components` in the `ConsentProvider` options
|
|
19
|
-
| Nuxt | `components` in the `c15t` options, or in `app/app.config.ts`
|
|
20
|
-
| Vue | `components` in the `c15tVue` options
|
|
21
|
-
| Astro | `theme.slots` in the `c15t()` integration options
|
|
22
|
-
| Svelte, SvelteKit | `theme.slots` on `
|
|
23
|
-
| HTML, JavaScript | `ui.theme.slots`
|
|
15
|
+
| Framework | Part API | Keys look like | Class key |
|
|
16
|
+
| ----------------------- | ------------------------------------------------------------------------ | ------------------------- | ------------------------ |
|
|
17
|
+
| Next.js, TanStack Start | `options.components` in Next.js `c15t.config.ts`, or on `ConsentRoot` | `components.banner.card` | `className` |
|
|
18
|
+
| React | `components` in the `ConsentProvider` options | `components.banner.card` | `className` |
|
|
19
|
+
| Nuxt | `components` in the `c15t` options, or in `app/app.config.ts` | `components.banner.card` | `class` |
|
|
20
|
+
| Vue | `components` in the `c15tVue` options | `components.banner.card` | `class` |
|
|
21
|
+
| Astro | `theme.slots` in the `c15t()` integration options | `slots.consentBannerCard` | A string, or `className` |
|
|
22
|
+
| Svelte, SvelteKit | `theme.slots` on `ConsentProvider` (Svelte) or `ConsentRoot` (SvelteKit) | `slots.consentBannerCard` | A string, or `className` |
|
|
23
|
+
| HTML, JavaScript | `ui.theme.slots` | `slots.consentBannerCard` | A string, or `className` |
|
|
24
24
|
|
|
25
25
|
React and Vue also read `theme.slots` from the theme in their options, and
|
|
26
26
|
apply each slot to the matching `components` part, such as
|
|
@@ -65,22 +65,22 @@ Modules, vanilla-extract, StyleX and Emotion, and
|
|
|
65
65
|
|
|
66
66
|
## Banner parts
|
|
67
67
|
|
|
68
|
-
| Part | `components` key | `theme.slots` key | `data-testid`
|
|
69
|
-
| ------------------------------------------- | ------------------------------------ | ---------------------------------- |
|
|
70
|
-
| Positioning root, with the state attributes | `banner.root` | `consentBanner` | `consent-banner-root`
|
|
71
|
-
| Card sizing and branding container | `banner.cardShell` | None |
|
|
72
|
-
| Visible card | `banner.card` | `consentBannerCard` | `consent-banner-card`
|
|
73
|
-
| Title and description container | `banner.header` | `consentBannerHeader` |
|
|
74
|
-
| Title | `banner.title` | `consentBannerTitle` |
|
|
75
|
-
| Description | `description.banner` | `consentBannerDescription` |
|
|
76
|
-
| Action area | `banner.footer` | `consentBannerFooter` |
|
|
77
|
-
| Group of action groups | `banner.actions` | None |
|
|
78
|
-
| One group of equally prominent actions | `banner.actionGroup` | `consentBannerFooterSubGroup` |
|
|
79
|
-
| Group of right links | `banner.rights` | `consentBannerRights` |
|
|
80
|
-
| One right link | `banner.rightLink` | `consentBannerRightLink` |
|
|
81
|
-
| Backdrop of a blocking banner | `banner.overlay` | `consentBannerOverlay` |
|
|
82
|
-
| "Secured by" tag | `tag.banner` | `consentBannerTag` |
|
|
83
|
-
| Filled and outlined buttons | `button.primary`, `button.secondary` | `buttonPrimary`, `buttonSecondary` |
|
|
68
|
+
| Part | `components` key | `theme.slots` key | `data-testid` |
|
|
69
|
+
| ------------------------------------------- | ------------------------------------ | ---------------------------------- | ------------------------- |
|
|
70
|
+
| Positioning root, with the state attributes | `banner.root` | `consentBanner` | `consent-banner-root` |
|
|
71
|
+
| Card sizing and branding container | `banner.cardShell` | None | |
|
|
72
|
+
| Visible card | `banner.card` | `consentBannerCard` | `consent-banner-card` |
|
|
73
|
+
| Title and description container | `banner.header` | `consentBannerHeader` | |
|
|
74
|
+
| Title | `banner.title` | `consentBannerTitle` | |
|
|
75
|
+
| Description | `description.banner` | `consentBannerDescription` | |
|
|
76
|
+
| Action area | `banner.footer` | `consentBannerFooter` | |
|
|
77
|
+
| Group of action groups | `banner.actions` | None | |
|
|
78
|
+
| One group of equally prominent actions | `banner.actionGroup` | `consentBannerFooterSubGroup` | |
|
|
79
|
+
| Group of right links | `banner.rights` | `consentBannerRights` | |
|
|
80
|
+
| One right link | `banner.rightLink` | `consentBannerRightLink` | |
|
|
81
|
+
| Backdrop of a blocking banner | `banner.overlay` | `consentBannerOverlay` | |
|
|
82
|
+
| "Secured by" tag | `tag.banner` | `consentBannerTag` | `consent-banner-branding` |
|
|
83
|
+
| Filled and outlined buttons | `button.primary`, `button.secondary` | `buttonPrimary`, `buttonSecondary` | |
|
|
84
84
|
|
|
85
85
|
The button parts apply to every c15t button of that style, in the banner and
|
|
86
86
|
the dialog. The script tag's banner has no rights group, so
|
|
@@ -104,20 +104,18 @@ need control over the file:
|
|
|
104
104
|
cache performs better for your site's repeat visits. Compare cold and warm
|
|
105
105
|
visits on your production host before choosing this option.
|
|
106
106
|
|
|
107
|
-
| Framework | Option
|
|
108
|
-
| ----------------- |
|
|
109
|
-
| Next.js | `options.styles` on `ConsentRoot`
|
|
110
|
-
| TanStack Start | `options.styles` on `ConsentRoot`
|
|
111
|
-
| React | `options.styles` on `ConsentProvider`
|
|
112
|
-
| Svelte, SvelteKit | `options.styles` on `
|
|
113
|
-
| Astro | `styles` in the `c15t()` integration options
|
|
114
|
-
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
options={{ styles: false }}
|
|
120
|
-
>
|
|
107
|
+
| Framework | Option | Files to import |
|
|
108
|
+
| ----------------- | -------------------------------------------------------- | -------------------------------------------------------------------------------------- |
|
|
109
|
+
| Next.js | `options.styles` in `c15t.config.ts` or on `ConsentRoot` | `c15t/next/styles.css`, and `c15t/next/iab/styles.css` for IAB TCF |
|
|
110
|
+
| TanStack Start | `options.styles` on `ConsentRoot` | `c15t/tanstack-start/styles.css`, and `c15t/tanstack-start/iab/styles.css` for IAB TCF |
|
|
111
|
+
| React | `options.styles` on `ConsentProvider` | `c15t/react/styles.css`, and `c15t/react/iab/styles.css` for IAB TCF |
|
|
112
|
+
| Svelte, SvelteKit | `options.styles` on `ConsentProvider` or `ConsentRoot` | `@c15t/svelte/styles.css`, and `@c15t/svelte/iab/styles.css` for IAB TCF |
|
|
113
|
+
| Astro | `styles` in the `c15t()` integration options | See [load Astro's stylesheets yourself](#load-astros-stylesheets-yourself) |
|
|
114
|
+
|
|
115
|
+
```ts title="c15t.config.ts (Next.js)"
|
|
116
|
+
import { defineConsentConfig } from 'c15t/next';
|
|
117
|
+
|
|
118
|
+
export default defineConsentConfig({ options: { styles: false } });
|
|
121
119
|
```
|
|
122
120
|
|
|
123
121
|
`styles: false` turns off only the stylesheets. Tokens from `ConsentTheme`
|
|
@@ -111,9 +111,10 @@ Add `@tailwindcss/vite` under `vite.plugins` and list your CSS entry in
|
|
|
111
111
|
|
|
112
112
|
```ts title="nuxt.config.ts"
|
|
113
113
|
import tailwindcss from '@tailwindcss/vite';
|
|
114
|
+
import { hosted } from 'c15t/vue';
|
|
114
115
|
|
|
115
116
|
export default defineNuxtConfig({
|
|
116
|
-
c15t: { backendURL: '/api/c15t' },
|
|
117
|
+
c15t: { backendURL: '/api/c15t', mode: hosted() },
|
|
117
118
|
compatibilityDate: '2026-07-04',
|
|
118
119
|
css: ['~/assets/css/main.css'],
|
|
119
120
|
modules: ['c15t/vue'],
|
|
@@ -138,10 +139,12 @@ Tailwind:
|
|
|
138
139
|
```ts title="vite.config.ts"
|
|
139
140
|
import tailwindcss from '@tailwindcss/vite';
|
|
140
141
|
import vue from '@vitejs/plugin-vue';
|
|
141
|
-
import
|
|
142
|
+
import { consentManifest } from 'c15t/vue/vite';
|
|
142
143
|
import { defineConfig } from 'vite';
|
|
143
144
|
|
|
144
|
-
export default defineConfig({
|
|
145
|
+
export default defineConfig({
|
|
146
|
+
plugins: [vue(), consentManifest({ backendURL: '/api/c15t' }), tailwindcss()],
|
|
147
|
+
});
|
|
145
148
|
```
|
|
146
149
|
|
|
147
150
|
Import this stylesheet from `src/main.ts`:
|
|
@@ -272,9 +275,10 @@ They are the same plugin. A config that already lists
|
|
|
272
275
|
|
|
273
276
|
Make four changes:
|
|
274
277
|
|
|
275
|
-
1. Set `styles: false` where you configure c15t: `options`
|
|
276
|
-
|
|
277
|
-
and `styles={false}` on `
|
|
278
|
+
1. Set `styles: false` where you configure c15t: `options` in Next.js
|
|
279
|
+
`c15t.config.ts`, `options` on `ConsentRoot` in TanStack Start, `options`
|
|
280
|
+
on `ConsentProvider` in React, and `styles={false}` on `ConsentProvider` in
|
|
281
|
+
Svelte or `ConsentRoot` in SvelteKit.
|
|
278
282
|
Vue, Nuxt and Astro need no change.
|
|
279
283
|
2. Add the plugin to your PostCSS plugins, before `tailwindcss`. Write the plugins as an object, as the examples below do.
|
|
280
284
|
PostCSS runs them in the order of the keys. Next.js also accepts an array
|
|
@@ -415,8 +419,10 @@ Nuxt reads PostCSS plugins from `postcss.plugins` in `nuxt.config.ts`, in
|
|
|
415
419
|
the order listed:
|
|
416
420
|
|
|
417
421
|
```ts title="nuxt.config.ts"
|
|
422
|
+
import { hosted } from 'c15t/vue';
|
|
423
|
+
|
|
418
424
|
export default defineNuxtConfig({
|
|
419
|
-
c15t: { backendURL: '/api/c15t' },
|
|
425
|
+
c15t: { backendURL: '/api/c15t', mode: hosted() },
|
|
420
426
|
compatibilityDate: '2026-07-04',
|
|
421
427
|
css: ['~/assets/css/main.css'],
|
|
422
428
|
modules: ['c15t/vue'],
|
|
@@ -536,7 +542,7 @@ export default {
|
|
|
536
542
|
|
|
537
543
|
Import `@c15t/svelte/styles.css` above the directives, import this
|
|
538
544
|
stylesheet from `src/main.ts`, and pass `styles={false}` to
|
|
539
|
-
`
|
|
545
|
+
`ConsentProvider`:
|
|
540
546
|
|
|
541
547
|
```css title="src/app.css"
|
|
542
548
|
/* Vite ignores an @import below other rules, so it goes first. */
|
|
@@ -572,7 +578,7 @@ export default {
|
|
|
572
578
|
|
|
573
579
|
Import `@c15t/svelte/styles.css` above the directives, import this
|
|
574
580
|
stylesheet from your root `+layout.svelte`, and pass `styles={false}` to
|
|
575
|
-
`
|
|
581
|
+
`ConsentRoot`:
|
|
576
582
|
|
|
577
583
|
```css title="src/app.css"
|
|
578
584
|
/* Vite ignores an @import below other rules, so it goes first. */
|
|
@@ -677,12 +683,12 @@ Add the classes to `components` in the `c15tVue` options. Vue takes
|
|
|
677
683
|
|
|
678
684
|
```ts title="src/main.ts"
|
|
679
685
|
.use(c15tVue, {
|
|
680
|
-
backendURL: '/api/c15t',
|
|
681
686
|
components: {
|
|
682
687
|
banner: {
|
|
683
688
|
root: { class: 'p-[7px] dark:p-[11px]' },
|
|
684
689
|
},
|
|
685
690
|
},
|
|
691
|
+
mode: hosted(),
|
|
686
692
|
})
|
|
687
693
|
```
|
|
688
694
|
|
|
@@ -816,7 +822,7 @@ instead:
|
|
|
816
822
|
```
|
|
817
823
|
|
|
818
824
|
Import `@c15t/browser/styles.css` above the directives in your Tailwind entry.
|
|
819
|
-
Install `@c15t/browser
|
|
825
|
+
Install `@c15t/browser`, which provides both the stylesheet and
|
|
820
826
|
`@c15t/browser/postcss-tailwind3`:
|
|
821
827
|
|
|
822
828
|
```css title="style.css"
|
|
@@ -40,13 +40,13 @@ export const theme = defineTheme({
|
|
|
40
40
|
Install `@c15t/ui` if importing its theme helper directly. Where the theme
|
|
41
41
|
goes depends on the framework:
|
|
42
42
|
|
|
43
|
-
| Framework | Tokens | `consentActions`
|
|
44
|
-
| ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------- |
|
|
45
|
-
| Next.js, TanStack Start, React | `<ConsentTheme theme={theme} />`, rendered on the server where the app has one | `theme` in the provider options
|
|
46
|
-
| Nuxt, Vue | `theme` or `tokens` in the module or plugin options | Not available
|
|
47
|
-
| Astro | `theme` in the integration options | The same `theme`
|
|
48
|
-
| Svelte, SvelteKit | `generateThemeCSS(theme)` from `@c15t/ui/theme` on the server, in a `<style>` element, or `--c15t-*` variables in your stylesheet | `theme` on `
|
|
49
|
-
| HTML, JavaScript | `ui.theme` | Not available
|
|
43
|
+
| Framework | Tokens | `consentActions` |
|
|
44
|
+
| ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
|
|
45
|
+
| Next.js, TanStack Start, React | `<ConsentTheme theme={theme} />`, rendered on the server where the app has one | `theme` in the provider options |
|
|
46
|
+
| Nuxt, Vue | `theme` or `tokens` in the module or plugin options | Not available |
|
|
47
|
+
| Astro | `theme` in the integration options | The same `theme` |
|
|
48
|
+
| Svelte, SvelteKit | `generateThemeCSS(theme)` from `@c15t/ui/theme` on the server, in a `<style>` element, or `--c15t-*` variables in your stylesheet | `theme` on `ConsentProvider` (Svelte) or `ConsentRoot` (SvelteKit) |
|
|
49
|
+
| HTML, JavaScript | `ui.theme` | Not available |
|
|
50
50
|
|
|
51
51
|
React and Svelte providers do not turn tokens in their `theme` option into
|
|
52
52
|
CSS, and warn in development when a theme holds tokens but the page has no
|
|
@@ -169,6 +169,35 @@ them, on any screen size.
|
|
|
169
169
|
Test long translations and small screens after changing width or typography.
|
|
170
170
|
A compact banner must still fit the required actions.
|
|
171
171
|
|
|
172
|
+
## Stack the banner with your own layers
|
|
173
|
+
|
|
174
|
+
The banner and its overlay sit at the top of the page's stacking order by
|
|
175
|
+
default. Lower them when a navbar, drawer, or chat widget should cover the
|
|
176
|
+
banner.
|
|
177
|
+
|
|
178
|
+
| Variable | Default | Target |
|
|
179
|
+
| -------------------------------------- | -------- | ----------------------------- |
|
|
180
|
+
| `--consent-banner-z-index` | `999998` | Banner |
|
|
181
|
+
| `--consent-banner-overlay-z-index` | `999997` | Backdrop of a blocking banner |
|
|
182
|
+
| `--iab-consent-banner-z-index` | `999998` | IAB TCF banner |
|
|
183
|
+
| `--iab-consent-banner-overlay-z-index` | `999997` | IAB TCF banner backdrop |
|
|
184
|
+
| `--consent-dialog-z-index` | `999999` | Preferences dialog |
|
|
185
|
+
| `--consent-dialog-overlay-z-index` | `999998` | Preferences dialog backdrop |
|
|
186
|
+
|
|
187
|
+
```css
|
|
188
|
+
:root {
|
|
189
|
+
--consent-banner-z-index: 40;
|
|
190
|
+
--consent-banner-overlay-z-index: 39;
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Keep each z-index above its overlay's, or the backdrop covers the card it
|
|
195
|
+
belongs to. Keep the dialog above the banner so Customize opens on top.
|
|
196
|
+
|
|
197
|
+
Only the card and the "Secured by" tag take clicks. Clicks on the space
|
|
198
|
+
around a floating card, or beside the tag on a bar, reach the page. A
|
|
199
|
+
blocking banner catches every click.
|
|
200
|
+
|
|
172
201
|
## Restyle the "Secured by" tag
|
|
173
202
|
|
|
174
203
|
The tag sits on the edge of the banner and dialog cards and uses the primary
|
|
@@ -12,26 +12,30 @@ The [quickstart](../quickstart.md) mounts both in
|
|
|
12
12
|
`src/consent.tsx`:
|
|
13
13
|
|
|
14
14
|
```tsx title="src/consent.tsx"
|
|
15
|
-
import {
|
|
15
|
+
import { posthog } from '@c15t/integrations/posthog';
|
|
16
16
|
import {
|
|
17
17
|
ConsentBanner,
|
|
18
18
|
ConsentDialog,
|
|
19
19
|
ConsentDialogLink,
|
|
20
20
|
ConsentProvider,
|
|
21
|
+
hosted,
|
|
21
22
|
} from 'c15t/react';
|
|
22
23
|
import type { ReactNode } from 'react';
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
25
|
+
const options = {
|
|
26
|
+
// Asks VITE_C15T_BACKEND_URL for each visitor's policy.
|
|
27
|
+
mode: hosted(),
|
|
28
|
+
scripts: [
|
|
29
|
+
posthog({
|
|
30
|
+
id: 'phc_your_project_key',
|
|
31
|
+
initOptions: { cookieless_mode: 'never' },
|
|
32
|
+
loadMode: 'after-consent',
|
|
33
|
+
}),
|
|
34
|
+
],
|
|
35
|
+
};
|
|
32
36
|
|
|
33
37
|
export const Consent = ({ children }: { children: ReactNode }) => (
|
|
34
|
-
<ConsentProvider options={
|
|
38
|
+
<ConsentProvider options={options}>
|
|
35
39
|
{children}
|
|
36
40
|
<ConsentBanner />
|
|
37
41
|
<ConsentDialog />
|
|
@@ -14,26 +14,30 @@ group: frameworks
|
|
|
14
14
|
code.
|
|
15
15
|
|
|
16
16
|
```tsx title="src/consent.tsx"
|
|
17
|
-
import {
|
|
17
|
+
import { posthog } from '@c15t/integrations/posthog';
|
|
18
18
|
import {
|
|
19
19
|
ConsentBanner,
|
|
20
20
|
ConsentDialog,
|
|
21
21
|
ConsentDialogLink,
|
|
22
22
|
ConsentProvider,
|
|
23
|
+
hosted,
|
|
23
24
|
} from 'c15t/react';
|
|
24
25
|
import type { ReactNode } from 'react';
|
|
25
26
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
27
|
+
const options = {
|
|
28
|
+
// Asks VITE_C15T_BACKEND_URL for each visitor's policy.
|
|
29
|
+
mode: hosted(),
|
|
30
|
+
scripts: [
|
|
31
|
+
posthog({
|
|
32
|
+
id: 'phc_your_project_key',
|
|
33
|
+
initOptions: { cookieless_mode: 'never' },
|
|
34
|
+
loadMode: 'after-consent',
|
|
35
|
+
}),
|
|
36
|
+
],
|
|
37
|
+
};
|
|
34
38
|
|
|
35
39
|
export const Consent = ({ children }: { children: ReactNode }) => (
|
|
36
|
-
<ConsentProvider options={
|
|
40
|
+
<ConsentProvider options={options}>
|
|
37
41
|
{children}
|
|
38
42
|
<ConsentBanner />
|
|
39
43
|
<ConsentDialog />
|
|
@@ -14,26 +14,30 @@ The [quickstart](../quickstart.md) does this in
|
|
|
14
14
|
`src/consent.tsx`:
|
|
15
15
|
|
|
16
16
|
```tsx title="src/consent.tsx"
|
|
17
|
-
import {
|
|
17
|
+
import { posthog } from '@c15t/integrations/posthog';
|
|
18
18
|
import {
|
|
19
19
|
ConsentBanner,
|
|
20
20
|
ConsentDialog,
|
|
21
21
|
ConsentDialogLink,
|
|
22
22
|
ConsentProvider,
|
|
23
|
+
hosted,
|
|
23
24
|
} from 'c15t/react';
|
|
24
25
|
import type { ReactNode } from 'react';
|
|
25
26
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
27
|
+
const options = {
|
|
28
|
+
// Asks VITE_C15T_BACKEND_URL for each visitor's policy.
|
|
29
|
+
mode: hosted(),
|
|
30
|
+
scripts: [
|
|
31
|
+
posthog({
|
|
32
|
+
id: 'phc_your_project_key',
|
|
33
|
+
initOptions: { cookieless_mode: 'never' },
|
|
34
|
+
loadMode: 'after-consent',
|
|
35
|
+
}),
|
|
36
|
+
],
|
|
37
|
+
};
|
|
34
38
|
|
|
35
39
|
export const Consent = ({ children }: { children: ReactNode }) => (
|
|
36
|
-
<ConsentProvider options={
|
|
40
|
+
<ConsentProvider options={options}>
|
|
37
41
|
{children}
|
|
38
42
|
<ConsentBanner />
|
|
39
43
|
<ConsentDialog />
|
|
@@ -44,11 +48,14 @@ export const Consent = ({ children }: { children: ReactNode }) => (
|
|
|
44
48
|
);
|
|
45
49
|
```
|
|
46
50
|
|
|
47
|
-
`
|
|
48
|
-
|
|
49
|
-
the
|
|
50
|
-
`
|
|
51
|
-
|
|
51
|
+
`hosted()` from `c15t/react` asks the backend's `/init` for the visitor's
|
|
52
|
+
policy on each page load, and sends consent choices to the same backend. It
|
|
53
|
+
uses the backend URL `consentManifest()` read from `VITE_C15T_BACKEND_URL` or
|
|
54
|
+
`VITE_INTH_PROJECT_URL`. Set one to the backend URL from your Inth project. To
|
|
55
|
+
resolve a bundled policy in the browser instead, pass `manifest()` from
|
|
56
|
+
`c15t/react`; see
|
|
57
|
+
[rendering](../rendering.md#bundle-the-policy-at-build-time).
|
|
58
|
+
The Next.js and TanStack Start adapters export `ConsentRoot` instead, which wraps
|
|
52
59
|
this provider and passes it server-resolved state.
|
|
53
60
|
|
|
54
61
|
## Provider options
|
|
@@ -61,35 +68,35 @@ the provider to change them. `scripts`, `vendors`, `networkBlocker`,
|
|
|
61
68
|
`iframeBlocker`, `consentCategories`, `overrides`, `user`, `callbacks` and
|
|
62
69
|
`enabled` apply when they change.
|
|
63
70
|
|
|
64
|
-
| Option | Purpose
|
|
65
|
-
| ----------------------------- |
|
|
66
|
-
| `mode` | Required. `hosted(
|
|
67
|
-
| `prefetch` | Server-resolved state, or a promise of it, from a framework adapter's server helper
|
|
68
|
-
| `scripts` | Consent-gated vendor scripts. See [scripts and embeds](../scripts.md)
|
|
69
|
-
| `vendors` | Vendors listed under their category with their own switch. See [vendor consent](../vendor-consent.md)
|
|
70
|
-
| `scriptLoader` | Options for the script loader module
|
|
71
|
-
| `networkBlocker` | Rules that hold `fetch` and `XMLHttpRequest` calls until their category is allowed, or `false`
|
|
72
|
-
| `iframeBlocker` | Gates DOM iframes that carry `data-category`. On by default; `false` turns it off
|
|
73
|
-
| `persistence` | Stores the visitor's choice in a cookie and localStorage. On by default
|
|
74
|
-
| `storageConfig` | Storage key and cookie settings for the stored choice
|
|
75
|
-
| `clearOnRevocation` | Cookies and storage keys to delete when a category is denied
|
|
76
|
-
| `reloadOnConsentRevoked` | Reload the page after the visitor turns off a granted category or vendor. Defaults to `true`
|
|
77
|
-
| `consentCategories` | Categories the preference dialog offers alongside those your scripts use, within the policy's scope
|
|
78
|
-
| `overrides` | Force the country, region or language the policy is resolved for, for testing
|
|
79
|
-
| `user` | Link consent records to a signed-in user
|
|
80
|
-
| `callbacks` | Choice, permission and error events
|
|
81
|
-
| `i18n` | Languages and message overrides
|
|
82
|
-
| `legalLinks` | Privacy policy and other links shown in the banner and dialog
|
|
83
|
-
| `theme` | `consentActions` and slot styles. Tokens go through `ConsentTheme`; see [customize](../customize.md)
|
|
84
|
-
| `components` | Slot attributes per component part
|
|
85
|
-
| `presentation` | Banner and dialog shape, position and blocking
|
|
86
|
-
| `experiment` | A/B test of `presentation`, read once at mount. See [banner experiments](../../../guides/banner-experiments.md)
|
|
87
|
-
| `journey` | Random id that links each `/init` to the save that follows. See [session reports](../../../concepts/data-fetching.md#link-an-init-to-the-save-that-follows)
|
|
88
|
-
| `colorScheme` | `'light'`, `'dark'`, `'system'`, or `null` to leave the `c15t-dark` class alone
|
|
89
|
-
| `noStyle`, `disableAnimation` | Drop the built-in styles, or turn off animations
|
|
90
|
-
| `preloadDialog` | When the deferred `ConsentDialog` starts loading: `'idle'` (default) or `'intent'`; see [ConsentDialog](./consent-dialog.md#behavior)
|
|
91
|
-
| `nonce` | Content Security Policy nonce for script elements c15t inserts
|
|
92
|
-
| `enabled` | Set `false` only when you deliberately bypass consent enforcement
|
|
71
|
+
| Option | Purpose |
|
|
72
|
+
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
73
|
+
| `mode` | Required. `hosted()` for the backend's `/init`, `manifest()` for a bundled policy, `offline()` for local policies, all from `c15t/react`, or `custom()` for your own transport. See [consent modes](../../../concepts/modes.md) |
|
|
74
|
+
| `prefetch` | Server-resolved state, or a promise of it, from a framework adapter's server helper |
|
|
75
|
+
| `scripts` | Consent-gated vendor scripts. See [scripts and embeds](../scripts.md) |
|
|
76
|
+
| `vendors` | Vendors listed under their category with their own switch. See [vendor consent](../vendor-consent.md) |
|
|
77
|
+
| `scriptLoader` | Options for the script loader module |
|
|
78
|
+
| `networkBlocker` | Rules that hold `fetch` and `XMLHttpRequest` calls until their category is allowed, or `false` |
|
|
79
|
+
| `iframeBlocker` | Gates DOM iframes that carry `data-category`. On by default; `false` turns it off |
|
|
80
|
+
| `persistence` | Stores the visitor's choice in a cookie and localStorage. On by default |
|
|
81
|
+
| `storageConfig` | Storage key and cookie settings for the stored choice |
|
|
82
|
+
| `clearOnRevocation` | Cookies and storage keys to delete when a category is denied |
|
|
83
|
+
| `reloadOnConsentRevoked` | Reload the page after the visitor turns off a granted category or vendor. Defaults to `true` |
|
|
84
|
+
| `consentCategories` | Categories the preference dialog offers alongside those your scripts use, within the policy's scope |
|
|
85
|
+
| `overrides` | Force the country, region or language the policy is resolved for, for testing |
|
|
86
|
+
| `user` | Link consent records to a signed-in user |
|
|
87
|
+
| `callbacks` | Choice, permission and error events |
|
|
88
|
+
| `i18n` | Languages and message overrides |
|
|
89
|
+
| `legalLinks` | Privacy policy and other links shown in the banner and dialog |
|
|
90
|
+
| `theme` | `consentActions` and slot styles. Tokens go through `ConsentTheme`; see [customize](../customize.md) |
|
|
91
|
+
| `components` | Slot attributes per component part |
|
|
92
|
+
| `presentation` | Banner and dialog shape, position and blocking |
|
|
93
|
+
| `experiment` | A/B test of `presentation`, read once at mount. See [banner experiments](../../../guides/banner-experiments.md) |
|
|
94
|
+
| `journey` | Random id that links each `/init` to the save that follows. See [session reports](../../../concepts/data-fetching.md#link-an-init-to-the-save-that-follows) |
|
|
95
|
+
| `colorScheme` | `'light'`, `'dark'`, `'system'`, or `null` to leave the `c15t-dark` class alone |
|
|
96
|
+
| `noStyle`, `disableAnimation` | Drop the built-in styles, or turn off animations |
|
|
97
|
+
| `preloadDialog` | When the deferred `ConsentDialog` starts loading: `'idle'` (default) or `'intent'`; see [ConsentDialog](./consent-dialog.md#behavior) |
|
|
98
|
+
| `nonce` | Content Security Policy nonce for script elements c15t inserts |
|
|
99
|
+
| `enabled` | Set `false` only when you deliberately bypass consent enforcement |
|
|
93
100
|
|
|
94
101
|
`enabled: false` grants categories and allows gated loading while suppressing
|
|
95
102
|
consent UI. It is not a way to fix failed initialization or hide a banner in
|
|
@@ -36,26 +36,30 @@ Most apps start with four components. `ConsentProvider` holds the runtime,
|
|
|
36
36
|
one file:
|
|
37
37
|
|
|
38
38
|
```tsx title="src/consent.tsx"
|
|
39
|
-
import {
|
|
39
|
+
import { posthog } from '@c15t/integrations/posthog';
|
|
40
40
|
import {
|
|
41
41
|
ConsentBanner,
|
|
42
42
|
ConsentDialog,
|
|
43
43
|
ConsentDialogLink,
|
|
44
44
|
ConsentProvider,
|
|
45
|
+
hosted,
|
|
45
46
|
} from 'c15t/react';
|
|
46
47
|
import type { ReactNode } from 'react';
|
|
47
48
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
49
|
+
const options = {
|
|
50
|
+
// Asks VITE_C15T_BACKEND_URL for each visitor's policy.
|
|
51
|
+
mode: hosted(),
|
|
52
|
+
scripts: [
|
|
53
|
+
posthog({
|
|
54
|
+
id: 'phc_your_project_key',
|
|
55
|
+
initOptions: { cookieless_mode: 'never' },
|
|
56
|
+
loadMode: 'after-consent',
|
|
57
|
+
}),
|
|
58
|
+
],
|
|
59
|
+
};
|
|
56
60
|
|
|
57
61
|
export const Consent = ({ children }: { children: ReactNode }) => (
|
|
58
|
-
<ConsentProvider options={
|
|
62
|
+
<ConsentProvider options={options}>
|
|
59
63
|
{children}
|
|
60
64
|
<ConsentBanner />
|
|
61
65
|
<ConsentDialog />
|
|
@@ -10,14 +10,16 @@ group: frameworks
|
|
|
10
10
|
|
|
11
11
|
A React app with c15t adds these to the page, and your policy must allow them:
|
|
12
12
|
|
|
13
|
-
| What
|
|
14
|
-
|
|
|
15
|
-
| The `<style>` elements the banner, dialog and other stock components render with c15t's rules
|
|
16
|
-
| `c15t/react/styles.css`, only if you import it with `styles: false`
|
|
17
|
-
| The `<style id="c15t-theme">` element, if you render `ConsentTheme`
|
|
18
|
-
| `<script>` elements the script loader creates for `scripts` entries, both `src` and inline
|
|
19
|
-
|
|
|
20
|
-
|
|
|
13
|
+
| What | Directive |
|
|
14
|
+
| --------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------- |
|
|
15
|
+
| The `<style>` elements the banner, dialog and other stock components render with c15t's rules | `style-src` with a nonce |
|
|
16
|
+
| `c15t/react/styles.css`, only if you import it with `styles: false` | `style-src 'self'` |
|
|
17
|
+
| The `<style id="c15t-theme">` element, if you render `ConsentTheme` | `style-src` with a nonce or its hash |
|
|
18
|
+
| `<script>` elements the script loader creates for `scripts` entries, both `src` and inline | `script-src` with each vendor's host, or a nonce |
|
|
19
|
+
| The inline `<script>` that `consentManifest()` adds to `index.html` to send `/init` early | `script-src` with a nonce or its hash |
|
|
20
|
+
| With server rendering, the inline `<script>` before the banner's buttons that holds a tap made before hydration | `script-src` with a nonce or its hash |
|
|
21
|
+
| Browser requests to your backend's `/init` and `/subjects` | `connect-src` with the backend origin |
|
|
22
|
+
| Iframes inside `ConsentGate`, and the frames, images and requests your vendors load | `frame-src`, `img-src`, `connect-src` for each vendor |
|
|
21
23
|
|
|
22
24
|
In a client-rendered app, c15t components set their inline styles through
|
|
23
25
|
React. A policy does not restrict styles set that way, so they need no
|
|
@@ -25,8 +27,10 @@ directive.
|
|
|
25
27
|
|
|
26
28
|
## Allow the consent backend
|
|
27
29
|
|
|
28
|
-
With `hosted(
|
|
29
|
-
and `POST {url}/subjects` when the visitor accepts, rejects or saves.
|
|
30
|
+
With `hosted()`, the browser calls `GET {url}/init` on every page load
|
|
31
|
+
and `POST {url}/subjects` when the visitor accepts, rejects or saves. With
|
|
32
|
+
`manifest()`, it calls `POST {url}/subjects`, and `GET {url}/init` only when
|
|
33
|
+
the policy needs a location the browser does not know. Add the
|
|
30
34
|
backend's origin to `connect-src`:
|
|
31
35
|
|
|
32
36
|
```txt title="Content-Security-Policy (partial)"
|
|
@@ -67,8 +71,9 @@ entry takes precedence for that element. The stock components put it on the
|
|
|
67
71
|
With Vite, set `html.cspNonce` to a placeholder in `vite.config.ts`, and have
|
|
68
72
|
your server replace it with a new nonce on every response. Vite then adds
|
|
69
73
|
`<meta property="csp-nonce" nonce="...">` to the page, and the browser keeps the
|
|
70
|
-
value in the tag's `nonce` property.
|
|
71
|
-
the
|
|
74
|
+
value in the tag's `nonce` property. Vite also stamps the nonce on the early
|
|
75
|
+
`/init` script. Read it where you create the provider, in the
|
|
76
|
+
quickstart's `src/consent.tsx`:
|
|
72
77
|
|
|
73
78
|
```tsx title="src/consent.tsx (partial)"
|
|
74
79
|
const nonce =
|
|
@@ -85,6 +90,10 @@ The provider reads `options.nonce` once, when it mounts. A server-rendered
|
|
|
85
90
|
React app, such as one built with React Router framework mode, reads the nonce
|
|
86
91
|
from its own request and passes it the same way.
|
|
87
92
|
|
|
93
|
+
On a static host, allow the early `/init` script by the hash in the browser's
|
|
94
|
+
`Refused to execute inline script` error. If the policy blocks it, the app
|
|
95
|
+
sends `/init` itself.
|
|
96
|
+
|
|
88
97
|
## Allow c15t's style elements
|
|
89
98
|
|
|
90
99
|
The banner, dialog and other stock components render c15t's rules as
|
|
@@ -65,6 +65,6 @@ Use focused hooks for feature gates. For a complete custom prompt or preference
|
|
|
65
65
|
center, use `useHeadlessConsentUI()` for surface actions and `useConsentDraft()`
|
|
66
66
|
for staged choices, inside one `ConsentDraftProvider` so the save commits the
|
|
67
67
|
same draft. v3 has no `useConsentManager()`; the
|
|
68
|
-
[
|
|
69
|
-
|
|
68
|
+
[`use-consent-manager-to-hooks` codemod](https://c15t.com/docs/cli/commands/codemods#migrate-useconsentmanager-to-v3-hooks)
|
|
69
|
+
rewrites most of its calls to hooks. Read [how consent works](../../concepts/how-consent-works.md#a-permission-is-not-a-recorded-choice) before
|
|
70
70
|
treating a callback as evidence of a choice.
|