@c15t/react 3.0.0-alpha.4 → 3.0.0-alpha.6
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 +8 -5
- package/dist/component-hooks/use-headless-consent-ui.js +1 -1
- package/dist/component-hooks/use-headless-iab-consent-ui.js +1 -1
- package/dist/components/iab-panel/atoms/vendor-list.js +1 -1
- package/dist/components/iab-panel/hooks/use-gvl-data.js +1 -1
- package/dist/components/iab-panel/index.js +1 -1
- package/dist/components/panel/index.js +1 -1
- package/dist/components/panel-trigger/atoms/toolbar.js +1 -1
- package/dist/components/panel-trigger/atoms/trigger-icons.js +1 -1
- package/dist/components/panel-trigger/panel-trigger.js +1 -1
- package/dist/components/preferences/atoms/accordion.js +1 -1
- package/dist/components/preferences/index.js +1 -1
- package/dist/components/shared/primitives/button.js +1 -1
- package/dist/components/shared/ui/accordion/accordion.js +1 -1
- package/dist/components/shared/ui/collapsible/collapsible.js +1 -1
- package/dist/components/shared/ui/preference-item/preference-item.js +1 -1
- package/dist/components/shared/ui/switch/switch.js +1 -1
- package/dist/components/shared/ui/tabs/tabs.js +1 -1
- package/dist/devtools-launcher.js +2 -0
- package/dist/devtools.js +1 -1
- package/dist/draft-context.js +2 -0
- package/dist/draft.js +1 -1
- package/dist/external-iab-context.js +1 -1
- package/dist/gpp.js +2 -0
- package/dist/hooks/use-color-scheme.js +1 -1
- package/dist/hooks/use-headless-iab-consent-ui.js +1 -1
- package/dist/hooks.js +1 -1
- package/dist/index-parts/consent-banner.js +1 -0
- package/dist/index-parts/consent-dialog-link.js +1 -0
- package/dist/index-parts/consent-dialog-trigger.js +1 -0
- package/dist/index-parts/consent-dialog.js +1 -0
- package/dist/index-parts/consent-gate.js +1 -0
- package/dist/index-parts/core.js +1 -0
- package/dist/index-parts/draft.js +1 -0
- package/dist/index-parts/hooks.js +1 -0
- package/dist/index-parts/module-hooks.js +1 -0
- package/dist/index-parts/provider.js +1 -0
- package/dist/index-parts/theme.js +1 -0
- package/dist/index-parts/translations.js +1 -0
- package/dist/index.js +1 -1
- package/dist/kernel-selector.js +1 -1
- package/dist/module-hooks/iframe-blocker.js +1 -1
- package/dist/provider.js +1 -1
- package/dist/styles.tw3.css +27 -3
- package/dist/version.js +1 -1
- package/dist-types/component-hooks/use-headless-consent-ui.d.ts +4 -4
- package/dist-types/components/iab-panel/index.d.ts +0 -1
- package/dist-types/components/panel/index.d.ts +0 -1
- package/dist-types/components/panel-trigger/atoms/trigger-icons.d.ts +5 -0
- package/dist-types/components/panel-trigger/panel-trigger.d.ts +0 -8
- package/dist-types/components/preferences/index.d.ts +0 -1
- package/dist-types/components/shared/ui/accordion/accordion.d.ts +0 -1
- package/dist-types/components/shared/ui/collapsible/collapsible.d.ts +0 -1
- package/dist-types/components/shared/ui/preference-item/preference-item.d.ts +0 -1
- package/dist-types/components/shared/ui/switch/switch.d.ts +0 -1
- package/dist-types/components/shared/ui/tabs/tabs.d.ts +0 -1
- package/dist-types/devtools-launcher.d.ts +29 -0
- package/dist-types/draft-context.d.ts +31 -0
- package/dist-types/draft.d.ts +13 -36
- package/dist-types/gpp.d.ts +27 -0
- package/dist-types/hooks/use-iab-manager.d.ts +4 -4
- package/dist-types/hooks.d.ts +30 -5
- package/dist-types/index-parts/consent-banner.d.ts +7 -0
- package/dist-types/index-parts/consent-dialog-link.d.ts +7 -0
- package/dist-types/index-parts/consent-dialog-trigger.d.ts +7 -0
- package/dist-types/index-parts/consent-dialog.d.ts +7 -0
- package/dist-types/index-parts/consent-gate.d.ts +7 -0
- package/dist-types/index-parts/core.d.ts +8 -0
- package/dist-types/index-parts/draft.d.ts +7 -0
- package/dist-types/index-parts/hooks.d.ts +7 -0
- package/dist-types/index-parts/module-hooks.d.ts +7 -0
- package/dist-types/index-parts/provider.d.ts +7 -0
- package/dist-types/index-parts/theme.d.ts +8 -0
- package/dist-types/index-parts/translations.d.ts +7 -0
- package/dist-types/index.d.ts +15 -16
- package/dist-types/kernel-selector.d.ts +0 -8
- package/dist-types/module-hooks/iframe-blocker.d.ts +12 -7
- package/dist-types/provider.d.ts +47 -13
- package/dist-types/version.d.ts +1 -1
- package/docs/README.md +8 -5
- package/docs/concepts/choose-your-setup.md +22 -5
- package/docs/concepts/consent-state.md +60 -5
- package/docs/concepts/data-fetching.md +34 -11
- package/docs/customization/recipes.md +4 -5
- package/docs/customization/slots.md +3 -2
- package/docs/customization/stylesheets.md +29 -39
- package/docs/customization/tailwind.md +5 -5
- package/docs/customization/tokens.md +1 -1
- package/docs/customization/translations.md +33 -7
- package/docs/frameworks/react/components/consent-dialog-trigger.md +5 -0
- package/docs/frameworks/react/components/consent-dialog.md +2 -1
- package/docs/frameworks/react/components/consent-provider.md +6 -2
- package/docs/frameworks/react/components/dev-tools.md +24 -1
- package/docs/frameworks/react/gpp.md +163 -0
- package/docs/frameworks/react/headless.md +4 -4
- package/docs/frameworks/react/hooks.md +10 -5
- package/docs/frameworks/react/iab.md +24 -18
- package/docs/frameworks/react/quickstart.md +77 -16
- package/docs/frameworks/react/rendering.md +82 -11
- package/docs/frameworks/react/scripts.md +8 -3
- package/docs/frameworks/react/upgrade-v3.md +596 -0
- package/docs/frameworks/react/vendor-consent.md +6 -0
- package/docs/guides/banner-experiments.md +26 -5
- package/docs/guides/troubleshooting.md +3 -2
- package/docs/integrations/overview.md +28 -27
- package/docs/integrations/posthog.md +99 -11
- package/docs/integrations/sentry.md +416 -0
- package/docs/upgrade-v3.md +222 -314
- package/package.json +13 -8
- package/dist/ui-save.js +0 -1
- package/dist-types/ui-save.d.ts +0 -25
|
@@ -12,7 +12,7 @@ to the alternatives it rules out.
|
|
|
12
12
|
|
|
13
13
|
| Your app | Setup | Guide |
|
|
14
14
|
| -------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
|
|
15
|
-
| Next.js App Router with a Next.js server | Server resolves consent from a
|
|
15
|
+
| Next.js App Router with a Next.js server | Server resolves consent from a build-time manifest and streams it to the page | [App Router](https://c15t.com/docs/frameworks/next/quickstart) |
|
|
16
16
|
| Next.js App Router, banner must be in the first HTML | Await consent inside `Suspense` | [Stream or await](https://c15t.com/docs/frameworks/next/rendering#stream-or-await-consent-in-the-app-router) |
|
|
17
17
|
| Next.js with static, ISR or `'use cache'` pages | Browser resolves consent on those pages | [Static, ISR and cached pages](https://c15t.com/docs/frameworks/next/rendering#render-static-isr-and-cached-pages) |
|
|
18
18
|
| Next.js Pages Router | Resolve consent in `getServerSideProps` | [Pages Router](https://c15t.com/docs/frameworks/next/rendering#pick-your-rendering-path) |
|
|
@@ -22,14 +22,14 @@ to the alternatives it rules out.
|
|
|
22
22
|
| TanStack Start in SPA mode or prerendered | Browser resolves consent | [TanStack Start rendering](https://c15t.com/docs/frameworks/tanstack-start/rendering#spa-mode-prerendered-pages-and-static-hosts) |
|
|
23
23
|
| React with Vite, or another single-page app | Browser resolves consent | [React](../frameworks/react/quickstart.md) |
|
|
24
24
|
| React Router framework mode, Remix, or another server-rendered React app | Browser resolves consent after hydration | [React rendering](../frameworks/react/rendering.md#react-router-remix-and-other-server-rendered-apps) |
|
|
25
|
-
| Nuxt with a Nuxt server | Nuxt module resolves consent on the server from a
|
|
25
|
+
| Nuxt with a Nuxt server | Nuxt module resolves consent on the server from a build-time manifest | [Nuxt](https://c15t.com/docs/frameworks/nuxt/quickstart) |
|
|
26
26
|
| Nuxt with prerendered or cached routes | Nuxt server for most pages, the browser on prerendered and cached routes | [Nuxt prerendered and cached routes](https://c15t.com/docs/frameworks/nuxt/rendering#prerendered-and-cached-routes) |
|
|
27
27
|
| Nuxt with `nuxt generate` on static hosting | Nuxt module, browser resolves consent from the manifest or `/init` | [Nuxt static hosting](https://c15t.com/docs/frameworks/nuxt/rendering#deploy-to-static-hosting) |
|
|
28
28
|
| Nuxt with `ssr: false` | Nuxt module, browser resolves consent from the manifest | [Nuxt single-page app](https://c15t.com/docs/frameworks/nuxt/rendering#build-a-single-page-app-with-ssr-false) |
|
|
29
29
|
| Vue with Vite | Vue plugin, browser resolves consent | [Vue](https://c15t.com/docs/frameworks/vue/quickstart) |
|
|
30
30
|
| Vue rendered on the server without Nuxt | Vue plugin; the banner mounts after hydration. Use Nuxt for the banner in server HTML. | [Vue rendering](https://c15t.com/docs/frameworks/vue/rendering#server-rendering-without-nuxt) |
|
|
31
31
|
| Astro with static output | Browser resolves consent through the hosted backend | [Astro static output](https://c15t.com/docs/frameworks/astro/rendering#static-output-with-hosted) |
|
|
32
|
-
| Astro with server output and an adapter | Middleware resolves consent from a
|
|
32
|
+
| Astro with server output and an adapter | Middleware resolves consent from a build-time manifest | [Astro server output](https://c15t.com/docs/frameworks/astro/rendering#server-output-with-manifest) |
|
|
33
33
|
| Svelte with Vite | Svelte provider, browser resolves consent | [Svelte](https://c15t.com/docs/frameworks/svelte/quickstart) |
|
|
34
34
|
| SvelteKit with a server | Root layout load resolves consent on the server | [SvelteKit](https://c15t.com/docs/frameworks/sveltekit/quickstart) |
|
|
35
35
|
| SvelteKit with `adapter-static`, prerendered pages or SPA mode | Browser resolves consent | [SvelteKit rendering](https://c15t.com/docs/frameworks/sveltekit/rendering#build-a-static-site) |
|
|
@@ -75,9 +75,26 @@ public policy manifest, never a response that contains a visitor's consent.
|
|
|
75
75
|
|
|
76
76
|
## How the server gets the policy
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
Use a build-time manifest as the default for supported production builds.
|
|
79
|
+
Next.js, TanStack Start, Nuxt server output, Astro server output and SvelteKit
|
|
80
|
+
can resolve requests from the deployment's snapshot. Vite apps can bundle it
|
|
81
|
+
for browser resolution too; location-based policies may still need a location
|
|
82
|
+
request. The framework quickstarts show the build hook and snapshot wiring.
|
|
79
83
|
|
|
80
|
-
|
|
84
|
+
The build fetches your public policy once and bundles it, so the server never
|
|
85
|
+
fetches it at runtime.
|
|
86
|
+
|
|
87
|
+
The snapshot is fixed at build time:
|
|
88
|
+
|
|
89
|
+
* Rebuild after changing policies, translations or vendors. If your CI caches
|
|
90
|
+
build output, force a fresh build.
|
|
91
|
+
* The build must reach the backend. A failed fetch fails the build.
|
|
92
|
+
* Consent choices still go to the backend.
|
|
93
|
+
|
|
94
|
+
For deployments that need policy updates without a rebuild, choose a runtime
|
|
95
|
+
path:
|
|
96
|
+
|
|
97
|
+
* **Cached manifest**.
|
|
81
98
|
Your server downloads the project's public policy file, caches it, and
|
|
82
99
|
resolves each visitor locally. Consent saves still go to the backend.
|
|
83
100
|
* **`/init`**. Each visit asks the backend to resolve the visitor. Simpler, but
|
|
@@ -27,12 +27,49 @@ itself stays refused: its `effectivePermissions` entry is `false`, and targets
|
|
|
27
27
|
that name only the category, or that also declare a consent purpose or special
|
|
28
28
|
feature, stay blocked.
|
|
29
29
|
|
|
30
|
+
## Categories under an IAB policy
|
|
31
|
+
|
|
32
|
+
Under an IAB policy the visitor chooses TCF purposes, and c15t derives each
|
|
33
|
+
category from them when the choice is saved. A category is granted when the
|
|
34
|
+
visitor consented to every purpose in it that a listed vendor processes on
|
|
35
|
+
consent:
|
|
36
|
+
|
|
37
|
+
| Category | TCF purposes |
|
|
38
|
+
| --------------- | ------------ |
|
|
39
|
+
| `marketing` | 2, 3, 4 |
|
|
40
|
+
| `measurement` | 7, 8, 9 |
|
|
41
|
+
| `experience` | 5, 6 |
|
|
42
|
+
| `functionality` | 10, 11 |
|
|
43
|
+
|
|
44
|
+
`necessary` is always granted. Purpose 1, device storage, decides no category.
|
|
45
|
+
|
|
46
|
+
Accept All consents only to the purposes and special features that the vendors
|
|
47
|
+
in your list declare, because the TCF Policies allow no consent signal for a
|
|
48
|
+
purpose the visitor was not shown. A category whose purposes no listed vendor
|
|
49
|
+
processes on consent therefore stays denied after Accept All, and so does every
|
|
50
|
+
script, iframe or network rule gated on it. With a vendor list whose vendors
|
|
51
|
+
declare only purposes 1 to 4 and 7, for example, `experience` and
|
|
52
|
+
`functionality` stay denied.
|
|
53
|
+
|
|
54
|
+
If your own scripts depend on such a category, do one of these:
|
|
55
|
+
|
|
56
|
+
* Declare the processing. Add a custom vendor for it, with the purposes it
|
|
57
|
+
uses, through the `customVendors` option of your IAB setup. The preference
|
|
58
|
+
centre then lists those purposes, and Accept All and the purpose switches
|
|
59
|
+
can grant the category.
|
|
60
|
+
* Gate the script on a category that your listed vendors' purposes cover, or on
|
|
61
|
+
`necessary` if it needs no consent.
|
|
62
|
+
|
|
63
|
+
Check `effectivePermissions` after Accept All on a fresh visit to see which
|
|
64
|
+
categories your vendor list leaves denied.
|
|
65
|
+
|
|
30
66
|
## When a choice is saved
|
|
31
67
|
|
|
32
68
|
A save records the choice in the browser first and sends it to the backend
|
|
33
69
|
afterwards. The stock banner, preference dialog and IAB surfaces in every
|
|
34
|
-
framework adapter, and the
|
|
35
|
-
and
|
|
70
|
+
framework adapter, and the `acceptAll()`, `rejectAll()` and `save()` methods
|
|
71
|
+
of the browser and Astro clients, close without waiting for the backend. In
|
|
72
|
+
order:
|
|
36
73
|
|
|
37
74
|
1. In the click task, the explicit choice and effective permissions change,
|
|
38
75
|
`onChoiceRecorded` and `onPermissionsChanged` run, gated scripts, iframes
|
|
@@ -52,9 +89,10 @@ and `save()`, close without waiting for the backend. In order:
|
|
|
52
89
|
|
|
53
90
|
A failed request does not reopen the surface or roll the choice back. The
|
|
54
91
|
kernel emits `command:error`, which reaches the `onError` callback in adapters
|
|
55
|
-
that accept one, and queues the payload in localStorage.
|
|
56
|
-
|
|
57
|
-
|
|
92
|
+
that accept one, and queues the payload in localStorage. Where localStorage is
|
|
93
|
+
unavailable, the queue lives in memory until the page unloads. The queue is
|
|
94
|
+
replayed after the next successful initialization and when the browser comes
|
|
95
|
+
back online, up to 10 attempts over 7 days. A replay carries the original action
|
|
58
96
|
time and policy snapshot token, so the backend records when the visitor
|
|
59
97
|
decided, and a duplicate submission resolves to the same consent record. A
|
|
60
98
|
backend that signs policy snapshot tokens rejects a replay made after the
|
|
@@ -66,6 +104,19 @@ after its TC string is encoded, which can wait for the TCF library to load.
|
|
|
66
104
|
If that local step records nothing, for example because the vendor list
|
|
67
105
|
failed to load, the surface comes back so the visitor can try again.
|
|
68
106
|
|
|
107
|
+
Every adapter leaves the same surface after a save: the banner while the
|
|
108
|
+
policy still owes a choice or a notice, and nothing once no prompt is owed,
|
|
109
|
+
while the policy is still loading, or after it failed to resolve. A banner
|
|
110
|
+
the visitor reopened closes too. A save that records nothing new, such as an
|
|
111
|
+
unchanged selection, closes the surface when it resolves successfully. Opening
|
|
112
|
+
or closing a surface, or starting another save, before then leaves the surface
|
|
113
|
+
as the visitor set it.
|
|
114
|
+
|
|
115
|
+
Closing the dialog without saving, with Escape or the adapter's close call,
|
|
116
|
+
leaves the same surface a save would. A visitor who opens preferences from the
|
|
117
|
+
banner and backs out still owes a choice, so the banner comes back. Once a
|
|
118
|
+
choice is recorded, closing the dialog leaves nothing open.
|
|
119
|
+
|
|
69
120
|
## Preserve records during hydration
|
|
70
121
|
|
|
71
122
|
Server helpers return records with policy information and evaluation time.
|
|
@@ -194,6 +245,10 @@ receive a stale TC string: c15t withdraws it, or holds it back, before
|
|
|
194
245
|
|
|
195
246
|
### Clearing records across tabs
|
|
196
247
|
|
|
248
|
+
`clearRecords()` also drops every save queued for replay, with or without
|
|
249
|
+
browser persistence, so nothing the visitor decided before the clear reaches
|
|
250
|
+
the backend afterwards.
|
|
251
|
+
|
|
197
252
|
`clearRecords()` removes every record and then stores the time of the clear,
|
|
198
253
|
the clear epoch, under its own key: `c15t-epoch` in localStorage and a cookie
|
|
199
254
|
of the same name (`<storageKey>-epoch` with a custom `storageKey`). Clearing
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Data fetching
|
|
3
|
-
description:
|
|
4
|
-
|
|
3
|
+
description: Choose the recommended build-time policy snapshot or runtime
|
|
4
|
+
manifest fetching, backend /init, browser resolution or offline rules, and
|
|
5
|
+
understand where consent choices are saved.
|
|
5
6
|
group: concepts
|
|
6
7
|
---
|
|
7
8
|
|
|
@@ -13,13 +14,14 @@ the same protocol, so every path below works with either. Only `offline()`
|
|
|
13
14
|
removes backend requests. For a recommendation by framework, start with
|
|
14
15
|
[choose your setup](./choose-your-setup.md).
|
|
15
16
|
|
|
16
|
-
| Fetching path
|
|
17
|
-
|
|
|
18
|
-
|
|
|
19
|
-
|
|
|
20
|
-
|
|
|
21
|
-
|
|
|
22
|
-
|
|
|
17
|
+
| Fetching path | Where policy resolves | Where choices are submitted | Choose it when |
|
|
18
|
+
| -------------------------------- | ------------------------------------------------------------------------------------- | --------------------------- | ------------------------------------------------------------------------------------------------------ |
|
|
19
|
+
| Build-time manifest, recommended | Your server or browser resolves a bundled policy snapshot with each visitor's inputs | Inth or your c15t backend | Your framework supports a build integration and policy changes can ship with a rebuild |
|
|
20
|
+
| Cached manifest on your server | Your application resolves public policy data with each request's location and signals | Inth or your c15t backend | Policy changes must reach the app without rebuilding, or builds cannot access the backend |
|
|
21
|
+
| Regular backend `/init` | The consent backend | The same backend | You want the fewest moving parts, need backend-owned request resolution, or have no application server |
|
|
22
|
+
| Manifest in the browser | The browser, using supplied or unknown location | Inth or your c15t backend | You deliberately want client resolution and have planned geography, bundle size and policy refresh |
|
|
23
|
+
| Offline | The browser or local runtime, using bundled rules | No backend submission | Local development and tests. Not recommended for production environments. |
|
|
24
|
+
| Custom transport | Your implementation | Your implementation | An existing service cannot use the c15t backend protocol |
|
|
23
25
|
|
|
24
26
|
## What is a consent manifest?
|
|
25
27
|
|
|
@@ -38,6 +40,24 @@ Do not put secrets, visitor identifiers or consent records into a manifest.
|
|
|
38
40
|
Keep personalized init responses out of shared caches. Changing a policy also
|
|
39
41
|
requires a refresh strategy for cached or build-time manifests.
|
|
40
42
|
|
|
43
|
+
## Use a build-time manifest by default
|
|
44
|
+
|
|
45
|
+
The build fetches your public policy once and bundles it, so the server never
|
|
46
|
+
fetches it at runtime.
|
|
47
|
+
|
|
48
|
+
The framework quickstarts include the build integration for supported
|
|
49
|
+
deployments. Server resolution uses the snapshot without an upstream manifest
|
|
50
|
+
request. Browser resolution includes the policy and resolver in the client
|
|
51
|
+
bundle, and may still request location for regional policies. Static Nuxt and
|
|
52
|
+
Astro sites and script-tag sites keep the runtime setup from their guides.
|
|
53
|
+
|
|
54
|
+
The snapshot is fixed at build time:
|
|
55
|
+
|
|
56
|
+
* Rebuild after changing policies, translations or vendors. If your CI caches
|
|
57
|
+
build output, force a fresh build.
|
|
58
|
+
* The build must reach the backend. A failed fetch fails the build.
|
|
59
|
+
* Consent choices still go to the backend.
|
|
60
|
+
|
|
41
61
|
## How manifest mode counts visitors
|
|
42
62
|
|
|
43
63
|
The backend counts visitors from `/init` requests, and manifest resolution
|
|
@@ -156,10 +176,13 @@ the kernel contract. Prefer a built-in transport when your backend supports it.
|
|
|
156
176
|
## Verify the selected path
|
|
157
177
|
|
|
158
178
|
Inspect browser and server requests separately. A server manifest fetch will
|
|
159
|
-
not appear in the browser's Network panel.
|
|
179
|
+
not appear in the browser's Network panel. With a build-time snapshot, start a
|
|
180
|
+
fresh production server and confirm it makes no upstream `/manifest` request.
|
|
181
|
+
After a policy edit, rebuild and confirm the new policy appears. On a runtime
|
|
182
|
+
manifest path, check that
|
|
160
183
|
page requests do not call the backend `/init`, a visitor's choice still reaches
|
|
161
184
|
the backend's `/subjects`, and policy changes become visible after the configured
|
|
162
|
-
refresh.
|
|
185
|
+
refresh. With a same-origin consent proxy, the browser should call only
|
|
163
186
|
`/api/c15t` paths for consent HTTP traffic; inspect server logs to verify their
|
|
164
187
|
upstream destinations.
|
|
165
188
|
|
|
@@ -517,8 +517,7 @@ from your Inth project, and put the block before `</body>`.
|
|
|
517
517
|
|
|
518
518
|
```html title="index.html"
|
|
519
519
|
<script
|
|
520
|
-
src="https://
|
|
521
|
-
data-backend-url="https://your-project.inth.app"
|
|
520
|
+
src="https://your-project.inth.app/c15t.headless.js"
|
|
522
521
|
defer
|
|
523
522
|
></script>
|
|
524
523
|
|
|
@@ -622,8 +621,8 @@ from your Inth project, and put the block before `</body>`.
|
|
|
622
621
|
hidden
|
|
623
622
|
>
|
|
624
623
|
<p class="cookie-bar__text">
|
|
625
|
-
We use cookies to measure traffic and improve this site. Choose which
|
|
626
|
-
can run.
|
|
624
|
+
We use cookies to measure traffic and improve this site. Choose which
|
|
625
|
+
ones can run.
|
|
627
626
|
</p>
|
|
628
627
|
<fieldset
|
|
629
628
|
class="cookie-bar__prefs"
|
|
@@ -867,5 +866,5 @@ The source repository renders each design in its Storybook under
|
|
|
867
866
|
`Docs / Banner designs`: `apps/storybook-react`, `apps/storybook-vue`,
|
|
868
867
|
`apps/storybook-svelte` and `apps/storybook-astro`. Each story uses an
|
|
869
868
|
in-memory policy and loads no analytics. The HTML headless bar runs at
|
|
870
|
-
`/consent-example/headless` in `
|
|
869
|
+
`/consent-example/headless` in `internals/fixtures/script-tag`, which the example
|
|
871
870
|
acceptance tests cover.
|
|
@@ -129,8 +129,9 @@ The widget is the list of categories inside the dialog. React and Vue call it
|
|
|
129
129
|
| Label | `trigger.text` | None |
|
|
130
130
|
| Toolbar, its items and icons | `trigger.toolbar`, `trigger.toolbarItem`, `trigger.toolbarIcon` | `consentDialogTriggerToolbar`, `consentDialogTriggerToolbarItem`, `consentDialogTriggerToolbarIcon` |
|
|
131
131
|
|
|
132
|
-
|
|
133
|
-
|
|
132
|
+
React renders the toolbar from `ConsentDialogTriggerToolbar`, and while
|
|
133
|
+
`ConsentDevTools` is mounted. Vue renders it only while `ConsentDevTools` is
|
|
134
|
+
mounted. In Astro, the toolbar slots reach the React dialog.
|
|
134
135
|
|
|
135
136
|
## Legal links and IAB TCF parts
|
|
136
137
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Stylesheets and CSS layers
|
|
3
|
-
description: Load the right c15t stylesheet for your framework, see
|
|
4
|
-
dialog's
|
|
5
|
-
without its styles.
|
|
3
|
+
description: Load the right c15t stylesheet for your framework, see which file
|
|
4
|
+
holds the dialog's rules, order c15t's cascade layer against your own, and run
|
|
5
|
+
c15t without its styles.
|
|
6
6
|
group: customization
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -26,32 +26,25 @@ when the integration sets `iab`. Tailwind 3 uses the same files and adds a
|
|
|
26
26
|
PostCSS plugin; [Tailwind CSS](./tailwind.md#set-up-tailwind-css-3)
|
|
27
27
|
shows the setup.
|
|
28
28
|
|
|
29
|
-
##
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
| Framework | The preference dialog's rules
|
|
37
|
-
| ------------------------------ |
|
|
38
|
-
| Next.js, TanStack Start, React |
|
|
39
|
-
| Nuxt, Vue | The dialog component imports its stylesheet, so the rules load with the dialog's code, not the banner's
|
|
40
|
-
| Astro | c15t
|
|
41
|
-
| Svelte, SvelteKit |
|
|
42
|
-
| HTML, JavaScript | Part of the stylesheet in the shadow root, which holds only the rules the stock surfaces use
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
`@c15t/
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
These modules import the stylesheet through `@c15t/ui/styles/dialog`. Under
|
|
50
|
-
the `node` export condition that module imports nothing, so server code that
|
|
51
|
-
loads `@c15t/react` with plain Node, such as the Pages Router or an SSR build
|
|
52
|
-
that keeps dependencies external, does not fail on the `.css` file. In your own
|
|
53
|
-
components, import `@c15t/ui/styles/dialog` rather than the `.css` file if the
|
|
54
|
-
module can run on the server.
|
|
29
|
+
## Where the dialog's rules come from
|
|
30
|
+
|
|
31
|
+
`styles.css` holds the default tokens, every c15t CSS variable and the rules
|
|
32
|
+
for every stock surface: the banner, the floating trigger, the `ConsentGate`
|
|
33
|
+
placeholder, the preference dialog and the preference widget. Only the IAB TCF
|
|
34
|
+
surfaces need a second file, `iab/styles.css`.
|
|
35
|
+
|
|
36
|
+
| Framework | The preference dialog's rules |
|
|
37
|
+
| ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
38
|
+
| Next.js, TanStack Start, React | In `styles.css`. No `@c15t/react` or `@c15t/ui` module imports CSS, so a Next.js app that uses only the Pages Router builds without `transpilePackages` |
|
|
39
|
+
| Nuxt, Vue | The dialog component imports its stylesheet, so the rules load with the dialog's code, not the banner's |
|
|
40
|
+
| Astro | In `c15t/astro/styles.css`. The Svelte dialog, the default `ui`, also needs the primitives stylesheet, which c15t links when a visitor first points at, focuses or opens a control that opens the dialog, and keeps across `ClientRouter` navigation |
|
|
41
|
+
| Svelte, SvelteKit | In `@c15t/svelte/styles.css` |
|
|
42
|
+
| HTML, JavaScript | Part of the stylesheet in the shadow root, which holds only the rules the stock surfaces use |
|
|
43
|
+
|
|
44
|
+
Earlier 3.0 alphas shipped the dialog's rules in `@c15t/ui/styles/dialog.css`,
|
|
45
|
+
which the dialog's code imported. That file, the `@c15t/ui/styles/dialog`
|
|
46
|
+
module and `c15t/astro/dialog.css` are now empty and stay only so existing
|
|
47
|
+
imports keep resolving. Remove those imports.
|
|
55
48
|
|
|
56
49
|
## Order c15t's layer against your CSS
|
|
57
50
|
|
|
@@ -78,11 +71,9 @@ What this means for your overrides:
|
|
|
78
71
|
[theme tokens](./tokens.md).
|
|
79
72
|
|
|
80
73
|
If your CSS declares its own layer order, load that statement before c15t's
|
|
81
|
-
stylesheet.
|
|
82
|
-
`@import 'c15t/react/styles.css' layer(c15t)
|
|
83
|
-
|
|
84
|
-
for example `@layer c15t, components, app;`, so it does not land after your
|
|
85
|
-
own layers.
|
|
74
|
+
stylesheet. You can import c15t's stylesheet into a named layer, such as
|
|
75
|
+
`@import 'c15t/react/styles.css' layer(c15t)`. Its component rules then sit
|
|
76
|
+
in `c15t.components`, so order `c15t` against your own layers.
|
|
86
77
|
|
|
87
78
|
## Load Astro's stylesheets yourself
|
|
88
79
|
|
|
@@ -90,12 +81,11 @@ The Astro integration adds `c15t/astro/styles.css` to every page ahead of your
|
|
|
90
81
|
own CSS. To control the order yourself, for example from a global stylesheet
|
|
91
82
|
that names its own layers, set `styles: false` in the `c15t()` options and
|
|
92
83
|
import the files after your layer order statement. With `styles: false`, c15t
|
|
93
|
-
links no
|
|
94
|
-
|
|
84
|
+
links no stylesheet when the dialog opens either. The Svelte dialog, the
|
|
85
|
+
default `ui`, needs the primitives stylesheet next to `styles.css`:
|
|
95
86
|
|
|
96
87
|
```css title="src/styles/global.css"
|
|
97
88
|
@import 'c15t/astro/styles.css';
|
|
98
|
-
@import 'c15t/astro/dialog.css';
|
|
99
89
|
/* Only with ui: 'svelte'. */
|
|
100
90
|
@import 'c15t/astro/primitives.css';
|
|
101
91
|
/* Only when the integration sets iab. */
|
|
@@ -141,7 +131,7 @@ selector before you reach for `noStyle`.
|
|
|
141
131
|
|
|
142
132
|
1. Open DevTools Network, clear site data and reload. Your framework's c15t
|
|
143
133
|
stylesheet loads once, and no second copy appears.
|
|
144
|
-
2. Open the preference dialog. It is styled on its first frame,
|
|
145
|
-
|
|
134
|
+
2. Open the preference dialog. It is styled on its first frame, and in React,
|
|
135
|
+
Next.js and TanStack Start no new stylesheet request appears.
|
|
146
136
|
3. Select a banner part and read the Styles panel. c15t's rules appear under
|
|
147
137
|
`@layer components`, and your unlayered rules for the same property win.
|
|
@@ -282,8 +282,8 @@ Make three changes:
|
|
|
282
282
|
3. Set `darkMode: 'class'` so Tailwind's `dark:` variant follows the same
|
|
283
283
|
`dark` class c15t reads.
|
|
284
284
|
|
|
285
|
-
The plugin also processes the stylesheets c15t loads for you, such as
|
|
286
|
-
|
|
285
|
+
The plugin also processes the stylesheets c15t loads for you, such as Astro's
|
|
286
|
+
injected one. Without it, Tailwind 3 stops
|
|
287
287
|
the build with "`@layer components` is used but no matching
|
|
288
288
|
`@tailwind components` directive is present", or purges c15t's rules, because
|
|
289
289
|
c15t's class names never appear in your source.
|
|
@@ -300,7 +300,7 @@ cannot edit your PostCSS config, it prints the step to do by hand. See
|
|
|
300
300
|
[setup](https://c15t.com/docs/cli/commands/setup#set-up-styles-and-tailwind-css).
|
|
301
301
|
|
|
302
302
|
Create React App ignores PostCSS config files, so Tailwind 3 cannot run the
|
|
303
|
-
plugin and the build fails on c15t's
|
|
303
|
+
plugin and the build fails on c15t's stylesheet. `c15t setup` warns
|
|
304
304
|
about this. Add the plugin before `tailwindcss` through CRACO, eject, or move
|
|
305
305
|
the app to Vite.
|
|
306
306
|
|
|
@@ -771,7 +771,7 @@ stylesheet, and the layer order keeps it above preflight:
|
|
|
771
771
|
|
|
772
772
|
```html title="light-dom.html"
|
|
773
773
|
<script
|
|
774
|
-
src="/c15t.js"
|
|
774
|
+
src="/c15t.offline.js"
|
|
775
775
|
data-mode="offline"
|
|
776
776
|
data-country="DE"
|
|
777
777
|
data-shadow="false"
|
|
@@ -793,7 +793,7 @@ instead:
|
|
|
793
793
|
window.c15t = [['config', { ui: { shadow: false, styles: false } }]];
|
|
794
794
|
</script>
|
|
795
795
|
<script
|
|
796
|
-
src="/c15t.js"
|
|
796
|
+
src="/c15t.offline.js"
|
|
797
797
|
data-mode="offline"
|
|
798
798
|
data-country="DE"
|
|
799
799
|
defer
|
|
@@ -101,7 +101,7 @@ easing tokens.
|
|
|
101
101
|
| `--c15t-text-on-primary` | `colors.textOnPrimary` | auto-derived from `colors.primary` when omitted |
|
|
102
102
|
| `--c15t-overlay` | `colors.overlay` | `hsla(0, 0%, 0%, 0.5)` |
|
|
103
103
|
| `--c15t-switch-track` | `colors.switchTrack` | `hsl(0, 0%, 85%)` |
|
|
104
|
-
| `--c15t-switch-track-active` | `colors.switchTrackActive` | `
|
|
104
|
+
| `--c15t-switch-track-active` | `colors.switchTrackActive` | `colors.primary` |
|
|
105
105
|
| `--c15t-switch-thumb` | `colors.switchThumb` | `hsl(0, 0%, 100%)` |
|
|
106
106
|
| `--c15t-font-family` | `typography.fontFamily` | `system-ui, -apple-system, sans-serif` |
|
|
107
107
|
| `--c15t-font-size-sm` | `typography.fontSize.sm` | `0.875rem` |
|
|
@@ -31,6 +31,33 @@ site-wide change. Astro's serializable integration options have their own
|
|
|
31
31
|
types, so verify that shape before copying a React object. The Vue plugin and
|
|
32
32
|
Nuxt module have no `i18n` option; their copy comes from the backend.
|
|
33
33
|
|
|
34
|
+
## Load only the languages you use
|
|
35
|
+
|
|
36
|
+
c15t bundles English. Every other language it ships is a separate entry point
|
|
37
|
+
in `@c15t/translations`, named by its language code. Importing one registers
|
|
38
|
+
c15t's built-in copy for that language. Offline mode can then switch to it,
|
|
39
|
+
and your messages that repeat its wording don't hide backend edits. Import
|
|
40
|
+
them in the file that configures the provider, so they load in the browser:
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
import '@c15t/translations/de';
|
|
44
|
+
import '@c15t/translations/fr';
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Each entry also exports that copy as `translations`, if you want to read a
|
|
48
|
+
string or build your messages from it:
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
import { translations as de } from '@c15t/translations/de';
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
The entries are `bg`, `cs`, `cy`, `da`, `de`, `el`, `es`, `et`, `fi`, `fr`,
|
|
55
|
+
`ga`, `gu`, `he`, `hi`, `hr`, `hu`, `id`, `is`, `it`, `lb`, `lt`, `lv`, `mt`,
|
|
56
|
+
`nb`, `nl`, `nn`, `pl`, `pt`, `rm`, `ro`, `sk`, `sl`, `sv` and `zh`.
|
|
57
|
+
`@c15t/translations/all` still loads every language at once. The `c15t`
|
|
58
|
+
package doesn't re-export these entries, so add `@c15t/translations` to your
|
|
59
|
+
dependencies.
|
|
60
|
+
|
|
34
61
|
## Combine messages with backend copy
|
|
35
62
|
|
|
36
63
|
With a backend or a manifest, the copy it sends for the visitor's language is
|
|
@@ -41,11 +68,11 @@ its primary language, so `de-AT` uses your `de` messages when there is no
|
|
|
41
68
|
`de-AT` entry. Messages for other languages are not applied.
|
|
42
69
|
|
|
43
70
|
A key only overrides the backend when your text differs from c15t's built-in
|
|
44
|
-
wording for that language. So passing
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
71
|
+
wording for that language. So passing a stock bundle to enable a language
|
|
72
|
+
keeps backend edits visible, while a key you actually reworded stays pinned
|
|
73
|
+
in code. c15t only recognizes the built-in wording of English and of the
|
|
74
|
+
languages you [import](#load-only-the-languages-you-use), such as
|
|
75
|
+
`@c15t/translations/de` or `@c15t/translations/all`.
|
|
49
76
|
|
|
50
77
|
## Write labels that describe the action
|
|
51
78
|
|
|
@@ -68,8 +95,7 @@ The `ConsentGate` placeholder reads the `consentGate` section:
|
|
|
68
95
|
| `consentGate.policyBlocked` | React and Vue show it in place of the title, with no button, when a strict policy leaves the category out of scope. |
|
|
69
96
|
|
|
70
97
|
Earlier versions called this section `frame`. Copy under `frame` in
|
|
71
|
-
`i18n.messages
|
|
72
|
-
still applies. c15t reads it as `consentGate`, a key set under `consentGate`
|
|
98
|
+
`i18n.messages` or custom translations still applies. c15t reads it as `consentGate`, a key set under `consentGate`
|
|
73
99
|
wins over the same key under `frame`, and c15t logs a warning once outside
|
|
74
100
|
production. Rename the section to `consentGate` to remove the warning.
|
|
75
101
|
|
|
@@ -112,6 +112,11 @@ nothing only when it has no visible item.
|
|
|
112
112
|
| `ariaLabel` | `string` | `'Privacy controls'` | Accessible name for the toolbar group. |
|
|
113
113
|
| `noStyle` | `boolean` | `false` | Remove the default styling. |
|
|
114
114
|
|
|
115
|
+
While `<ConsentDevTools>` is mounted, the toolbar adds a DevTools button at
|
|
116
|
+
the end farthest from its corner and opens the DevTools panel beside itself.
|
|
117
|
+
The ready-made `ConsentDialogTrigger` switches to this toolbar layout for as
|
|
118
|
+
long as DevTools is mounted.
|
|
119
|
+
|
|
115
120
|
### Toolbar styling
|
|
116
121
|
|
|
117
122
|
The toolbar follows the standard precedence: bundled styles, then provider slots, then direct `className` and `style` on the toolbar or on one action. Use `noStyle` for a fully custom implementation.
|
|
@@ -132,7 +132,8 @@ cached: the next hover, focus or open tries the download again.
|
|
|
132
132
|
The dialog's CSS travels in the same chunk and is applied before the dialog
|
|
133
133
|
renders, so your app's `styles.css` import stays small.
|
|
134
134
|
|
|
135
|
-
Without an `open` prop, Escape closes the dialog
|
|
135
|
+
Without an `open` prop, Escape closes the dialog without saving. If the
|
|
136
|
+
policy still owes a choice, the banner comes back. Save Settings, Accept All and
|
|
136
137
|
Reject All close it as soon as the choice is recorded in the browser, in
|
|
137
138
|
the same task as the click; the exit animation still plays. The request to
|
|
138
139
|
the backend runs afterwards and never reopens the dialog: a failed request
|
|
@@ -49,8 +49,12 @@ this provider and passes it server-resolved state.
|
|
|
49
49
|
## Provider options
|
|
50
50
|
|
|
51
51
|
Keep the provider mounted across client navigation. It reads `mode`,
|
|
52
|
-
`prefetch`, `persistence`, `clearOnRevocation` and
|
|
53
|
-
when it mounts.
|
|
52
|
+
`prefetch`, `persistence`, `storageConfig`, `clearOnRevocation`, `i18n` and
|
|
53
|
+
`experiment` once, when it mounts. Outside production, changing `mode`,
|
|
54
|
+
`i18n`, `experiment`, `persistence` or `storageConfig` logs a warning. Remount
|
|
55
|
+
the provider to change them. `scripts`, `vendors`, `networkBlocker`,
|
|
56
|
+
`iframeBlocker`, `consentCategories`, `overrides`, `user`, `callbacks` and
|
|
57
|
+
`enabled` apply when they change.
|
|
54
58
|
|
|
55
59
|
| Option | Purpose |
|
|
56
60
|
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
|
|
@@ -76,6 +76,29 @@ panel renders inside a shadow root by default, so page CSS does not reach
|
|
|
76
76
|
it. `shadow={false}` mounts it in the light DOM with its stylesheet in
|
|
77
77
|
`<head>`.
|
|
78
78
|
|
|
79
|
+
## Open DevTools from the consent trigger
|
|
80
|
+
|
|
81
|
+
While `ConsentDialogTriggerToolbar` or the ready-made `ConsentDialogTrigger`
|
|
82
|
+
is visible, the trigger shows a DevTools button and DevTools hides its own
|
|
83
|
+
floating launcher, so one control occupies the corner. The button sits at the
|
|
84
|
+
end of the toolbar farthest from its corner. The panel opens just past the
|
|
85
|
+
toolbar, aligned with its outer edge, and follows it when a visitor drags the
|
|
86
|
+
toolbar to another corner. `position` applies again once no trigger is
|
|
87
|
+
visible.
|
|
88
|
+
|
|
89
|
+
`ConsentDialogTrigger` becomes a two-button toolbar while DevTools is
|
|
90
|
+
mounted. A trigger composed from `ConsentDialogTrigger.Root` keeps its own
|
|
91
|
+
markup, and DevTools keeps its floating launcher beside it.
|
|
92
|
+
|
|
93
|
+
DevTools brings its launcher back whenever no trigger is visible, for example
|
|
94
|
+
while `showWhen="after-prompt"` waits for a choice. A production build that
|
|
95
|
+
loads DevTools only in development shows no DevTools button in the trigger.
|
|
96
|
+
|
|
97
|
+
With the imperative engine, call `devTools.dock({ position, inline, block })`
|
|
98
|
+
to hide the launcher and anchor the panel `inline` and `block` pixels from the
|
|
99
|
+
viewport edges of `position`'s corner. Call `devTools.dock(null)` to restore
|
|
100
|
+
the launcher.
|
|
101
|
+
|
|
79
102
|
## Panels
|
|
80
103
|
|
|
81
104
|
Accept and reject apply only to categories displayed by the provider, leaving
|
|
@@ -95,7 +118,7 @@ explicit scope or policy categories, bulk saves cover all known categories.
|
|
|
95
118
|
| ------------ | -------------------------------------------------------------------------------------------- |
|
|
96
119
|
| **Consents** | Inspect and save categories, accept all, or reject optional categories |
|
|
97
120
|
| **Scripts** | Configured scripts, loading status, search, and external page resources |
|
|
98
|
-
| **Location** |
|
|
121
|
+
| **Location** | Resolved country and region, and location overrides |
|
|
99
122
|
| **Policy** | Resolved policy and UI configuration |
|
|
100
123
|
| **IAB** | Edit vendors, purposes, legitimate interests, and special features; save and copy TC strings |
|
|
101
124
|
| **Events** | Timeline of consent changes, kernel events, and script lifecycle events |
|