---
title: ConsentDialogTrigger
description: Add a floating, draggable privacy button to a SvelteKit layout with
  ConsentDialogTrigger, and set its corner, size, saved position, accessible
  name and callbacks.
group: frameworks
lastModified: "2026-10-10T16:01:45+01:00"
---
## Add a floating privacy button

`ConsentDialogTrigger` is a small round button, fixed to a corner of the
viewport, that opens the preference dialog. It keeps preferences one click
away on every page without a footer link. Render it next to `ConsentDialog`:

```svelte title="src/lib/privacy-trigger.svelte"
<script lang="ts">
	import { ConsentDialog, ConsentDialogTrigger } from '@c15t/svelte';
</script>

<!-- A floating button in the bottom-left corner that opens preferences.
     Visitors can drag it to another corner; c15t remembers where. -->
<ConsentDialogTrigger defaultPosition="bottom-left" size="sm" />
<ConsentDialog />
```

Render the component inside `ConsentProvider`. `ConsentDialog`'s
`showTrigger` prop renders the same button for you, but only after the dialog
chunk loads; a separate `ConsentDialogTrigger` is part of the page from the
first render.

## Props

|Prop|Type|Default|Behavior|
|--|--|--|--|
|`defaultPosition`|`'bottom-right'`, `'bottom-left'`, `'top-right'` or `'top-left'`|`'bottom-right'`|The corner it starts in.|
|`persistPosition`|`boolean`|`true`|Remembers the corner a visitor drags it to, in local storage.|
|`showWhen`|`'always'` or `'never'`|`'always'`|`'never'` hides it.|
|`size`|`'sm'`, `'md'` or `'lg'`|`'md'`|Button size.|
|`ariaLabel`|`string`|`'Open privacy settings'`|Accessible name. Translate it yourself; it does not come from `i18n`.|
|`noStyle`|`boolean`|`false`|Drops c15t's classes, including the fixed positioning.|
|`class`|`string`|none|Extra class on the button.|
|`onclick`|`(event: MouseEvent) => void`|none|Runs before the dialog opens. Call `event.preventDefault()` to stop it.|
|`onPositionChange`|`(corner) => void`|none|Runs after a drag moves it to another corner.|

## Behavior

* The button renders only when the policy offers a way to change preferences,
  and hides while the dialog is open.
* Visitors can drag it. On release it snaps to the nearest corner in the
  direction of the drag. A drag does not open the dialog; a click does.
* The icon follows the project's branding.
* It is rendered into `document.body`, so a parent's `overflow` or
  `transform` does not clip it.
* It starts loading the dialog chunk in idle time and on hover or focus, like
  the other buttons that open the dialog.
* While `ConsentDevTools` is mounted, it becomes a two-button toolbar: the
  preferences button stays in the corner and a DevTools button sits beside it.
  The DevTools panel opens next to the toolbar instead of from its own
  launcher. See [DevTools](./dev-tools).

## Accessibility

The trigger is a `<button type="button">` with `aria-label`, since it shows
only an icon. Keep the label in the page's language by passing `ariaLabel`.
Dragging needs a pointer; keyboard users activate it with Enter or Space and
cannot move it, so pick a `defaultPosition` that does not cover your own
controls.

## Style the trigger

The button carries `data-testid="consent-dialog-trigger"`,
`data-c15t-trigger="true"` and `data-c15t-rights`. Its colors come from the
`--c15t-*` tokens; [theme tokens](/docs/customization/tokens) lists them.

## Trigger in the server HTML

Rendered in the root layout with server-resolved consent, the trigger is in the
server HTML at its default corner. After hydration it moves to
`document.body` and, if the visitor dragged it on an earlier visit, to the
saved corner.
