---
title: ConsentRoot
description: Mount the c15t banner, preference dialog and floating trigger in
  Nuxt with the globally registered ConsentRoot, rendered on the server.
group: frameworks
lastModified: "2026-10-10T16:01:45+01:00"
---
## Render `ConsentRoot` in `app.vue`

The Nuxt module registers `ConsentRoot` globally, so you render it without an
import. Put it in `app.vue`, next to `<NuxtPage />`:

```vue title="app/app.vue"
<template>
	<ConsentRoot />
	<NuxtPage />
	<footer>
		<ConsentDialogLink>Privacy settings</ConsentDialogLink>
	</footer>
</template>
```

`ConsentRoot` reads the consent runtime the module creates. Keep it in
`app.vue` so it stays mounted when the route changes. It brings its own
styles.

`ConsentRoot` is not a provider. The module's plugin already gives every
component the consent runtime, so nothing needs to sit inside it. Render
`<ConsentRoot />` next to `<NuxtPage />` as shown above. If you wrap the app
in it instead, the page still renders after the banner, dialog and trigger,
but wrapping adds nothing.

Always mount the Nuxt `ConsentRoot`, not the Vue one from
`c15t/vue/vue-plugin`. The Nuxt component renders the banner on the
server.

## What ConsentRoot renders

`ConsentRoot` picks the surfaces for the visitor's policy:

|Policy|Banner|Preferences|
|--|--|--|
|Standard, opt-in or opt-out|[`ConsentBanner`](/docs/frameworks/nuxt/components/consent-banner)|[`ConsentManager`](/docs/frameworks/nuxt/components/consent-manager)|
|IAB TCF, with a vendor list|[`IABConsentBanner`](/docs/frameworks/nuxt/components/iab-consent-banner)|[`IABConsentDialog`](/docs/frameworks/nuxt/components/iab-consent-dialog)|

It also renders [`ConsentDialogTrigger`](/docs/frameworks/nuxt/components/consent-dialog-trigger)
when the `showTrigger` option is `true`.

The banner is part of the server render. When the server resolves the policy, in the default `manifest()` mode or `hosted()`,
a visitor whose policy asks for consent gets the banner
in the first HTML, with no layout shift after hydration. On prerendered and
cached routes the banner appears after the browser resolves the policy. See
[rendering](/docs/frameworks/nuxt/rendering).

The IAB surfaces replace the standard ones only when the module's `iab`
option is set and the policy uses the `iab` model. The dialog and the IAB
surfaces load as separate chunks. `ConsentRoot`
prefetches the dialog chunk after the page's `load` event, mounts the dialog
the first time preferences open, and keeps it mounted after that so its close
animation runs.

The banner and the trigger are separate chunks too, so their CSS is not part
of your app's entry stylesheets. Every page preloads the banner chunk. With
Nuxt's `features.inlineStyles`, on by default, it also preloads the banner's
CSS instead of linking it: a server-rendered banner paints with the styles
Nuxt writes into the page head, so no c15t stylesheet blocks the first paint.
The browser applies the CSS with the chunk, before it shows a banner it
renders itself. The trigger chunk loads after the page mounts, and only when
`showTrigger` is `true`.

## Theme tokens

The Nuxt module's plugin, not `ConsentRoot`, writes the `tokens` option
into a `<style id="c15t-css-vars">` tag in the page head, on every page and
with the module's `nonce`. During server rendering and prerendering the tag is
in the first HTML. See
[customize](/docs/frameworks/nuxt/customize#set-theme-tokens).

## Props

|Prop|Type|Default|Behavior|
|--|--|--|--|
|`country`|`string`|The location from the request headers|Overrides the visitor's country and resolves the policy again.|
|`region`|`string`|The location from the request headers|Overrides the visitor's region, such as `CA`, and resolves the policy again.|
|`language`|`string`|The browser language|Overrides the language and resolves the policy again, which fetches the banner and dialog text in that language.|

Use `country` and `region` to preview another region's policy while you
build, such as `<ConsentRoot country="DE" />`. Bind `language` to your site's
current language. See [translations](/docs/frameworks/nuxt/translations).

## Compose the surfaces yourself

`ConsentRoot` is the same as rendering the banner, dialog and trigger with the
right conditions. To place them yourself, render them in place of
`ConsentRoot`, as in
[ConsentBanner](/docs/frameworks/nuxt/components/consent-banner#import-the-banner-in-place-of-consentroot). Do not
render `ConsentRoot` next to them, or the visitor sees two banners.

## Verify

Build and start the app, then view the source of a page under a policy that
asks for consent. The HTML holds `data-testid="consent-banner-root"` and the
`c15t-css-vars` style tag. Click Customize and the preference dialog opens.
Reject, reload, and confirm the banner stays closed.

## Next steps

* [Nuxt module](/docs/frameworks/nuxt/module) lists the options `ConsentRoot`
  reads.
* [Customize](/docs/frameworks/nuxt/customize) changes tokens, layout and
  slots.
* [Headless](/docs/frameworks/nuxt/headless) replaces `ConsentRoot` with your
  own markup.
