ConsentDialog
ConsentDialog is a modal that shows toggles for each consent category. In opt-in jurisdictions, it typically opens when users click "Customize" on ConsentBanner. It can also be controlled programmatically for use on settings pages regardless of jurisdiction.
Basic Usage
import { ConsentManagerProvider, ConsentBanner, ConsentDialog } from '@c15t/nextjs';
export function ConsentManager() {
return (
<ConsentManagerProvider options={{ mode: 'hosted', backendURL: '/api/c15t' }}>
<ConsentBanner />
<ConsentDialog />
</ConsentManagerProvider>
);
}Controlled State
By default, the dialog follows activeUI === 'dialog' from the consent store. Use the open prop for manual control:
import { useState } from 'react';
function SettingsPage() {
const [open, setOpen] = useState(false);
return (
<>
<button onClick={() => setOpen(true)}>Privacy Settings</button>
<ConsentDialog open={open} />
</>
);
}Or use the hook to open it programmatically:
import { useConsentManager } from '@c15t/nextjs';
function PrivacyLink() {
const { setActiveUI } = useConsentManager();
return (
<button onClick={() => setActiveUI('dialog')}>
Manage cookies
</button>
);
}Floating Trigger
Add a floating button that lets users re-open the dialog after dismissing the banner:
{/* Default trigger */}
<ConsentDialog showTrigger />
{/* Custom trigger */}
<ConsentDialog
showTrigger={{
icon: 'settings',
defaultPosition: 'bottom-left',
showWhen: 'after-consent',
size: 'sm',
}}
/>Branding
Hide the c15t branding tag:
<ConsentDialog hideBranding />Styling First
Info
If you are only changing visuals, stay with the stock dialog and use the theme system first. Start with tokens and slots such as consentDialogCard, consentWidgetFooter, and consentDialogTag. See Styling Overview.
<ConsentManagerProvider
options={{
theme: {
colors: {
surface: '#fffdf8',
surfaceHover: '#f6f3ee',
},
slots: {
consentDialogCard: 'rounded-[32px] shadow-xl',
consentDialogHeader: 'gap-3',
consentWidgetFooter: 'gap-3 pt-6',
consentDialogTag: 'shadow-none',
},
},
}}
>
<ConsentDialog />
</ConsentManagerProvider>Dialog copy should be changed through ConsentManagerProvider.options.i18n, not by rebuilding the dialog structure.
Advanced: Compound Components
Use compound components only when you need custom dialog markup while still keeping c15t primitives and policy-aware footer actions:
<ConsentDialog.Root>
<ConsentDialog.Overlay />
<ConsentDialog.Card>
<ConsentDialog.Header>
<ConsentDialog.HeaderTitle />
<ConsentDialog.HeaderDescription />
</ConsentDialog.Header>
<ConsentDialog.Content>
<ConsentWidget.Root>
<ConsentWidget.Accordion type="single">
<ConsentWidget.AccordionItems />
</ConsentWidget.Accordion>
<ConsentWidget.PolicyActions />
</ConsentWidget.Root>
</ConsentDialog.Content>
<ConsentDialog.Footer />
</ConsentDialog.Card>
</ConsentDialog.Root>ConsentDialog.Root— Portal container with focus trap, scroll lock, and animationConsentDialog.Card— Main dialog cardConsentDialog.Header— Contains title and descriptionConsentDialog.HeaderTitle— Dialog titleConsentDialog.HeaderDescription— Description with optionallegalLinksConsentDialog.Content— Main content area (typically containsConsentWidget)ConsentDialog.Footer— Footer with optional branding (hideBrandingprop)ConsentDialog.Overlay— Backdrop overlayConsentWidget.PolicyActions— Renders policy-aware grouped dialog actions
For a quick pre-composed layout, use the shorthand card:
<ConsentDialog.Root>
<ConsentDialog.ConsentCustomizationCard />
</ConsentDialog.Root>ConsentWidget.PolicyActions uses stock c15t widget buttons and translations by default. Pass renderAction only when you need to customize the action mapping, and return stock widget button compounds if you want to preserve built-in behavior and copy.
For fully manual control over dialog action rendering, use useHeadlessConsentUI() and map dialog.actionGroups yourself.
If the stock dialog structure still works, prefer tokens, slots, and provider configuration instead.
Props
Warning: ExtractedTypeTable: Could not extract "ConsentDialogProps" from "./packages/react/src/components/consent-dialog/consent-dialog.tsx" using base path "/vercel/path0/apps/c15t-docs/.leadtype/c15t". Verify the path/name and that the file is included by your tsconfig.