@c15t/react 2.0.0-rc.6 → 2.0.0-rc.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/components/consent-banner/atoms/root.cjs +1 -1
  2. package/dist/components/consent-banner/atoms/root.js +1 -1
  3. package/dist/components/consent-dialog/atoms/root.cjs +1 -1
  4. package/dist/components/consent-dialog/atoms/root.js +1 -1
  5. package/dist/components/consent-widget/atoms/accordion.cjs +1 -1
  6. package/dist/components/consent-widget/atoms/accordion.js +1 -1
  7. package/dist/components/iab-consent-banner/atoms/card.cjs +1 -1
  8. package/dist/components/iab-consent-banner/atoms/card.js +1 -1
  9. package/dist/components/iab-consent-banner/atoms/footer.cjs +1 -1
  10. package/dist/components/iab-consent-banner/atoms/footer.js +1 -1
  11. package/dist/components/iab-consent-banner/atoms/header.cjs +1 -1
  12. package/dist/components/iab-consent-banner/atoms/header.js +1 -1
  13. package/dist/components/iab-consent-banner/atoms/root.cjs +1 -1
  14. package/dist/components/iab-consent-banner/atoms/root.js +1 -1
  15. package/dist/components/iab-consent-dialog/atoms/card.cjs +1 -1
  16. package/dist/components/iab-consent-dialog/atoms/card.js +1 -1
  17. package/dist/components/iab-consent-dialog/atoms/footer.cjs +1 -1
  18. package/dist/components/iab-consent-dialog/atoms/footer.js +1 -1
  19. package/dist/components/iab-consent-dialog/atoms/header.cjs +1 -1
  20. package/dist/components/iab-consent-dialog/atoms/header.js +1 -1
  21. package/dist/components/iab-consent-dialog/atoms/root.cjs +1 -1
  22. package/dist/components/iab-consent-dialog/atoms/root.js +1 -1
  23. package/dist/components/shared/primitives/box.cjs +1 -1
  24. package/dist/components/shared/primitives/box.js +1 -1
  25. package/dist/iab/styles.tw3.css +1 -0
  26. package/dist/styles.tw3.css +1 -0
  27. package/dist/version.cjs +1 -1
  28. package/dist/version.js +1 -1
  29. package/dist-types/components/consent-banner/atoms/root.d.ts +43 -12
  30. package/dist-types/components/consent-banner/index.d.ts +44 -24
  31. package/dist-types/components/consent-dialog/index.d.ts +29 -8
  32. package/dist-types/components/consent-preferences-link/consent-preferences-link.d.ts +0 -1
  33. package/dist-types/components/consent-widget/atoms/accordion.d.ts +4 -3
  34. package/dist-types/components/consent-widget/index.d.ts +23 -6
  35. package/dist-types/version.d.ts +1 -1
  36. package/docs/building-headless-components.md +3 -0
  37. package/docs/components/consent-banner.md +68 -18
  38. package/docs/components/consent-dialog.md +31 -2
  39. package/docs/components/consent-widget.md +31 -2
  40. package/docs/headless.md +13 -7
  41. package/docs/styling/classnames.md +17 -9
  42. package/docs/styling/overview.md +166 -29
  43. package/docs/styling/slots.md +37 -7
  44. package/docs/styling/tailwind.md +12 -20
  45. package/package.json +6 -2
  46. package/src/iab/styles.tw3.css +10 -0
  47. package/src/styles.tw3.css +10 -0
