---
title: ConsentDialogLink
description: Let visitors reopen c15t preferences from a Svelte footer with
  ConsentDialogLink, an unstyled button that renders only when the policy offers
  preferences.
group: frameworks
lastModified: "2026-10-10T16:01:45+01:00"
---
## Reopen preferences from your footer

`ConsentDialogLink` is an unstyled button that opens the preference dialog.
Put it where your site keeps its legal links, so preferences stay reachable
after the banner closes:

```svelte title="src/App.svelte"
<script lang="ts">
	import { posthog } from '@c15t/integrations/posthog';
	import {
		ConsentBanner,
		ConsentDialog,
		ConsentDialogLink,
		ConsentProvider,
		manifest,
	} from '@c15t/svelte';

	const scripts = [
		posthog({
			id: 'phc_your_project_key',
			initOptions: { cookieless_mode: 'never' },
			loadMode: 'after-consent',
		}),
	];
</script>

<ConsentProvider mode={manifest()} {scripts}>
	<main>
		<h1>c15t + Svelte</h1>
		<p>Your app goes here.</p>
	</main>
	<footer>
		<ConsentDialogLink>Privacy settings</ConsentDialogLink>
	</footer>
	<ConsentBanner />
	<ConsentDialog />
</ConsentProvider>
```

It needs `ConsentDialog` mounted in the same provider. Inside a
`ConsentGate` placeholder it gives visitors a way to allow a blocked embed:

```svelte title="src/YouTubeEmbed.svelte"
<script lang="ts">
	import { ConsentDialogLink, ConsentGate } from '@c15t/svelte';
</script>

<!-- The iframe mounts only while measurement is allowed. -->
<ConsentGate category="measurement">
	{#snippet placeholder()}<div class="placeholder">
			<p>Allow measurement to load this YouTube video.</p>
			<ConsentDialogLink>Choose video permissions</ConsentDialogLink>
		</div>{/snippet}
	<iframe
		title="YouTube video"
		src="https://www.youtube-nocookie.com/embed/czTksCF6X8Y?playsinline=1"
		allow="encrypted-media; picture-in-picture"
		allowfullscreen
	></iframe>
</ConsentGate>
```

## Props

`ConsentDialogLink` takes its label as children and passes every other
attribute, such as `class`, `id` or `aria-describedby`, to the `<button>` it
renders.

|Prop|Type|Default|Behavior|
|--|--|--|--|
|`children`|`Snippet`|required|The visible label, such as "Privacy settings".|
|`noStyle`|`boolean`|`true`|Unstyled by default so it matches your footer links. Set `false` for c15t's button style.|
|`onclick`|`(event: MouseEvent) => void`|none|Runs before the dialog opens. Call `event.preventDefault()` to stop it opening.|
|any button attribute|||Passed to the `<button>`.|

There is no `asChild`. To style it like your links, give it the same class,
and reset the button's border, background and padding in that class.

## Behavior

* The link renders only when the policy offers a way to change preferences:
  a prompt or a visitor right. Visitors in a
  region with no consent law and no rights see no link.
* A click sets the active surface to `'dialog'`. It needs a mounted
  `ConsentDialog` in the same provider to show anything.
* It starts loading the dialog chunk in browser idle time while mounted, and
  on hover or focus. See [ConsentDialog](./consent-dialog#how-the-dialog-loads).

## Accessibility

The link is a `<button type="button">`, so keyboard users reach it with Tab
and activate it with Enter or Space. Its accessible name is its text. Keep the
text specific, such as "Privacy settings" or "Cookie preferences", rather
than "Click here".

## Style the link

The button carries `data-testid="consent-dialog-link"` and
`data-c15t-rights` with the rights the policy grants, separated by spaces.
Style it with your own class; with `noStyle` on, c15t adds no classes.
