---
title: Components
description: Every c15t Astro component, from ConsentScript and ConsentBanner to
  the server island banner, the preference dialog, its link and the IAB TCF
  surfaces, with import paths and links to each reference.
group: frameworks
lastModified: "2026-10-10T16:01:45+01:00"
---
## Where the components go

Every component reads `Astro.locals.c15t`, which the integration's middleware
sets on each request. Put them in the layout that wraps every page:

```astro title="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>
```

The `c15t()` integration in `astro.config.mjs` plays the part a provider plays
in React or Vue. It holds the configuration every component reads. See
[Integration options](/docs/frameworks/astro/integration).

## Component reference

Import the components by name from `c15t/astro/components`. Astro compiles
the `.astro` files it re-exports, so a page ships only what it renders.
`ConsentBannerDeferred` is the exception: it renders a server island, which
Astro refuses to build on a site without an adapter, so import it from its
own path.

|Component|Import from|Renders|
|--|--|--|
|[`ConsentScript`](/docs/frameworks/astro/components/consent-script)|`c15t/astro/components`|Inline scripts for the boot payload and color scheme, and the theme `<style>`|
|[`ConsentBanner`](/docs/frameworks/astro/components/consent-banner)|`c15t/astro/components`|The banner, as server HTML|
|[`ConsentBannerDeferred`](/docs/frameworks/astro/components/consent-banner-deferred)|`c15t/astro/components/consent-banner-deferred.astro`|The banner, in a server island|
|[`ConsentDialog`](/docs/frameworks/astro/components/consent-dialog)|`c15t/astro/components`|An empty host for the preference dialog island|
|[`ConsentDialogLink`](/docs/frameworks/astro/components/consent-dialog-link)|`c15t/astro/components`|A button or link that opens a dialog|
|[`IABConsentBanner`](/docs/frameworks/astro/components/iab-consent-banner)|`c15t/astro/components`|The IAB TCF banner, as server HTML|
|[`IABConsentDialog`](/docs/frameworks/astro/components/iab-consent-dialog)|`c15t/astro/components`|An empty host for the IAB TCF dialog island|

## How much JavaScript each component ships

The banners and the link are plain `.astro` markup and ship no framework
JavaScript. One small shared script turns their buttons into consent actions.
The dialogs are islands in the framework the integration's `ui` option names,
and they download only when a visitor first reaches for one. See
[Dialog islands and your own islands](/docs/frameworks/astro/islands).

Astro has no floating preferences widget, consent gate component or dev tools
component. Gate embeds with the pattern in
[Embeds](/docs/frameworks/astro/embeds), and inspect consent with the
[client API](/docs/frameworks/astro/client-api) and DevTools.

## What every component needs

* The `c15t()` integration in `astro.config.mjs`, with its middleware on.
  `ConsentBanner` and `IABConsentBanner` throw when `Astro.locals.c15t` is
  missing, and the others render nothing useful without it.
* A route that the middleware does not skip. A route in `middleware.skip` has
  no `Astro.locals.c15t`.
* For the dialogs, the Astro integration of the `ui` framework, listed before
  `c15t()`.