@@ -34,8 +34,9 @@ export interface ConsentBannerCompoundComponent extends FC<ConsentBannerProps> {
34
34
  *
35
35
  * @remarks
36
36
  * This component serves as the main entry point for rendering a consent banner.
37
- * It provides a structured layout with customizable title, description, and action buttons
38
- * for accepting, rejecting, or customizing consent preferences.
37
+ * Start with the pre-built component and its existing configuration surface.
38
+ * For most customization, use `ConsentManagerProvider` options, theme tokens,
39
+ * slots, and `theme.consentActions` before reaching for compound composition.
39
40
  *
40
41
  * Key features:
41
42
  * - Fully accessible by default
@@ -43,7 +44,7 @@ export interface ConsentBannerCompoundComponent extends FC<ConsentBannerProps> {
43
44
  * - Customizable appearance
44
45
  * - Responsive design
45
46
  * - Error boundary protection
46
- * - Compound component pattern support
47
+ * - Advanced compound component support when markup must change
47
48
  *
48
49
  * @example
49
50
  * Simple usage with default settings:
@@ -52,35 +53,54 @@ export interface ConsentBannerCompoundComponent extends FC<ConsentBannerProps> {
52
53
  * ```
53
54
  *
54
55
  * @example
55
- * Customized usage with all props:
56
+ * Preferred customization via provider `i18n`, theme tokens, and slots:
56
57
  * ```tsx
57
- * <ConsentBanner
58
- * title="Cookie Settings"
59
- * description="We use cookies to enhance your browsing experience"
60
- * rejectButtonText="Decline"
61
- * customizeButtonText="Preferences"
62
- * acceptButtonText="Allow All"
63
- * />
58
+ * <ConsentManagerProvider
59
+ * options={{
60
+ * i18n: {
61
+ * locale: 'en',
62
+ * messages: {
63
+ * en: {
64
+ * cookieBanner: { title: 'Privacy choices' },
65
+ * },
66
+ * },
67
+ * },
68
+ * theme: {
69
+ * colors: {
70
+ * surface: '#fffdf8',
71
+ * surfaceHover: '#f6f3ee',
72
+ * },
73
+ * slots: {
74
+ * consentBannerCard: 'rounded-3xl',
75
+ * consentBannerFooter: 'border-t border-black/10',
76
+ * },
77
+ * },
78
+ * }}
79
+ * >
80
+ * <ConsentBanner primaryButton="accept" />
81
+ * </ConsentManagerProvider>
64
82
  * ```
65
83
  *
66
84
  * @example
85
+ * Advanced custom markup with compound components:
67
86
  * ```tsx
68
87
  * <ConsentBanner.Root>
69
- * <ConsentBanner.Content>
70
- * <ConsentBanner.Title>Cookie Settings</ConsentBanner.Title>
71
- * <ConsentBanner.Description>
72
- * Choose your cookie preferences
73
- * </ConsentBanner.Description>
74
- * <ConsentBanner.Actions>
75
- * <ConsentBanner.RejectButton>Decline</ConsentBanner.RejectButton>
76
- * <ConsentBanner.CustomizeButton>Customize</ConsentBanner.CustomizeButton>
77
- * <ConsentBanner.AcceptButton>Accept</ConsentBanner.AcceptButton>
78
- * </ConsentBanner.Actions>
79
- * </ConsentBanner.Content>
88
+ * <ConsentBanner.Card>
89
+ * <ConsentBanner.Header>
90
+ * <ConsentBanner.Title />
91
+ * <ConsentBanner.Description />
92
+ * </ConsentBanner.Header>
93
+ * <ConsentBanner.Footer>
94
+ * <ConsentBanner.CustomizeButton />
95
+ * <ConsentBanner.FooterSubGroup>
96
+ * <ConsentBanner.RejectButton />
97
+ * <ConsentBanner.AcceptButton />
98
+ * </ConsentBanner.FooterSubGroup>
99
+ * </ConsentBanner.Footer>
100
+ * </ConsentBanner.Card>
80
101
  * </ConsentBanner.Root>
81
102
  * ```
82
- * Note: Next.js Server Components do not support compound components. Ensure you add 'use client' to the file.
83
- * Using compound components for custom layout:
103
+ * Note: Next.js Server Components do not support compound components. Ensure you add `'use client'` to the file.
84
104
  *
85
105
  * @public
86
106
  */
@@ -42,30 +42,51 @@ export interface ConsentDialogCompoundComponent extends FC<ConsentDialogProps> {
42
42
  * - Provides an accessible modal interface for consent customization
43
43
  * - Implements smooth enter/exit animations
44
44
  * - Manages proper focus handling
45
- * - Supports theme customization
45
+ * - Supports theme customization through provider tokens and slots
46
46
  * - Handles client-side portal rendering
47
+ * - Exposes compound primitives for advanced markup changes
47
48
  *
48
49
  * @example
50
+ * Basic usage:
49
51
  * ```tsx
50
- * <ConsentDialog
51
- * theme={customTheme}
52
- * disableAnimation={false}
53
- * noStyle={false}
54
- * />
52
+ * <ConsentDialog />
55
53
  * ```
56
54
  *
57
55
  * @example
56
+ * Preferred customization with stock structure:
57
+ * ```tsx
58
+ * <ConsentManagerProvider
59
+ * options={{
60
+ * theme: {
61
+ * slots: {
62
+ * consentDialogCard: 'rounded-3xl shadow-xl',
63
+ * consentDialogFooter: 'border-t border-black/10',
64
+ * },
65
+ * },
66
+ * }}
67
+ * >
68
+ * <ConsentDialog hideBranding showTrigger />
69
+ * </ConsentManagerProvider>
70
+ * ```
71
+ *
72
+ * @example
73
+ * Advanced custom markup with compound components:
58
74
  * ```tsx
59
75
  * <ConsentDialog.Root>
60
76
  * <ConsentDialog.Card>
61
77
  * <ConsentDialog.Header>
62
- * <ConsentDialog.HeaderTitle>Consent Manager</ConsentDialog.HeaderTitle>
78
+ * <ConsentDialog.HeaderTitle />
79
+ * <ConsentDialog.HeaderDescription />
63
80
  * </ConsentDialog.Header>
81
+ * <ConsentDialog.Content>
82
+ * <ConsentWidget />
83
+ * </ConsentDialog.Content>
84
+ * <ConsentDialog.Footer />
64
85
  * </ConsentDialog.Card>
65
86
  * </ConsentDialog.Root>
66
87
  * ```
67
88
  *
68
- * Note: Next.js Server Components do not support compound components. Ensure you add 'use client' to the file.
89
+ * Note: Next.js Server Components do not support compound components. Ensure you add `'use client'` to the file.
69
90
  *
70
91
  * @public
71
92
  */
@@ -13,4 +13,3 @@ export interface ConsentDialogLinkProps extends Omit<ConsentButtonProps, 'childr
13
13
  children: ReactNode;
14
14
  }
15
15
  export declare const ConsentDialogLink: import("react").ForwardRefExoticComponent<ConsentDialogLinkProps & import("react").RefAttributes<HTMLButtonElement>>;
16
- lement>>;
@@ -7,20 +7,21 @@ declare const ConsentWidgetAccordionTriggerInner: import("react").ForwardRefExot
7
7
  declare const ConsentWidgetAccordionContent: import("react").ForwardRefExoticComponent<PreferenceItem.PreferenceItemContentProps & import("react").RefAttributes<HTMLDivElement>>;
8
8
  declare const ConsentWidgetAccordionArrow: import("react").ForwardRefExoticComponent<PreferenceItem.PreferenceItemSlotProps & import("react").RefAttributes<HTMLDivElement>>;
9
9
  declare const ConsentWidgetSwitch: import("react").ForwardRefExoticComponent<RadixSwitch.SwitchProps & import("react").RefAttributes<HTMLButtonElement>>;
10
- type ConsentWidgetAccordionProps = {
10
+ type ConsentWidgetAccordionProps = Omit<BoxProps, 'themeKey'> & {
11
+ 'data-testid'?: string;
11
12
  children: ReactNode;
12
13
  onValueChange?: (value: string | string[]) => void;
13
14
  type?: 'multiple' | 'single';
14
15
  value?: string | string[];
15
16
  };
16
- declare const ConsentWidgetAccordion: ({ children, onValueChange, type, value, }: ConsentWidgetAccordionProps) => import("react/jsx-runtime").JSX.Element;
17
+ declare const ConsentWidgetAccordion: ({ "data-testid": dataTestId, children, className, noStyle, onValueChange, style, type, value, ...props }: ConsentWidgetAccordionProps) => import("react/jsx-runtime").JSX.Element;
17
18
  declare const ConsentWidgetAccordionItems: () => import("react/jsx-runtime").JSX.Element[];
18
19
  declare const ConsentWidgetAccordionItem: import("react").ForwardRefExoticComponent<Omit<PreferenceItem.PreferenceItemRootProps & import("react").RefAttributes<HTMLDivElement>, "ref"> & import("react").RefAttributes<HTMLDivElement>>;
19
20
  declare const AccordionTriggerInner: import("react").ForwardRefExoticComponent<PreferenceItem.PreferenceItemTriggerProps & import("react").RefAttributes<HTMLButtonElement>>;
20
21
  declare const AccordionTrigger: import("react").ForwardRefExoticComponent<BoxProps & import("react").RefAttributes<HTMLDivElement>>;
21
22
  declare const AccordionContent: import("react").ForwardRefExoticComponent<PreferenceItem.PreferenceItemContentProps & import("react").RefAttributes<HTMLDivElement>>;
22
23
  declare const AccordionArrow: import("react").ForwardRefExoticComponent<PreferenceItem.PreferenceItemSlotProps & import("react").RefAttributes<HTMLDivElement>>;
23
- declare const Accordion: ({ children, onValueChange, type, value, }: ConsentWidgetAccordionProps) => import("react/jsx-runtime").JSX.Element;
24
+ declare const Accordion: ({ "data-testid": dataTestId, children, className, noStyle, onValueChange, style, type, value, ...props }: ConsentWidgetAccordionProps) => import("react/jsx-runtime").JSX.Element;
24
25
  declare const Switch: import("react").ForwardRefExoticComponent<RadixSwitch.SwitchProps & import("react").RefAttributes<HTMLButtonElement>>;
25
26
  declare const AccordionItems: () => import("react/jsx-runtime").JSX.Element[];
26
27
  declare const AccordionItem: import("react").ForwardRefExoticComponent<Omit<PreferenceItem.PreferenceItemRootProps & import("react").RefAttributes<HTMLDivElement>, "ref"> & import("react").RefAttributes<HTMLDivElement>>;
@@ -44,11 +44,11 @@ export interface ConsentWidgetCompoundComponent extends FC<ConsentWidgetProps> {
44
44
  *
45
45
  * @remarks
46
46
  * Key features:
47
- * - Implements compound component pattern for flexible composition
48
47
  * - Manages consent state and user interactions
49
48
  * - Provides accessible controls for consent management
50
- * - Supports comprehensive theming
49
+ * - Supports comprehensive theming with tokens and slots
51
50
  * - Handles accordion state management
51
+ * - Exposes compound primitives for advanced layout changes
52
52
  *
53
53
  * @example
54
54
  * Basic usage:
@@ -59,15 +59,32 @@ export interface ConsentWidgetCompoundComponent extends FC<ConsentWidgetProps> {
59
59
  * ```
60
60
  *
61
61
  * @example
62
- * Compound components:
62
+ * Preferred stock customization with theme slots:
63
+ * ```tsx
64
+ * <ConsentManagerProvider
65
+ * options={{
66
+ * theme: {
67
+ * slots: {
68
+ * consentWidgetAccordion: 'rounded-3xl border border-black/10',
69
+ * consentWidgetFooter: 'border-t border-black/10',
70
+ * },
71
+ * },
72
+ * }}
73
+ * >
74
+ * <ConsentWidget hideBranding />
75
+ * </ConsentManagerProvider>
76
+ * ```
77
+ *
78
+ * @example
79
+ * Advanced compound components:
63
80
  * ```tsx
64
81
  * <ConsentWidget.Root>
65
82
  * <ConsentWidget.Accordion>
66
83
  * <ConsentWidget.AccordionItems />
67
- * </ConsentWidget.Accordion>
68
- * </ConsentWidget.Root>
84
+ * </ConsentWidget.Accordion>
85
+ * </ConsentWidget.Root>
69
86
  * ```
70
- * Note: Next.js Server Components do not support compound components. Ensure you add 'use client' to the file.
87
+ * Note: Next.js Server Components do not support compound components. Ensure you add `'use client'` to the file.
71
88
  *
72
89
  */
73
90
  declare const ConsentWidget: ConsentWidgetCompoundComponent;
@@ -1 +1 @@
1
- export declare const version = "2.0.0-rc.6";
1
+ export declare const version = "2.0.0-rc.7";
@@ -4,6 +4,9 @@ description: Build policy-aware custom consent components in React using the hea
4
4
  ---
5
5
  Building headless components is easier now because c15t exposes policy-aware primitives instead of forcing you to reconstruct banner rules by hand.
6
6
 
7
+ > ⚠️ **Warning:**
8
+ > Headless is the last step in the customization ladder. Use this guide only when pre-built components, tokens, slots, compound components, and noStyle are no longer sufficient.
9
+
7
10
  The headless stack is:
8
11
 
9
12
  * `useHeadlessConsentUI()` for policy-aware banner/dialog actions, ordering, layout, and primary actions hints
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  title: ConsentBanner
3
- description: A pre-built consent banner that appears when user consent is needed. Supports custom layout, button arrangement, and full compound component composition.
3
+ description: A pre-built consent banner that appears when user consent is needed. Supports policy-aware layout, theming, and advanced composition when markup must change.
4
4
  ---
5
5
  `ConsentBanner` is a ready-to-use consent banner that appears automatically in **opt-in jurisdictions** (like GDPR) where explicit consent is required before tracking. In opt-out jurisdictions (like CCPA), the banner won't appear — users get an opt-out mechanism instead. It includes reject, accept, and customize buttons with configurable layout.
6
6
 
@@ -18,20 +18,6 @@ export function ConsentManager() {
18
18
  }
19
19
  ```
20
20
 
21
- ## Customizing Content
22
-
23
- Override the default title, description, and button labels:
24
-
25
- ```tsx
26
- <ConsentBanner
27
- title="We value your privacy"
28
- description="We use cookies to enhance your browsing experience and analyze site traffic."
29
- acceptButtonText="Accept all"
30
- rejectButtonText="Reject all"
31
- customizeButtonText="Manage preferences"
32
- />
33
- ```
34
-
35
21
  ## Button Layout
36
22
 
37
23
  The `layout` prop controls button arrangement. Each item is either a button ID or an array of button IDs (which groups them together):
@@ -86,6 +72,37 @@ Use the provider `theme` prop to control how stock consent actions look:
86
72
 
87
73
  Policy packs control grouping, ordering, and direction. The theme controls button appearance.
88
74
 
75
+ ## Styling First
76
+
77
+ > ℹ️ **Info:**
78
+ > For pure theming, stay inside the pre-built banner. Start with layout props, theme.consentActions, design tokens, and theme.slots before reaching for compound components. See Styling Overview.
79
+
80
+ The stock banner maps common visual changes to the theme system:
81
+
82
+ * Card background -> `theme.colors.surface`
83
+ * Footer background -> `theme.colors.surfaceHover`
84
+ * Card, footer, and title tweaks -> `theme.slots.consentBannerCard`, `consentBannerFooter`, and `consentBannerTitle`
85
+
86
+ ```tsx
87
+ <ConsentManagerProvider
88
+ options={{
89
+ theme: {
90
+ colors: {
91
+ surface: '#fffdf8',
92
+ surfaceHover: '#f6f3ee',
93
+ },
94
+ slots: {
95
+ consentBannerCard: 'rounded-[28px] shadow-xl',
96
+ consentBannerFooter: 'border-t border-black/10 px-6',
97
+ consentBannerTitle: 'tracking-tight',
98
+ },
99
+ },
100
+ }}
101
+ >
102
+ <ConsentBanner />
103
+ </ConsentManagerProvider>
104
+ ```
105
+
89
106
  ### Primary Button
90
107
 
91
108
  Highlight specific button(s) as the primary action:
@@ -116,9 +133,40 @@ Control which legal links appear in the banner description:
116
133
  > ℹ️ **Info:**
117
134
  > Legal link URLs are configured in the ConsentManagerProvider options via the legalLinks prop, not on the banner itself.
118
135
 
119
- ## Compound Components
136
+ ## Customizing Copy
137
+
138
+ Prefer provider `i18n` when you want to rename the stock banner content:
139
+
140
+ ```tsx
141
+ <ConsentManagerProvider
142
+ options={{
143
+ i18n: {
144
+ locale: 'en',
145
+ messages: {
146
+ en: {
147
+ cookieBanner: {
148
+ title: 'We value your privacy',
149
+ description: 'We use cookies to improve the site and measure performance.',
150
+ },
151
+ common: {
152
+ acceptAll: 'Accept all',
153
+ rejectAll: 'Reject all',
154
+ customize: 'Manage preferences',
155
+ },
156
+ },
157
+ },
158
+ },
159
+ }}
160
+ >
161
+ <ConsentBanner />
162
+ </ConsentManagerProvider>
163
+ ```
164
+
165
+ Direct text props such as `title`, `description`, and `acceptButtonText` are still supported for one-off overrides, but `i18n` is the preferred path for copy changes.
120
166
 
121
- Build fully custom banner layouts using sub-components:
167
+ ## Advanced: Compound Components
168
+
169
+ Use compound components only when the stock banner structure is no longer enough and you need to rearrange existing c15t primitives:
122
170
 
123
171
  ```tsx
124
172
  <ConsentBanner.Root>
@@ -142,7 +190,7 @@ Build fully custom banner layouts using sub-components:
142
190
  * `ConsentBanner.Root` — Outermost container, provides theme context
143
191
  * `ConsentBanner.Card` — Main content card with optional focus trapping
144
192
  * `ConsentBanner.Header` — Contains title and description
145
- * `ConsentBanner.Title` — Heading, defaults to translation `consentBanner.title`
193
+ * `ConsentBanner.Title` — Heading, defaults to translation `cookieBanner.title`
146
194
  * `ConsentBanner.Description` — Description text, supports `legalLinks` prop
147
195
  * `ConsentBanner.Footer` — Action buttons container
148
196
  * `ConsentBanner.FooterSubGroup` — Groups related buttons together
@@ -151,6 +199,8 @@ Build fully custom banner layouts using sub-components:
151
199
  * `ConsentBanner.AcceptButton` — Accepts all consent
152
200
  * `ConsentBanner.Overlay` — Optional backdrop overlay
153
201
 
202
+ If you only need styling changes, stay with tokens and slots instead of rebuilding the banner layout.
203
+
154
204
  ## Props
155
205
 
156
206
  ### ConsentBannerProps
@@ -81,9 +81,36 @@ Hide the c15t branding in the dialog footer:
81
81
  <ConsentDialog hideBranding />
82
82
  ```
83
83
 
84
- ## Compound Components
84
+ ## Styling First
85
85
 
86
- Build fully custom dialog layouts using sub-components:
86
+ > ℹ️ **Info:**
87
+ > If you are only changing visuals, stay with the stock dialog and use the theme system first. Start with tokens and slots such as consentDialogCard, consentDialogHeader, and consentDialogFooter. See Styling Overview.
88
+
89
+ ```tsx
90
+ <ConsentManagerProvider
91
+ options={{
92
+ theme: {
93
+ colors: {
94
+ surface: '#fffdf8',
95
+ surfaceHover: '#f6f3ee',
96
+ },
97
+ slots: {
98
+ consentDialogCard: 'rounded-[32px] shadow-xl',
99
+ consentDialogHeader: 'gap-3',
100
+ consentDialogFooter: 'border-t border-black/10 px-6',
101
+ },
102
+ },
103
+ }}
104
+ >
105
+ <ConsentDialog />
106
+ </ConsentManagerProvider>
107
+ ```
108
+
109
+ Dialog copy should be changed through `ConsentManagerProvider.options.i18n`, not by rebuilding the dialog structure.
110
+
111
+ ## Advanced: Compound Components
112
+
113
+ Use compound components only when you need custom dialog markup while still keeping c15t primitives:
87
114
 
88
115
  ```tsx
89
116
  <ConsentDialog.Root>
@@ -118,6 +145,8 @@ For a quick pre-composed layout, use the shorthand card:
118
145
  </ConsentDialog.Root>
119
146
  ```
120
147
 
148
+ If the stock dialog structure still works, prefer tokens, slots, and provider configuration instead.
149
+
121
150
  ## Props
122
151
 
123
152
  ### ConsentDialogProps
@@ -35,9 +35,36 @@ export function PrivacySettingsPage() {
35
35
 
36
36
  Each consent category is rendered as an expandable accordion item. Clicking the category header expands it to show a description and any associated services. Users can toggle individual categories on or off using the switch control. The `necessary` category is always enabled and cannot be toggled.
37
37
 
38
- ## Compound Components
38
+ ## Styling First
39
39
 
40
- Build fully custom widget layouts using sub-components:
40
+ > ℹ️ **Info:**
41
+ > Most widget customization should stay in the stock component. Use theme tokens and slots such as consentWidgetAccordion, consentWidgetFooter, and toggle before reaching for compound components. See Styling Overview.
42
+
43
+ ```tsx
44
+ <ConsentManagerProvider
45
+ options={{
46
+ theme: {
47
+ colors: {
48
+ surface: '#fffdf8',
49
+ surfaceHover: '#f6f3ee',
50
+ },
51
+ slots: {
52
+ consentWidgetAccordion: 'rounded-3xl border border-black/10',
53
+ consentWidgetFooter: 'border-t border-black/10 px-6',
54
+ toggle: 'shadow-sm',
55
+ },
56
+ },
57
+ }}
58
+ >
59
+ <ConsentWidget />
60
+ </ConsentManagerProvider>
61
+ ```
62
+
63
+ Widget copy should be changed through `ConsentManagerProvider.options.i18n` so the inline UI stays aligned with the rest of the consent experience.
64
+
65
+ ## Advanced: Compound Components
66
+
67
+ Use compound components only when you need to rearrange the widget's existing primitives:
41
68
 
42
69
  ```tsx
43
70
  <ConsentWidget.Root>
@@ -68,6 +95,8 @@ Build fully custom widget layouts using sub-components:
68
95
  * `ConsentWidget.RejectButton` — Rejects all consent
69
96
  * `ConsentWidget.SaveButton` — Saves custom selections
70
97
 
98
+ If the stock widget structure is already correct, stay with tokens and slots instead of rebuilding the layout.
99
+
71
100
  ## Props
72
101
 
73
102
  ### ConsentWidgetProps
package/docs/headless.md CHANGED
@@ -4,11 +4,12 @@ description: Build fully custom consent UI using only hooks - no pre-built compo
4
4
  ---
5
5
  c15t's headless mode means using the hooks (`useConsentManager`, `useTranslations`, etc.) without any pre-built UI components. This gives you complete control over the consent experience.
6
6
 
7
- There are three levels of customization:
7
+ Before you go headless, walk the customization ladder in order:
8
8
 
9
- 1. **Props** - Use pre-built components with custom text and configuration
10
- 2. **noStyle** - Use pre-built components with their structure but strip all styles
11
- 3. **Headless** - Use only hooks and build the entire UI yourself
9
+ 1. **Pre-built components** - Use provider options, component props, tokens, slots, and `theme.consentActions`
10
+ 2. **Compound components** - Rearrange c15t primitives when the markup order must change
11
+ 3. **`noStyle`** - Keep c15t structure but replace its styling
12
+ 4. **Headless** - Use only hooks and build the entire UI yourself
12
13
 
13
14
  ## When to Go Headless
14
15
 
@@ -18,10 +19,15 @@ Go headless when:
18
19
  * You need a consent flow that doesn't fit the banner/dialog pattern
19
20
  * You want to embed consent choices inline rather than as overlays
20
21
 
21
- Use `noStyle` instead when:
22
+ Use a lower-power tool instead when:
22
23
 
23
- * The component structure works but the styling doesn't
24
- * You want to apply your own CSS/Tailwind without fighting defaults
24
+ * The component structure works but the styling doesn't -> use tokens, slots, or `noStyle`
25
+ * You only need to rearrange existing c15t parts -> use compound components
26
+ * You want to change copy -> use `ConsentManagerProvider.options.i18n`
27
+ * You only need to restyle stock actions -> use `theme.consentActions`
28
+
29
+ > ⚠️ **Warning:**
30
+ > Headless mode is not the first answer for pure theming. If you are still trying to debug why a banner footer color did not change, stay in the styling system and verify the token-to-component mapping before you rebuild the UI.
25
31
 
26
32
  > ℹ️ **Info:**
27
33
  > Need a policy-aware implementation guide? See Building Headless Components.
@@ -2,15 +2,11 @@
2
2
  title: Class Names
3
3
  description: Style consent components using className props and per-slot className targeting via the theme.
4
4
  ---
5
- ## Component className
5
+ ## Prefer Slots for Stock Components
6
6
 
7
- All consent components accept a `className` prop:
7
+ There is no single top-level `className` contract across every pre-built consent component.
8
8
 
9
- ```tsx
10
- <ConsentBanner className="my-banner" />
11
- <ConsentDialog className="my-dialog" />
12
- <ConsentWidget className="my-widget" />
13
- ```
9
+ For the stock `ConsentBanner`, `ConsentDialog`, and `ConsentWidget`, prefer `theme.slots` first. That keeps the markup intact and lets you target the exact part you need.
14
10
 
15
11
  ## Per-Slot className
16
12
 
@@ -59,9 +55,19 @@ const theme = {
59
55
  }
60
56
  ```
61
57
 
62
- ## noStyle Mode
58
+ ## When to Use Raw className
59
+
60
+ Use raw className-level styling when:
61
+
62
+ * your styling system is already class-driven
63
+ * tokens are too broad for the change
64
+ * slots already identify the correct element
63
65
 
64
- Use `noStyle` when you want to remove defaults and style from scratch:
66
+ If the request is "make the banner footer darker", prefer `theme.colors.surfaceHover` first. If the request is "add a border and spacing only to the footer", prefer `theme.slots.consentBannerFooter`.
67
+
68
+ ## Advanced: `noStyle`
69
+
70
+ Use `noStyle` only when you want to remove defaults and style from scratch while still keeping c15t's component structure:
65
71
 
66
72
  ```tsx
67
73
  {/* Remove all styles from a specific component */}
@@ -81,4 +87,6 @@ const theme = {
81
87
  } satisfies Theme;
82
88
  ```
83
89
 
90
+ Treat `noStyle` as an advanced escape hatch. Do not jump to it just because a token or slot needs debugging.
91
+
84
92
  For full custom markup and behavior, continue to [Headless Mode](../headless).