Public web component documentation for consent-dialog, consent-guard, consent-missing, and compliance-monitor.
Main entry component for the PrivacyKit consent UI and orchestration logic.
| Attribute | Type | Default / Required | Description |
|---|---|---|---|
| variant | standard | panel | modern | modest | standard | Visual variant of the dialog. |
| theme | standard | dark | teal | slate | light | vibrant | high-contrast | standard | Visual theme of the dialog. |
| expires-days | number | 180 | Cookie lifetime in days. |
| version | number | 0 | Consent schema version used for re-consent decisions. |
| google-consent-mode | boolean | unset | Emits Google Consent Mode v2 consent signals based on the user's PrivacyKit consent choices. |
| locale | da | de | en | es | fi | fr | it | nl | no | pl | sv | browser-derived | Locale override. |
| hide-summary-part-2 | boolean | unset | Hides the dialog summary part 2 (dialog-summary-part-2). |
| hide-necessary | boolean | unset | Hides the necessary category. |
| hide-preferences | boolean | unset | Hides the preferences category. |
| hide-analytics | boolean | unset | Hides the analytics category. |
| hide-marketing | boolean | unset | Hides the marketing category. |
| hide-readmore | boolean | unset | Hides the expandable Read More section. |
| hide-privacykit-badge | boolean | unset | Hides the PrivacyKit badge shown at the bottom of the consent dialog body. |
| hide-privacy-policy-link | boolean | unset | Hides the default Privacy Policy link entirely. Use `privacy-policy-url` instead to keep the link visible and redirect users to your own policy page. |
| privacy-policy-url | string | unset | URL to redirect users to when they click the Privacy Policy link. When set, the link opens this URL instead of the built-in privacy policy dialog. |
| demo | boolean | unset | Demo mode: disables auto-open and limits certain features. Not GDPR compliant and must not be used in production. |
| dismissible | boolean | false | Controls whether dialog can be dismissed via backdrop/escape if no accept/reject consent has been given. |
| show-fab | boolean | false | Enables the consent preferences button. Has no visible effect until a consent cookie exists. |
| fab-position | left | right | left | Pins the FAB to the bottom-left or bottom-right corner of the viewport. |
| dialog-position | left | right | left | Controls which side of the screen the dialog appears on. Only applies to the modern and modest variants — standard and panel are always centered. |
Example
<consent-dialog theme="panel" variant="dark" expires-days="90"
version="1" locale="en" hide-marketing hide-privacy-policy-link dismissible>
</consent-dialog><consent-dialog> ships with built-in translations for English, Norwegian, German, Polish, Spanish, French, Italian, Dutch, Swedish, Danish, and Finnish — no translation files to load or maintain yourself.
By default, the dialog reads the visitor's browser language and displays the matching translation automatically. If the browser is set to a language PrivacyKit doesn't support, it falls back to English.
To force a specific language regardless of the visitor's browser settings, set the locale attribute — see the table above for the full list of supported codes.
<consent-dialog locale="en"></consent-dialog>Design tokens expose a stable set of CSS variables that let you customize appearance—colors, spacing, typography, and more—without touching the component's internal implementation. Built-in themes are powered by the same token system, allowing you to override individual styles or create a completely custom appearance.
| Design Tokens | Description |
|---|---|
| --pk-bg-color | Surface background for the entire dialog shell. |
| --pk-paper-color | Paper surface for cards, accordions, and panels inside the dialog. |
| --pk-text-color | Base text color applied to headings and body text. |
| --pk-primary-color | Primary accent used for CTAs, focus rings, and links. |
| --pk-text-color-on-primary | Text color used on elements filled with the primary color, such as solid buttons. |
| --pk-secondary-color | Secondary accent, mainly used for the switch/thumb UI state. |
| --pk-focus-ring-color | Focus outline color used for keyboard focus states. |
| --pk-border-color | Border color applied to panel outlines, tables, and divider strokes. |
| --pk-border-width | Border width applied to panel outlines, tables, and divider strokes. |
| --pk-font-family | Font stack for all textual elements; falls back to your body font token. |
| --pk-spacing-unit | Spacing scale unit that drives paddings/gaps between sections. |
| --pk-control-radius | Corner radius for buttons, inputs, and interactive controls. |
| --pk-dialog-radius | Corner radius for the outer consent dialog container. |
| --pk-dialog-shadow | Box shadow applied to the consent dialog overlay. |
| --pk-dialog-max-height | Maximum height of the consent dialog; when content exceeds this limit, the dialog body scrolls. |
Example
<consent-dialog theme="light" style="
--pk-bg-color: #faf7f2;
--pk-paper-color: #f7eede;
--pk-primary-color: #b08968;
--pk-font-family: 'Segoe UI', Tahoma, sans-serif;
--pk-control-radius: 10px;
--pk-dialog-radius: 20px;
--pk-dialog-shadow: 10px 20px rgba(0, 0, 0, 0.5);
--pk-dialog-max-height: 50vh;
">
</consent-dialog>Inject custom content into specific parts of a component using named HTML slots — giving you full control over content and styling without modifying the component itself.
| Slot Name | Description |
|---|---|
| dialog-logo-top | Optional logo or brand image displayed in the header of the consent dialog. |
| dialog-logo-right | Optional logo or brand image displayed at the top right of the consent dialog. |
| dialog-title | Overrides the title in the dialog header. |
| dialog-summary-part-1 | Injects custom text for the first intro paragraph below the dialog title. |
| dialog-summary-part-2 | Injects custom text for the second intro paragraph that explains consent choices. |
| necessary-content | Replaces the default description for the Necessary category. |
| preferences-content | Custom text inside the Preferences category accordion body. |
| analytics-content | Custom text inside the Analytics category accordion body. |
| marketing-content | Custom text inside the Marketing category accordion body. |
| read-more-title | Sets the heading for the expandable “Read more” section at the bottom. |
| read-more-content | Supplies the body content shown when the “Read more” section expands. |
| privacy-policy-content | Replaces the default Privacy Policy copy. Use wording vetted by your own legal counsel, because PrivacyKit can’t verify GDPR compliance once you customize it. |
Example
<consent-dialog theme="standard" variant="standard" locale="en" version="1">
<img slot="dialog-logo-top" width="100px" src="/logo.png" alt="Company logo" />
<div slot="dialog-title" class="your-class">
<h2>We use cookies</h2>
</div>
<span slot="marketing-content">
<b>We currently do not collect cookies for marketing purposes.</b>
</span>
</consent-dialog>
When google-consent-mode is enabled, PrivacyKit reads the user's consent choices and signals them to Google Tag Manager or gtag using the Google Consent Mode v2 protocol. This happens automatically on page load and whenever the user changes their consent. No additional configuration is required beyond adding the attribute.
Pairing <consent-guard> around your GTM snippet with google-consent-mode on the dialog is an enforcement-first approach: GTM cannot load at all before consent is granted, and Google Consent Mode v2 signals are sent immediately once it does. GTM is just a container — it can host analytics tags, marketing tags, or both, depending on what you've configured inside it. Set the consent expression on <consent-guard> to match: marketing if GTM only fires marketing/ad tags, analytics if it's analytics-only, or analytics+marketing if it fires either.
<!-- Match the consent expression to what GTM actually fires: "analytics" or "marketing" -->
<consent-guard consent="analytics">
<script type="text/plain" data-src="https://www.googletagmanager.com/gtm.js?id=GTM-XXXXXXX"></script>
</consent-guard>
<consent-dialog google-consent-mode>
</consent-dialog>PrivacyKit maps its three consent categories to Google's seven Consent Mode v2 fields:
| GCM v2 field | Mapped from | Value |
|---|---|---|
| analytics_storage | Analytics | granted / denied |
| ad_storage | Marketing | granted / denied |
| ad_user_data | Marketing | granted / denied |
| ad_personalization | Marketing | granted / denied |
| functionality_storage | Preferences | granted / denied |
| personalization_storage | Preferences | granted / denied |
| security_storage | — | Always granted |
security_storage is always granted as it covers security-essential browser storage and is not subject to optional tracking consent.
PrivacyKit checks whether window.gtag is available (Google Tag Manager or gtag.js loaded). If it is, it calls:
gtag('consent', 'update', {
analytics_storage: 'granted' | 'denied',
ad_storage: 'granted' | 'denied',
ad_user_data: 'granted' | 'denied',
ad_personalization: 'granted' | 'denied',
functionality_storage: 'granted' | 'denied',
personalization_storage: 'granted' | 'denied',
security_storage: 'granted'
});If gtag is not available but window.dataLayer is, it pushes the consent update directly to the dataLayer. If neither is present, no signal is sent and nothing is queued.
When Google Tag Manager is protected by <consent-guard> — meaning it only loads after the user grants consent — PrivacyKit automatically retries the signal after GTM has finished loading.
Debugging tip: PrivacyKit logs its Google Consent Mode v2 activity to the browser console, so you can verify the behaviour directly in DevTools:
[PrivacyKit] Google Consent Mode v2 update emitted.
A consent signal was sent to gtag or the dataLayer.
[PrivacyKit] Google Consent Mode v2 update skipped because no Google tag was detected.
Neither gtag nor dataLayer was found in the browser, so nothing was sent.
openConsentDialog(): void
onConsentDialogClosed(callback: () => void): () => void
openPrivacyPolicyDialog(): voidConditionally renders children once the provided consent expression evaluates to true.
| Attribute | Type | Default / Required | Description |
|---|---|---|---|
| consent | string | unset | Consent expression to evaluate before rendering children. When unset, all categories are required. |
| Expression | Consent Required | Description |
|---|---|---|
| All Categories | If the consent attribute is omitted, all categories must be accepted for the guard to activate. | |
| necessary | None | Prevents false positives in Compliance Monitor for necessary resources that are not automatically recognized by PrivacyKit. |
| preferences | Preferences | |
| analytics | Analytics | |
| marketing | Marketing | |
| preferences+analytics | Preferences AND Analytics | |
| preferences|analytics | Preferences OR Analytics | |
| preferences+marketing | Preferences AND Marketing | |
| preferences|marketing | Preferences OR Marketing | |
| analytics+marketing | Analytics AND Marketing | |
| analytics|marketing | Analytics OR Marketing |
Example 1 – Manage Scripts
<consent-guard consent="marketing">
<script type="text/plain" data-src="https://www.googletagmanager.com/gtm/js"></script>
</consent-guard>
Example 2 – Manage Embedded Content
<consent-guard consent="analytics+marketing">
<iframe
title="YouTube video"
data-src="https://www.youtube.com/embed/abc123"
width="560"
height="315"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowfullscreen>
</iframe>
</consent-guard>
Important: Notice that managed resources in the examples use data-src instead of src, and type="text/plain" is used for scripts. PrivacyKit activates managed content after consent is granted — otherwise resources may load immediately and appear as hardcoded in Compliance Monitor.
Render fallback content whenever an associated consent-guard blocks the primary experience.
| Attribute | Type | Default / Required | Description |
|---|---|---|---|
| for | string | required | Id of the related <consent-guard> element. |
Example
<consent-guard id="analytics-guard" consent="analytics">
<script type="text/plain" data-src="https://example.com/analytics.js"></script>
</consent-guard>
<consent-missing for="analytics-guard">
Please accept analytics cookies to continue.
</consent-missing>
Compliance Monitor observes outgoing requests and validates consent guard coverage on your live website, surfacing unmanaged trackers and regressions introduced by website changes. Inactive by default, it remains invisible to visitors and is safe to ship in production.
| Attribute | Type | Default / Required | Description |
|---|---|---|---|
| debug | boolean | false | Enables the Compliance Monitor panel on page load. For development environments only. |
| delay | number | 5000 | Network observation window (in milliseconds) before the Compliance Monitor begins validating endpoint usage and consent guard coverage. |
| ignore-first-party-subdomains | boolean | true | When true, requests to subdomains of the current domain are silently ignored. |
| fab-position | left | right | right | Controls which side of the viewport the compliance monitor FAB is pinned to. |
Example
<compliance-monitor debug delay="5000" ignore-first-party-subdomains="true" fab-position="left"></compliance-monitor>
Compliance Monitor remains hidden from visitors even when included in the production bundle. The recommended way to activate it on a live website is to append ?privacykit=monitor to the URL — it activates the monitor only for that browser session, leaving the visitor experience unaffected.
Toggle programmatically:
window.PrivacyKit?.toggleComplianceMonitor();
Avoid flickering before the web components finish loading. Without this snippet the slotted or guarded HTML can flash briefly when:
consent-dialog can flash briefly if slotted elements are used and if they render before the component definition loads.consent-guard can flash briefly if it's used for conditional HTML and it renders before the component activates.consent-missing can flash briefly if consent-missing is used and it renders before the component activates.Add styling in your light DOM to avoid flickering.
consent-dialog:not(:defined) [slot] {
display: none;
}
consent-guard:not([active]) {
display: none;
}
consent-missing:not([active]) {
display: none;
}