Skip to main content

TanStack Start Consent API

Hooks

Read only the state you need

c15t/tanstack-start re-exports every hook from c15t/react. Each hook reads the runtime from ConsentRoot, so call hooks in components rendered inside it. Any route component qualifies, because ConsentRoot wraps the Outlet in the root route.

src/components/optional-feature.tsx
import { useConsent } from 'c15t/tanstack-start';

export function OptionalFeature() {
	const allowed = useConsent('marketing');
	return allowed ? <div>Optional marketing content</div> : null;
}

On the server, hooks read the state the root loader resolved, so a route renders the same result in the server HTML and in the first browser render.

Call hooks inside the consent provider. useConsent reads effective permission, which can be true under an opt-out policy without a recorded grant.

NeedHook
One category's current permissionuseConsent(category)
All current permissionsuseConsents()
Recorded per-category choicesuseExplicitChoice()
Whether one declared vendor may runuseVendorAllowed(id)
Whether a prompt is requiredusePromptRequirement()
Active policy and resolutionusePolicyRule(), usePolicyResolution()
Save an explicit choiceuseSaveConsents()
Open or close a consent surfaceuseSetActiveUI()
Acknowledge a noticeuseDismissNotice()

Open the preference dialog

Set the active surface to 'dialog' from any component inside ConsentRoot:

src/components/privacy-menu-item.tsx
import { useSetActiveUI } from 'c15t/tanstack-start';

export function PrivacyMenuItem() {
	const setActiveUI = useSetActiveUI();
	return (
		<button type="button" onClick={() => setActiveUI('dialog')}>
			Cookie preferences
		</button>
	);
}

ConsentDialogLink does the same without a hook.

Save from a visitor action

src/components/reject-button.tsx
import { useSaveConsents } from 'c15t/tanstack-start';

export function RejectButton() {
	const save = useSaveConsents();
	return (
		<button type="button" onClick={() => void save('none')}>
			Reject optional
		</button>
	);
}

This is an isolated action example, not a complete policy-aware banner. Use the stock UI or headless surface actions for a complete prompt. Do not call save on mount to persist a state derived from permissions.

Use focused hooks for feature gates. For a complete custom prompt or preference center, use useHeadlessConsentUI() for surface actions and useConsentDraft() for staged choices, inside one ConsentDraftProvider so the save commits the same draft. v3 has no useConsentManager(); the use-consent-manager-to-hooks codemod rewrites most of its calls to hooks. Read how consent works before treating a callback as evidence of a choice.

Where hooks do not work

Hooks need React context, so they do not run in loaders, beforeLoad, server functions or server routes. On the server, read the request's consent state with resolveConsent from c15t/tanstack-start/server.