Skip to main content

Astro Components

ConsentDialog

Add the dialog to your layout

Render one ConsentDialog in the layout that wraps every page:

src/layouts/base.astro
---
import { ClientRouter } from 'astro:transitions';
import {
	ConsentBanner,
	ConsentDialog,
	ConsentDialogLink,
	ConsentScript,
} from 'c15t/astro/components';

interface Props {
	title: string;
}

const { title } = Astro.props;
---

<html lang="en">
	<head>
		<meta charset="utf-8" />
		<meta content="width=device-width, initial-scale=1" name="viewport" />
		<title>{title}</title>
		<ConsentScript />
		<ClientRouter />
	</head>
	<body>
		<slot />
		<footer>
			<ConsentDialogLink>Privacy settings</ConsentDialogLink>
		</footer>
		<ConsentBanner />
		<ConsentDialog />
	</body>
</html>

ConsentDialog renders an empty host element on the server. The preference dialog mounts into the page the first time something opens it:

  • The banner's Customize button, or a "Manage preferences" or "Do not sell or share my data" button on a notice.
  • A ConsentDialogLink.
  • A link to #c15t-preferences, when the page loads with that hash.
  • openDialog() from c15t/astro/client.

Props

PropTypeDefaultEffect
preloadbooleanfalseDownloads the dialog once the browser is idle, on every page that renders it
legalLinks('privacyPolicy' | 'cookiePolicy' | 'termsOfService')[] | nullNoneWhich links from the integration's legalLinks the dialog shows, the same list ConsentBanner takes

When the dialog downloads

A visitor who only accepts or rejects from the banner never downloads the dialog. The download starts before the click, when the pointer moves over a control that opens the dialog or keyboard focus reaches one. On a touch screen, the tap itself starts it, so the first open can wait for the download.

With preload, the dialog downloads in the browser's first idle period, or after two seconds in browsers without requestIdleCallback. Use it when the first open must feel instant for every visitor. It costs a background download on each page, including for visitors who never open the dialog.

To download the dialog from your own code, call preloadDialog() from c15t/astro/client.

Which framework renders it

The dialog is the ConsentDialog component of the framework that the integration's ui option names:

uiRenders withAstro integration to install
'svelte' (default)@c15t/svelte@astrojs/svelte and svelte
'react'c15t/react@astrojs/react, react and react-dom
'vue'c15t/vue@astrojs/vue and vue

Pick the framework your site already ships, so visitors do not download a second one for a single dialog. See Dialog islands and your own islands.

What the dialog contains

The dialog lists the categories the policy covers, each with a switch, and offers Accept All, Reject All and Save Settings. necessary is always on. The dialog follows the integration's theme, presentation.preferences and consentCategories. With vendors declared, each category also lists its vendors with a switch per vendor. See vendor consent.

To link your policies from the dialog, define them in the integration's legalLinks option and list the keys in the legalLinks prop:

src/layouts/base.astro (partial)
<ConsentDialog legalLinks={['privacyPolicy', 'cookiePolicy']} />

c15t passes the list to the Svelte, React or Vue dialog island. A key renders only when the integration defines it. A link without a label reads as the translated name for its type, such as "Privacy Policy" in English.

Save Settings, Accept All and Reject All record a choice and close the dialog. Turning off a category that was allowed reloads the page, unless the integration sets reloadOnConsentRevoked: false. See withdraw consent without reloading.

The dialog does not open while no policy is resolved, or under a rule that owes no consent interface. An openDialog() call made while /init is still in flight waits for the answer.

Stylesheets

The page carries only the banner's rules. The first time a visitor reaches for the dialog, c15t links the dialog's rules from @c15t/ui/styles/sheets/dialog.css, plus the primitives stylesheet for the Svelte dialog, and waits for them to load before the dialog paints. On a Tailwind CSS 3 site, the dialog's rules come with c15t/astro/styles.css on every page, and c15t links only the primitives stylesheet. With styles: false, import c15t/astro/styles.css yourself, which holds the dialog's rules too, and c15t/astro/primitives.css for the Svelte dialog. See load the stylesheet yourself.

Across ClientRouter navigation

The dialog host is part of <body>, which ClientRouter replaces. When a visitor navigates with the dialog open, c15t mounts it again on the new page, so it stays open. A stylesheet c15t linked for the dialog carries over to the new page too.

Accessibility

The dialog keeps the focus and keyboard behavior of its framework's ConsentDialog. It opens as a modal dialog, and Escape closes it. Whether it locks page scroll follows presentation.preferences in the integration options. Every framework renders the same markup and labels, so the dialog behaves the same whichever ui you pick.

Next steps