---
title: Components
description: ConsentRoot and the consent banner, dialog, widget, links, gate and
  DevTools components a TanStack Start app imports from c15t/tanstack-start.
group: frameworks
lastModified: "2026-10-10T16:01:45+01:00"
---
## Import from c15t/tanstack-start

`c15t/tanstack-start` exports `ConsentRoot` and re-exports every component and
hook from `c15t/react`. Import them from `c15t/tanstack-start` so your app has
one import path. They behave the same as in a React app, and render on the
server with the state the root loader resolved.

|Component|Renders|Reference|
|--|--|--|
|`ConsentRoot`|The consent runtime, seeded with the root loader's state|[Below](#consentroot)|
|`ConsentBanner`|The banner, when the policy asks for one|[ConsentBanner](/docs/frameworks/tanstack-start/components/consent-banner)|
|`ConsentDialog`|The preference dialog|[ConsentDialog](/docs/frameworks/tanstack-start/components/consent-dialog)|
|`ConsentWidget`|The preference controls inline in a page|[ConsentWidget](/docs/frameworks/tanstack-start/components/consent-widget)|
|`ConsentDialogLink`|A button that opens the dialog, for your footer|[ConsentDialogLink](/docs/frameworks/tanstack-start/components/consent-dialog-link)|
|`ConsentDialogTrigger`|A floating, draggable button that opens the dialog. `ConsentDialogTriggerToolbar` adds your own actions beside it|[ConsentDialogTrigger](/docs/frameworks/tanstack-start/components/consent-dialog-trigger)|
|`ConsentGate`|Its children only while a category is allowed|[ConsentGate](/docs/frameworks/tanstack-start/components/consent-gate)|
|`ConsentTheme`|A `<style>` element with your theme tokens|[Customize](/docs/frameworks/tanstack-start/customize)|
|`DevTools` from `c15t/react/devtools`|A development panel for consent state and scripts|[DevTools](/docs/frameworks/tanstack-start/components/dev-tools)|

Render every component inside `ConsentRoot`. Do not also mount
`ConsentProvider`; `ConsentRoot` already renders one.

## ConsentRoot

`ConsentRoot` wraps the app in the root route. It takes the state the root
loader resolved on the server and creates the consent runtime from it, so the
server HTML and the first browser render match. The
[quickstart](/docs/frameworks/tanstack-start/quickstart#resolve-consent-in-the-root-route)
shows it in context.

|Prop|Purpose|
|--|--|
|`state`|Required. The loader's consent state, a promise of it for a [streamed loader](/docs/frameworks/tanstack-start/rendering#stream-the-page-while-consent-resolves), or `{}` for [pages without a server render](/docs/frameworks/tanstack-start/rendering#spa-mode-prerendered-pages-and-static-hosts)|
|`scripts`|Consent-gated vendor scripts. See [scripts and embeds](/docs/frameworks/tanstack-start/scripts)|
|`vendors`|Vendors listed under their category with their own switch|
|`networkBlocker`|Rules that hold `fetch` and `XMLHttpRequest` calls until their category is allowed|
|`clearOnRevocation`|Cookies and storage keys to delete when a category is denied|
|`persistence`|Stores the visitor's choice. On by default|
|`scriptLoader`|Options for the script loader module|
|`options`|Any other `ConsentProvider` option, such as `theme`, `i18n`, `presentation`, `callbacks`, `consentCategories`, `reloadOnConsentRevoked` or `preloadDialog`|

The state carries the backend URL, the mode and the route prefix you passed
to `createConsentStateHandler`, so `ConsentRoot` has no props for them. With
`state={{}}`, it takes the backend URL from `consentManifest()` and uses
`manifest()`. Without a backend URL from either, it throws, unless the mode is
`offline()`. `options.mode` replaces the state's mode: `manifest()`,
`hosted()` or `offline()` from `c15t/tanstack-start`, or a transport such as
`custom(transport)`.

`ConsentRoot` creates the runtime once, when it mounts, and ignores later
changes to `state`. Keep it in the root route so client navigation never
remounts it.

The root entry also exports `consentPrefetchHead` for pages without a server
render, and `buildPrefetchScript`, the script builder behind it.

## Server and other entry points

|Import|Exports|Use|
|--|--|--|
|`c15t/tanstack-start`|`manifest`, `hosted`, `offline`|The modes, as data for `createConsentStateHandler({ mode })`. See [consent modes](/docs/concepts/modes)|
|`c15t/tanstack-start/server`|`createConsentStateHandler`, `resolveConsent`, `consentLoaderOptions`, `mergeInitIntoConsentState`|Resolve the visitor's state in a server function. `createConsentStateHandler` takes `mode`, `routePrefix`, `proxy`, `snapshot` and the `resolveConsent` options|
|`c15t/tanstack-start/middleware`|`consentRequestMiddleware`|Read location, language and privacy headers on every request. See [geography headers](/docs/frameworks/tanstack-start/geography-headers)|
|`c15t/tanstack-start/api`|`createConsentRoute`|Serve `/api/c15t/*` from `src/routes/api/c15t/$.ts`|
|`c15t/tanstack-start/build`|`consentManifest`|Vite plugin that bundles the manifest at build time. See the [quickstart](/docs/frameworks/tanstack-start/quickstart#bundle-your-policy-at-build-time)|
|`c15t/generated`|`snapshot`, `backendURL`|The manifest and backend URL the plugin fetched. `snapshot` is `undefined` in the browser bundle|
|`c15t/tanstack-start/static`|`createStaticConsentResolver`, `loadStaticManifest`, `createStaticManifestModule`, `resolveUnknownLocationInit`|Lower-level helpers for a build-time manifest. See [rendering](/docs/frameworks/tanstack-start/rendering#spa-mode-prerendered-pages-and-static-hosts)|
|`c15t/tanstack-start/headless`|Headless hooks|[Custom markup](/docs/frameworks/tanstack-start/headless)|
|`c15t/tanstack-start/components/consent-dialog-link`|`ConsentDialogLink` only|A module that needs the link without loading the rest of the adapter|

`resolveConsent` is the function behind `createConsentStateHandler`. Call it
directly from a server route or middleware that already holds the `Request`,
and pass it as `request`. Import `server`, `middleware` and `api` only from
server code.

## IAB TCF components

Import `IABProvider`, `IABConsentBanner` and `IABConsentDialog` from
`c15t/react/iab`, render them inside `ConsentRoot` next to
`ConsentBanner` and `ConsentDialog`, and load
`c15t/tanstack-start/styles.css` and `c15t/tanstack-start/iab/styles.css`
with `styles: false`. The stock banner and dialog stay closed
under an IAB policy. See
[IAB TCF](/docs/frameworks/tanstack-start/iab).
