@c15t/react 3.0.0-alpha.8 → 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 +10 -12
- 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/prompt/prompt.js +1 -1
- package/dist/components/shared/dialog-sheets.js +1 -0
- package/dist/components/shared/first-paint-sheets.js +1 -0
- package/dist/components/shared/iab-dialog-sheets.js +1 -0
- package/dist/components/shared/iab-first-paint-sheets.js +1 -0
- package/dist/components/shared/primitives/button.js +1 -1
- package/dist/components/shared/surface-styles.js +2 -0
- package/dist/consent-gate.js +1 -1
- package/dist/context/index.js +1 -1
- package/dist/devtools.js +1 -1
- package/dist/hooks/use-iab-policy-guard.js +1 -0
- package/dist/iab/styles.tw3.css +2 -2
- package/dist/iab-context.js +1 -1
- 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/dialog-sheets.d.ts +9 -0
- package/dist-types/components/shared/first-paint-sheets.d.ts +8 -0
- package/dist-types/components/shared/iab-dialog-sheets.d.ts +3 -0
- package/dist-types/components/shared/iab-first-paint-sheets.d.ts +3 -0
- package/dist-types/components/shared/surface-styles.d.ts +60 -0
- 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/hooks/use-iab-policy-guard.d.ts +35 -0
- 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 +22 -4
- package/dist-types/transports/hosted.d.ts +36 -0
- package/dist-types/transports/manifest.d.ts +48 -0
- package/dist-types/ui-config-context.d.ts +4 -0
- package/dist-types/version.d.ts +1 -1
- package/docs/README.md +10 -12
- package/docs/concepts/choose-your-setup.md +45 -8
- package/docs/concepts/consent-categories.md +1 -1
- package/docs/concepts/consent-state.md +5 -2
- package/docs/concepts/data-fetching.md +100 -40
- 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/overview.md +3 -2
- package/docs/customization/recipes.md +4 -4
- package/docs/customization/slots.md +25 -25
- package/docs/customization/stylesheets.md +161 -50
- package/docs/customization/tailwind.md +71 -50
- package/docs/customization/tokens.md +42 -13
- package/docs/frameworks/react/components/consent-banner.md +14 -12
- package/docs/frameworks/react/components/consent-dialog.md +15 -13
- package/docs/frameworks/react/components/consent-provider.md +51 -46
- package/docs/frameworks/react/components.md +16 -13
- package/docs/frameworks/react/compose.md +3 -3
- package/docs/frameworks/react/content-security-policy.md +35 -12
- package/docs/frameworks/react/customize.md +21 -13
- package/docs/frameworks/react/hooks.md +2 -2
- package/docs/frameworks/react/iab.md +56 -6
- package/docs/frameworks/react/quickstart.md +65 -99
- package/docs/frameworks/react/rendering.md +170 -94
- package/docs/frameworks/react/scripts.md +19 -30
- package/docs/frameworks/react/troubleshooting.md +100 -32
- package/docs/frameworks/react/upgrade-v3.md +133 -79
- package/docs/frameworks/react/vendor-consent.md +19 -7
- package/docs/guides/banner-experiments.md +21 -8
- package/docs/guides/troubleshooting.md +90 -26
- 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
|
@@ -1,45 +1,143 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Stylesheets and CSS layers
|
|
3
|
-
description:
|
|
4
|
-
|
|
5
|
-
c15t
|
|
3
|
+
description: See how c15t delivers its styles in each framework without a
|
|
4
|
+
render-blocking stylesheet, when to import styles.css yourself with styles
|
|
5
|
+
false, which file holds the dialog's rules, and how c15t's cascade layer meets
|
|
6
|
+
your own.
|
|
6
7
|
group: customization
|
|
7
8
|
---
|
|
8
9
|
|
|
9
|
-
##
|
|
10
|
-
|
|
11
|
-
| Framework
|
|
12
|
-
|
|
|
13
|
-
| Next.js
|
|
14
|
-
|
|
|
15
|
-
|
|
|
16
|
-
|
|
|
17
|
-
|
|
|
18
|
-
|
|
|
19
|
-
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
10
|
+
## What each framework loads
|
|
11
|
+
|
|
12
|
+
| Framework | What you import | How the styles arrive |
|
|
13
|
+
| ------------------------------ | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
14
|
+
| Next.js, TanStack Start, React | Nothing | Each stock surface renders the rules it uses as `<style>` elements |
|
|
15
|
+
| Nuxt, Vue | Nothing | Each Vue component imports its own stylesheet |
|
|
16
|
+
| Astro | Nothing | `<ConsentScript />` inlines the banner's rules into the HTML. The client links the dialog's rules when a dialog first opens. On a Tailwind CSS 3 site, the integration adds `c15t/astro/styles.css` to every page instead |
|
|
17
|
+
| Svelte | Nothing | Each stock surface inserts the rules it uses into `<head>` |
|
|
18
|
+
| SvelteKit | Nothing | `c15tHandle` writes a server-rendered banner's rules into the HTML. The other surfaces insert theirs in the browser |
|
|
19
|
+
| HTML | Nothing | `c15t.js` carries its stylesheet into the UI's shadow root |
|
|
20
|
+
| JavaScript | Nothing | `init()` carries its stylesheet into the UI's shadow root |
|
|
21
|
+
|
|
22
|
+
Inline c15t styles avoid a stylesheet request before the page's first paint.
|
|
23
|
+
A linked stylesheet in `<head>` used to delay it by a round trip. With 4x
|
|
24
|
+
CPU throttling, 1.6 Mbps download and 150 ms RTT, a Next.js page first painted
|
|
25
|
+
at about 370 ms instead of 650 ms once the link was gone.
|
|
26
|
+
|
|
27
|
+
Inline rules add bytes to each server-rendered HTML response. Enable HTTP
|
|
28
|
+
compression on the production host to reduce their transfer cost. On repeat
|
|
29
|
+
document visits, a cached external stylesheet can paint sooner than sending
|
|
30
|
+
the inline rules again. To use that cache, keep the stylesheet imports and
|
|
31
|
+
set `styles: false` as described below.
|
|
32
|
+
|
|
33
|
+
Load `styles.css` yourself with Tailwind CSS 3 or a named cascade layer.
|
|
34
|
+
[Import the stylesheet yourself](#import-the-stylesheet-yourself)
|
|
35
|
+
covers those cases.
|
|
36
|
+
|
|
37
|
+
## How the surfaces deliver their rules
|
|
38
|
+
|
|
39
|
+
c15t splits its rules into two sheets. The first-paint sheet holds the
|
|
40
|
+
default tokens, every c15t CSS variable, and the rules for the banner, the
|
|
41
|
+
floating trigger and the `ConsentGate` placeholder. The dialog sheet holds the
|
|
42
|
+
preference dialog's and the preference widget's rules.
|
|
43
|
+
|
|
44
|
+
In React, Next.js and TanStack Start, `ConsentBanner`, `ConsentDialogTrigger`
|
|
45
|
+
and the default `ConsentGate` placeholder render the first-paint sheet.
|
|
46
|
+
`ConsentDialog` and `ConsentWidget` render it plus the dialog sheet. The
|
|
47
|
+
dialog sheet ships with the dialog's lazily loaded code, so it is not part of
|
|
48
|
+
the first page load. A server-rendered banner puts its rules in the HTML.
|
|
49
|
+
|
|
50
|
+
`IABConsentBanner` also delivers the IAB variables and banner rules.
|
|
51
|
+
`IABConsentDialog` adds the IAB dialog rules when it opens, including the
|
|
52
|
+
shared rules it needs when rendered without a banner. IAB setups need no
|
|
53
|
+
stylesheet imports with automatic styling enabled.
|
|
54
|
+
|
|
55
|
+
Streamed React IAB banners become visible once their complete card markup
|
|
56
|
+
arrives. This prevents the centered card from moving as the browser parses
|
|
57
|
+
its remaining content, without waiting for hydration.
|
|
58
|
+
|
|
59
|
+
* In React 19, React moves the elements into `<head>` and renders each sheet
|
|
60
|
+
once per page, as `<style data-precedence="c15t" data-href="c15t-first-paint">`.
|
|
61
|
+
* In React 18, the elements render in place, next to the surface.
|
|
62
|
+
* In React 19 with the provider's `nonce` option set, they also render in
|
|
63
|
+
place and carry the nonce. React drops the nonce of a style it moves to
|
|
64
|
+
`<head>` unless the app passed that nonce to React's server renderer.
|
|
65
|
+
|
|
66
|
+
In Svelte, each stock surface inserts the sheets it uses into `<head>` as
|
|
67
|
+
`<style data-c15t-styles="…">`, once per page, before its own elements
|
|
68
|
+
render. The elements stay after the surface unmounts. The Svelte dialog's
|
|
69
|
+
sheets, its rules and the primitives, load with the dialog's code.
|
|
70
|
+
|
|
71
|
+
On a server-rendered SvelteKit page, the banner leaves a
|
|
72
|
+
`<meta name="c15t-styles">` marker, and `c15tHandle` from `@c15t/svelte/kit`
|
|
73
|
+
writes the sheets into the HTML `<head>` as `<style>` elements. The banner is
|
|
74
|
+
styled before hydration with no stylesheet request. Without `c15tHandle` in
|
|
75
|
+
`src/hooks.server.ts`, a server-rendered banner shows unstyled until
|
|
76
|
+
hydration. The [SvelteKit quickstart](https://c15t.com/docs/frameworks/sveltekit/quickstart)
|
|
77
|
+
adds the handle.
|
|
78
|
+
|
|
79
|
+
In Astro, `<ConsentScript />`, or the banner on a layout without it, inlines
|
|
80
|
+
the first-paint sheet into the HTML as
|
|
81
|
+
`<style data-c15t-styles="c15t-first-paint">` with the page nonce. When
|
|
82
|
+
`tailwindcss` resolves to version 3 from the Astro root, the integration
|
|
83
|
+
inlines nothing and adds `c15t/astro/styles.css` to every page through
|
|
84
|
+
Astro's CSS pipeline, so the site's `c15t/postcss-tailwind3` plugin processes
|
|
85
|
+
it. That stylesheet still holds back the first paint.
|
|
86
|
+
|
|
87
|
+
The surfaces render no stylesheet with `noStyle`, or when the provider sets
|
|
88
|
+
`styles: false`.
|
|
89
|
+
|
|
90
|
+
## Import the stylesheet yourself
|
|
91
|
+
|
|
92
|
+
Set `styles: false` in the provider options and import `styles.css` when you
|
|
93
|
+
need control over the file:
|
|
94
|
+
|
|
95
|
+
* **Tailwind CSS 3.** c15t's `<style>` rules sit in a native
|
|
96
|
+
`@layer components`, and Tailwind 3's unlayered preflight beats them. Import
|
|
97
|
+
`styles.css` through the `postcss-tailwind3` plugin instead, as
|
|
98
|
+
[Tailwind CSS](./tailwind.md#set-up-tailwind-css-3) shows.
|
|
99
|
+
Astro sites skip this: the integration detects Tailwind 3 and links the
|
|
100
|
+
stylesheet itself.
|
|
101
|
+
* **A named cascade layer.** Import the stylesheet into your own layer, as in
|
|
102
|
+
[order c15t's layer against your CSS](#order-c15ts-layer-against-your-css).
|
|
103
|
+
* **Cached styles across document visits.** Keep external CSS when its HTTP
|
|
104
|
+
cache performs better for your site's repeat visits. Compare cold and warm
|
|
105
|
+
visits on your production host before choosing this option.
|
|
106
|
+
|
|
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 } });
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
`styles: false` turns off only the stylesheets. Tokens from `ConsentTheme`
|
|
122
|
+
and slot classes still apply.
|
|
123
|
+
|
|
124
|
+
If you keep a `styles.css` import without `styles: false`, the surfaces still
|
|
125
|
+
look right, but the rules ship twice and the stylesheet link still holds back
|
|
126
|
+
the first paint. Remove the import, or add `styles: false` if you need it.
|
|
28
127
|
|
|
29
128
|
## Where the dialog's rules come from
|
|
30
129
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
130
|
+
| Framework | The preference dialog's rules |
|
|
131
|
+
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
132
|
+
| Next.js, TanStack Start, React | In the dialog sheet that `ConsentDialog` and `ConsentWidget` render. It ships with the dialog's lazily loaded code. With `styles: false`, 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` |
|
|
133
|
+
| Nuxt, Vue | The dialog component imports its stylesheet, so the rules load with the dialog's code, not the banner's |
|
|
134
|
+
| Astro | In `@c15t/ui/styles/sheets/dialog.css`. The Svelte dialog, the default `ui`, also needs the primitives stylesheet. c15t links both when a visitor first points at, focuses or opens a control that opens the dialog, waits for them before it shows the dialog, and keeps them across `ClientRouter` navigation. On a Tailwind CSS 3 site, the dialog's rules are in `c15t/astro/styles.css`, and c15t links only the primitives stylesheet |
|
|
135
|
+
| Svelte, SvelteKit | In the dialog's sheets, which load with the dialog's code. With `styles: false`, in `@c15t/svelte/styles.css` |
|
|
136
|
+
| HTML, JavaScript | Part of the stylesheet in the shadow root, which holds only the rules the stock surfaces use |
|
|
35
137
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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 |
|
|
138
|
+
`styles.css` still holds every stock surface's rules for apps that set
|
|
139
|
+
`styles: false`. In that manual mode, IAB TCF also needs `iab/styles.css`
|
|
140
|
+
after the base stylesheet.
|
|
43
141
|
|
|
44
142
|
Earlier 3.0 alphas shipped the dialog's rules in `@c15t/ui/styles/dialog.css`,
|
|
45
143
|
which the dialog's code imported. That file, the `@c15t/ui/styles/dialog`
|
|
@@ -49,8 +147,8 @@ imports keep resolving. Remove those imports.
|
|
|
49
147
|
## Order c15t's layer against your CSS
|
|
50
148
|
|
|
51
149
|
c15t puts its component rules in the cascade layer `components`. Tokens,
|
|
52
|
-
variables and keyframes stay unlayered. Each stylesheet
|
|
53
|
-
CSS 4's layer order:
|
|
150
|
+
variables and keyframes stay unlayered. Each stylesheet, and each `<style>`
|
|
151
|
+
element the surfaces render, opens with Tailwind CSS 4's layer order:
|
|
54
152
|
|
|
55
153
|
```css
|
|
56
154
|
@layer properties, theme, base, components, utilities;
|
|
@@ -71,18 +169,23 @@ What this means for your overrides:
|
|
|
71
169
|
[theme tokens](./tokens.md).
|
|
72
170
|
|
|
73
171
|
If your CSS declares its own layer order, load that statement before c15t's
|
|
74
|
-
|
|
172
|
+
rules. To put c15t's rules in a named layer, set `styles: false` and import
|
|
173
|
+
the stylesheet into that layer, such as
|
|
75
174
|
`@import 'c15t/react/styles.css' layer(c15t)`. Its component rules then sit
|
|
76
175
|
in `c15t.components`, so order `c15t` against your own layers.
|
|
77
176
|
|
|
78
177
|
## Load Astro's stylesheets yourself
|
|
79
178
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
179
|
+
By default the Astro integration inlines the banner's rules into each page,
|
|
180
|
+
including the IAB banner rules when it sets `iab`, and links the dialog's
|
|
181
|
+
rules when a dialog opens. On a Tailwind CSS 3 site it adds
|
|
182
|
+
`c15t/astro/styles.css` and, with IAB, `c15t/astro/iab/styles.css` to every
|
|
183
|
+
page instead of inlining the banner's rules. To load the
|
|
184
|
+
files yourself, for example from a global stylesheet that names its own
|
|
185
|
+
layers, set `styles: false` in the `c15t()` options and import them after
|
|
186
|
+
your layer order statement. With `styles: false`, c15t inlines no rules and
|
|
187
|
+
links no stylesheet when the dialog opens. The Svelte dialog, the default
|
|
188
|
+
`ui`, needs the primitives stylesheet next to `styles.css`:
|
|
86
189
|
|
|
87
190
|
```css title="src/styles/global.css"
|
|
88
191
|
@import 'c15t/astro/styles.css';
|
|
@@ -92,9 +195,9 @@ default `ui`, needs the primitives stylesheet next to `styles.css`:
|
|
|
92
195
|
@import 'c15t/astro/iab/styles.css';
|
|
93
196
|
```
|
|
94
197
|
|
|
95
|
-
Keep c15t's
|
|
96
|
-
|
|
97
|
-
|
|
198
|
+
Keep c15t's rules when you restyle the surfaces. The browser hides the Astro
|
|
199
|
+
banner with the `hidden` attribute, and c15t's rules make that attribute beat
|
|
200
|
+
the banner's own `display` rule.
|
|
98
201
|
|
|
99
202
|
## Style the script tag's shadow root
|
|
100
203
|
|
|
@@ -129,9 +232,17 @@ selector before you reach for `noStyle`.
|
|
|
129
232
|
|
|
130
233
|
## Check the result
|
|
131
234
|
|
|
132
|
-
1. Open DevTools Network, clear site data and reload.
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
235
|
+
1. Open DevTools Network, clear site data and reload. No c15t stylesheet
|
|
236
|
+
request appears before the first paint. In the HTML or the Elements panel,
|
|
237
|
+
`<head>` holds c15t's rules: `<style data-href="c15t-first-paint">` in
|
|
238
|
+
React 19, or a `<style data-c15t-styles>` element in Svelte, SvelteKit
|
|
239
|
+
and Astro. In React 18, or with a `nonce`, the `<style>` sits next to the
|
|
240
|
+
banner instead.
|
|
241
|
+
2. Open the preference dialog. It is styled on its first frame. Opening it
|
|
242
|
+
adds the dialog's rules: a second `<style>` element in React, Next.js,
|
|
243
|
+
TanStack Start, Svelte and SvelteKit, or a linked
|
|
244
|
+
`@c15t/ui/styles/sheets/dialog.css` in Astro.
|
|
245
|
+
3. With `styles: false`, your imported `styles.css` loads once, and no c15t
|
|
246
|
+
`<style>` element appears.
|
|
247
|
+
4. Select a banner part and read the Styles panel. c15t's rules appear under
|
|
137
248
|
`@layer components`, and your unlayered rules for the same property win.
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Tailwind CSS
|
|
3
|
-
description:
|
|
4
|
-
|
|
5
|
-
c15t.
|
|
3
|
+
description: Use c15t's styles with Tailwind CSS 4 or 3 in every framework, put
|
|
4
|
+
utilities on c15t component parts, and use Tailwind's dark variant with c15t.
|
|
6
5
|
group: customization
|
|
7
6
|
---
|
|
8
7
|
|
|
@@ -21,7 +20,10 @@ directive and fails the build on a stylesheet that uses it without a matching
|
|
|
21
20
|
`@tailwind components`. c15t's Tailwind 3 PostCSS plugin removes the layer
|
|
22
21
|
wrappers from c15t's stylesheets before Tailwind 3 runs. c15t's rules then
|
|
23
22
|
win by specificity, as they did in c15t v2, so a utility on a c15t part needs
|
|
24
|
-
Tailwind's important modifier, such as `!p-2`.
|
|
23
|
+
Tailwind's important modifier, such as `!p-2`. The plugin cannot reach the
|
|
24
|
+
`<style>` elements c15t renders itself, so on Tailwind 3 you turn those off
|
|
25
|
+
with `styles: false` and import the stylesheet instead. The Astro integration
|
|
26
|
+
does this for you when it finds Tailwind 3.
|
|
25
27
|
|
|
26
28
|
The setups below come from fixtures that CI builds for each framework and
|
|
27
29
|
checks in Chromium. The Next.js snippets come from the Next.js 16 Turbopack
|
|
@@ -34,9 +36,11 @@ without a backend, so they use `offline()` mode or a local `backendURL`. Keep th
|
|
|
34
36
|
|
|
35
37
|
## Set up Tailwind CSS 4
|
|
36
38
|
|
|
37
|
-
Install Tailwind's plugin for your build tool
|
|
38
|
-
|
|
39
|
-
c15t's
|
|
39
|
+
Install Tailwind's plugin for your build tool and add it to the build. c15t
|
|
40
|
+
loads its own styles in every framework, so your CSS entry holds only
|
|
41
|
+
Tailwind. Do not import c15t's stylesheet next to Tailwind 4: the stock
|
|
42
|
+
components already render the same rules, and the import would hold back the
|
|
43
|
+
first paint.
|
|
40
44
|
|
|
41
45
|
**Next.js**
|
|
42
46
|
|
|
@@ -46,20 +50,18 @@ Next.js runs Tailwind 4 through `@tailwindcss/postcss`:
|
|
|
46
50
|
export default { plugins: { '@tailwindcss/postcss': {} } };
|
|
47
51
|
```
|
|
48
52
|
|
|
49
|
-
Import
|
|
50
|
-
|
|
53
|
+
Import Tailwind in the global stylesheet that `app/layout.tsx` or
|
|
54
|
+
`pages/_app.tsx` loads:
|
|
51
55
|
|
|
52
56
|
```css title="app/globals.css"
|
|
53
57
|
@import 'tailwindcss';
|
|
54
|
-
@import 'c15t/next/styles.css';
|
|
55
58
|
|
|
56
59
|
@custom-variant dark (&:where(.dark, .dark *));
|
|
57
60
|
```
|
|
58
61
|
|
|
59
62
|
**TanStack Start**
|
|
60
63
|
|
|
61
|
-
Add `@tailwindcss/vite` before the TanStack Start plugin
|
|
62
|
-
Tailwind and c15t from the stylesheet your root route links:
|
|
64
|
+
Add `@tailwindcss/vite` before the TanStack Start plugin:
|
|
63
65
|
|
|
64
66
|
```ts title="vite.config.ts"
|
|
65
67
|
import tailwindcss from '@tailwindcss/vite';
|
|
@@ -76,11 +78,10 @@ export default defineConfig({
|
|
|
76
78
|
});
|
|
77
79
|
```
|
|
78
80
|
|
|
79
|
-
Import Tailwind
|
|
81
|
+
Import Tailwind from the stylesheet your root route links:
|
|
80
82
|
|
|
81
83
|
```css title="src/styles.css"
|
|
82
84
|
@import 'tailwindcss';
|
|
83
|
-
@import 'c15t/tanstack-start/styles.css';
|
|
84
85
|
|
|
85
86
|
@custom-variant dark (&:where(.dark, .dark *));
|
|
86
87
|
```
|
|
@@ -95,12 +96,10 @@ import { defineConfig } from 'vite';
|
|
|
95
96
|
export default defineConfig({ plugins: [react(), tailwindcss()] });
|
|
96
97
|
```
|
|
97
98
|
|
|
98
|
-
Import this stylesheet from your entry module
|
|
99
|
-
`c15t/react/styles.css` import:
|
|
99
|
+
Import this stylesheet from your entry module:
|
|
100
100
|
|
|
101
101
|
```css title="src/app.css"
|
|
102
102
|
@import 'tailwindcss';
|
|
103
|
-
@import 'c15t/react/styles.css';
|
|
104
103
|
|
|
105
104
|
@custom-variant dark (&:where(.dark, .dark *));
|
|
106
105
|
```
|
|
@@ -112,9 +111,10 @@ Add `@tailwindcss/vite` under `vite.plugins` and list your CSS entry in
|
|
|
112
111
|
|
|
113
112
|
```ts title="nuxt.config.ts"
|
|
114
113
|
import tailwindcss from '@tailwindcss/vite';
|
|
114
|
+
import { hosted } from 'c15t/vue';
|
|
115
115
|
|
|
116
116
|
export default defineNuxtConfig({
|
|
117
|
-
c15t: { backendURL: '/api/c15t' },
|
|
117
|
+
c15t: { backendURL: '/api/c15t', mode: hosted() },
|
|
118
118
|
compatibilityDate: '2026-07-04',
|
|
119
119
|
css: ['~/assets/css/main.css'],
|
|
120
120
|
modules: ['c15t/vue'],
|
|
@@ -139,10 +139,12 @@ Tailwind:
|
|
|
139
139
|
```ts title="vite.config.ts"
|
|
140
140
|
import tailwindcss from '@tailwindcss/vite';
|
|
141
141
|
import vue from '@vitejs/plugin-vue';
|
|
142
|
-
import
|
|
142
|
+
import { consentManifest } from 'c15t/vue/vite';
|
|
143
143
|
import { defineConfig } from 'vite';
|
|
144
144
|
|
|
145
|
-
export default defineConfig({
|
|
145
|
+
export default defineConfig({
|
|
146
|
+
plugins: [vue(), consentManifest({ backendURL: '/api/c15t' }), tailwindcss()],
|
|
147
|
+
});
|
|
146
148
|
```
|
|
147
149
|
|
|
148
150
|
Import this stylesheet from `src/main.ts`:
|
|
@@ -155,8 +157,9 @@ Import this stylesheet from `src/main.ts`:
|
|
|
155
157
|
|
|
156
158
|
**Astro**
|
|
157
159
|
|
|
158
|
-
|
|
159
|
-
entry holds only Tailwind. Add
|
|
160
|
+
c15t inlines the banner's rules into each page and links the dialog's
|
|
161
|
+
when it opens, so the CSS entry holds only Tailwind. Add
|
|
162
|
+
`@tailwindcss/vite` under `vite.plugins`:
|
|
160
163
|
|
|
161
164
|
```js title="astro.config.mjs"
|
|
162
165
|
import svelte from '@astrojs/svelte';
|
|
@@ -202,12 +205,10 @@ import { defineConfig } from 'vite';
|
|
|
202
205
|
export default defineConfig({ plugins: [svelte(), tailwindcss()] });
|
|
203
206
|
```
|
|
204
207
|
|
|
205
|
-
Import this stylesheet from `src/main.ts
|
|
206
|
-
`@c15t/svelte/styles.css` import:
|
|
208
|
+
Import this stylesheet from `src/main.ts`:
|
|
207
209
|
|
|
208
210
|
```css title="src/app.css"
|
|
209
211
|
@import 'tailwindcss';
|
|
210
|
-
@import '@c15t/svelte/styles.css';
|
|
211
212
|
|
|
212
213
|
@custom-variant dark (&:where(.dark, .dark *));
|
|
213
214
|
```
|
|
@@ -226,7 +227,6 @@ Import this stylesheet from your root `+layout.svelte`:
|
|
|
226
227
|
|
|
227
228
|
```css title="src/app.css"
|
|
228
229
|
@import 'tailwindcss';
|
|
229
|
-
@import '@c15t/svelte/styles.css';
|
|
230
230
|
|
|
231
231
|
@custom-variant dark (&:where(.dark, .dark *));
|
|
232
232
|
```
|
|
@@ -256,8 +256,12 @@ c15t's parts, pass the URL of your built stylesheet in
|
|
|
256
256
|
|
|
257
257
|
## Set up Tailwind CSS 3
|
|
258
258
|
|
|
259
|
-
Tailwind 3
|
|
260
|
-
|
|
259
|
+
Tailwind 3's preflight is unlayered, so it beats the layered rules c15t
|
|
260
|
+
renders itself and strips the banner's padding and borders. On Tailwind 3,
|
|
261
|
+
turn those rules off with `styles: false` and import c15t's `styles.css`
|
|
262
|
+
through a PostCSS plugin. The Astro integration needs only the plugin: it
|
|
263
|
+
detects Tailwind 3 and links `c15t/astro/styles.css` itself. Every c15t
|
|
264
|
+
package that ships a stylesheet exports the plugin as
|
|
261
265
|
`<package>/postcss-tailwind3`, so use the one from the package you installed:
|
|
262
266
|
|
|
263
267
|
| You installed | Plugin name |
|
|
@@ -269,21 +273,27 @@ plugin. Every c15t package that ships a stylesheet exports it as
|
|
|
269
273
|
They are the same plugin. A config that already lists
|
|
270
274
|
`@c15t/ui/postcss-tailwind3` keeps working.
|
|
271
275
|
|
|
272
|
-
Make
|
|
276
|
+
Make four changes:
|
|
273
277
|
|
|
274
|
-
1.
|
|
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.
|
|
282
|
+
Vue, Nuxt and Astro need no change.
|
|
283
|
+
2. Add the plugin to your PostCSS plugins, before `tailwindcss`. Write the plugins as an object, as the examples below do.
|
|
275
284
|
PostCSS runs them in the order of the keys. Next.js also accepts an array
|
|
276
285
|
of plugin names, but Vite's PostCSS loader rejects that form.
|
|
277
|
-
|
|
278
|
-
|
|
286
|
+
3. Import c15t's stylesheet above the `@tailwind` directives, whatever your
|
|
287
|
+
build tool. Vue, Nuxt and Astro skip this step. Vite drops an `@import`
|
|
279
288
|
that follows another rule, with the warning
|
|
280
289
|
`@import must precede all other statements`, and the banner renders
|
|
281
290
|
unstyled. Next.js 16 with Turbopack fails the build.
|
|
282
|
-
|
|
291
|
+
4. Set `darkMode: 'class'` so Tailwind's `dark:` variant follows the same
|
|
283
292
|
`dark` class c15t reads.
|
|
284
293
|
|
|
285
|
-
The plugin also processes the stylesheets
|
|
286
|
-
|
|
294
|
+
The plugin also processes the stylesheets the Vue and Nuxt components import,
|
|
295
|
+
and the one the Astro integration adds on a Tailwind 3 site. Without it,
|
|
296
|
+
Tailwind 3 stops
|
|
287
297
|
the build with "`@layer components` is used but no matching
|
|
288
298
|
`@tailwind components` directive is present", or purges c15t's rules, because
|
|
289
299
|
c15t's class names never appear in your source.
|
|
@@ -293,8 +303,9 @@ class. Add the important modifier to utilities you pass to c15t parts:
|
|
|
293
303
|
`!bg-red-500`, `hover:!bg-red-500`. A bare `bg-red-500` has no effect. Theme
|
|
294
304
|
tokens work the same on Tailwind 3 and 4.
|
|
295
305
|
|
|
296
|
-
In React and Next.js apps, `c15t setup`
|
|
297
|
-
finds Tailwind 3
|
|
306
|
+
In React and Next.js apps, `c15t setup` adds the plugin and the stylesheet
|
|
307
|
+
import when it finds Tailwind 3, but does not set `styles: false`. Add that
|
|
308
|
+
yourself. It replaces an existing
|
|
298
309
|
`styles.tw3.css` import from an earlier setup with `styles.css`. When it
|
|
299
310
|
cannot edit your PostCSS config, it prints the step to do by hand. See
|
|
300
311
|
[setup](https://c15t.com/docs/cli/commands/setup#set-up-styles-and-tailwind-css).
|
|
@@ -327,7 +338,7 @@ export default {
|
|
|
327
338
|
|
|
328
339
|
Import `c15t/next/styles.css` above the directives. Turbopack fails the
|
|
329
340
|
build when the import sits below them. The same order works with
|
|
330
|
-
webpack:
|
|
341
|
+
webpack. Set `styles: false` in `ConsentRoot`'s `options` as well:
|
|
331
342
|
|
|
332
343
|
```css title="app/globals.css"
|
|
333
344
|
/* Turbopack rejects an @import below other rules, so it goes first. */
|
|
@@ -358,7 +369,8 @@ export default {
|
|
|
358
369
|
```
|
|
359
370
|
|
|
360
371
|
Import `c15t/tanstack-start/styles.css` above the directives, in the
|
|
361
|
-
stylesheet your root route links:
|
|
372
|
+
stylesheet your root route links, and set `styles: false` in
|
|
373
|
+
`ConsentRoot`'s `options`:
|
|
362
374
|
|
|
363
375
|
```css title="src/styles.css"
|
|
364
376
|
/* Vite ignores an @import below other rules, so it goes first. */
|
|
@@ -388,8 +400,9 @@ export default {
|
|
|
388
400
|
} satisfies Config;
|
|
389
401
|
```
|
|
390
402
|
|
|
391
|
-
Import `c15t/react/styles.css` above the directives,
|
|
392
|
-
stylesheet from your entry module:
|
|
403
|
+
Import `c15t/react/styles.css` above the directives, import this
|
|
404
|
+
stylesheet from your entry module, and set `styles: false` in the
|
|
405
|
+
`ConsentProvider` options:
|
|
393
406
|
|
|
394
407
|
```css title="src/app.css"
|
|
395
408
|
/* Vite ignores an @import below other rules, so it goes first. */
|
|
@@ -406,8 +419,10 @@ Nuxt reads PostCSS plugins from `postcss.plugins` in `nuxt.config.ts`, in
|
|
|
406
419
|
the order listed:
|
|
407
420
|
|
|
408
421
|
```ts title="nuxt.config.ts"
|
|
422
|
+
import { hosted } from 'c15t/vue';
|
|
423
|
+
|
|
409
424
|
export default defineNuxtConfig({
|
|
410
|
-
c15t: { backendURL: '/api/c15t' },
|
|
425
|
+
c15t: { backendURL: '/api/c15t', mode: hosted() },
|
|
411
426
|
compatibilityDate: '2026-07-04',
|
|
412
427
|
css: ['~/assets/css/main.css'],
|
|
413
428
|
modules: ['c15t/vue'],
|
|
@@ -489,8 +504,12 @@ export default {
|
|
|
489
504
|
} satisfies Config;
|
|
490
505
|
```
|
|
491
506
|
|
|
492
|
-
|
|
493
|
-
|
|
507
|
+
When the integration finds Tailwind 3 in the project, it adds
|
|
508
|
+
`c15t/astro/styles.css` to every page through Astro's CSS pipeline
|
|
509
|
+
instead of inlining the banner's rules, so the plugin processes it. You
|
|
510
|
+
do not set `styles: false` or import c15t's stylesheet, and the CSS
|
|
511
|
+
entry holds only the directives. The first paint still waits for that
|
|
512
|
+
stylesheet:
|
|
494
513
|
|
|
495
514
|
```css title="src/styles/global.css"
|
|
496
515
|
@tailwind base;
|
|
@@ -521,8 +540,9 @@ export default {
|
|
|
521
540
|
} satisfies Config;
|
|
522
541
|
```
|
|
523
542
|
|
|
524
|
-
Import `@c15t/svelte/styles.css` above the directives,
|
|
525
|
-
stylesheet from `src/main.ts
|
|
543
|
+
Import `@c15t/svelte/styles.css` above the directives, import this
|
|
544
|
+
stylesheet from `src/main.ts`, and pass `styles={false}` to
|
|
545
|
+
`ConsentProvider`:
|
|
526
546
|
|
|
527
547
|
```css title="src/app.css"
|
|
528
548
|
/* Vite ignores an @import below other rules, so it goes first. */
|
|
@@ -556,8 +576,9 @@ export default {
|
|
|
556
576
|
} satisfies Config;
|
|
557
577
|
```
|
|
558
578
|
|
|
559
|
-
Import `@c15t/svelte/styles.css` above the directives,
|
|
560
|
-
stylesheet from your root `+layout.svelte
|
|
579
|
+
Import `@c15t/svelte/styles.css` above the directives, import this
|
|
580
|
+
stylesheet from your root `+layout.svelte`, and pass `styles={false}` to
|
|
581
|
+
`ConsentRoot`:
|
|
561
582
|
|
|
562
583
|
```css title="src/app.css"
|
|
563
584
|
/* Vite ignores an @import below other rules, so it goes first. */
|
|
@@ -662,12 +683,12 @@ Add the classes to `components` in the `c15tVue` options. Vue takes
|
|
|
662
683
|
|
|
663
684
|
```ts title="src/main.ts"
|
|
664
685
|
.use(c15tVue, {
|
|
665
|
-
backendURL: '/api/c15t',
|
|
666
686
|
components: {
|
|
667
687
|
banner: {
|
|
668
688
|
root: { class: 'p-[7px] dark:p-[11px]' },
|
|
669
689
|
},
|
|
670
690
|
},
|
|
691
|
+
mode: hosted(),
|
|
671
692
|
})
|
|
672
693
|
```
|
|
673
694
|
|
|
@@ -801,7 +822,7 @@ instead:
|
|
|
801
822
|
```
|
|
802
823
|
|
|
803
824
|
Import `@c15t/browser/styles.css` above the directives in your Tailwind entry.
|
|
804
|
-
Install `@c15t/browser
|
|
825
|
+
Install `@c15t/browser`, which provides both the stylesheet and
|
|
805
826
|
`@c15t/browser/postcss-tailwind3`:
|
|
806
827
|
|
|
807
828
|
```css title="style.css"
|