SvelteKit Customization
Customize
Pick the right tool
| Change | Use |
|---|---|
| Brand colors, radius, type, spacing | generateThemeCSS() in a server load, or --c15t-* variables in a stylesheet |
| One part of one component | theme.slots on the provider |
| Button styles by action | theme.consentActions |
| Shape, position, blocking, button order | ConsentBanner props or presentation |
| Wording and languages | ConsentBanner text props, or translations |
| Different markup | Headless |
Customization explains how the pieces fit together across frameworks.
See the design gallery for five banner designs, from a bottom bar to a fully custom one, with tested code for this framework.
Render brand tokens on the server
The provider's theme prop does not turn colors, radius or other tokens into
CSS in the browser. Generate the CSS on the server instead, so the first paint
already uses your brand. Install @c15t/ui, which has the generator:
Put the theme in a module under src/lib/server. SvelteKit refuses to import
server-only modules into browser code, so the generator never reaches the bundle:
Return the CSS from a layout load. If your root +layout.server.ts already
exports loadConsent from the quickstart, call it from your own load and
return themeCSS next to its consent, as in
({ ...(await loadConsent(event)), themeCSS }). A separate layout looks like
this:
Render it in <svelte:head> in the layout:
SvelteKit writes <svelte:head> content before its stylesheet links, and
c15tHandle adds c15t's default rules at the end of <head>. The
generateThemeCSS selectors are more specific than those defaults, so the
theme still wins. Keep the c15t-theme id. In development, the provider logs a warning when its
theme prop has tokens and the page has no <style id="c15t-theme">. generateThemeCSS escapes <,
so its output is safe inside a <style> element.
generateThemeCSS fills in what you leave out, such as a readable text color
for your primary color. Pass a color scheme as its second argument,
'dark' or 'system', to include dark tokens. Keep slot styles and
consentActions in the provider's theme prop; the server CSS covers tokens
only. Theme tokens lists every token.
Use a stylesheet instead
For fixed brand values you can skip the generator. Write the --c15t-*
variables on :root in a stylesheet and import it in the root layout:
Set the hover and text colors yourself; a stylesheet does not derive them.
Pick one of the two for each token. generateThemeCSS output outranks a plain
:root rule, so a --c15t-* value you set on :root loses to the generated
theme wherever the two overlap. To override a generated value from your
stylesheet, write the rule on :root:root, or move the value into the theme.
Switch to dark tokens
The provider's colorScheme prop switches on the dark token set: 'dark'
always, 'system' when the operating system prefers dark, 'light' never. It
toggles a c15t-dark class on <html>. Left unset, the provider copies a
dark class on <html> into c15t-dark, so an app with its own dark mode
toggle gets the dark tokens without the prop. Pass null if your app sets
c15t-dark itself. Override dark values under :root.dark and
:root.c15t-dark in your stylesheet. Dark mode
covers a dark first paint.
Style one part with theme slots
The provider's theme prop still applies slot styles in the browser. A slot
takes a class name, or { className, style, noStyle }. Svelte applies a
slot's class and style on every stock part, including the IAB banner and
dialog:
Pass it as theme={theme} on ConsentProvider. Define the class in a
global stylesheet, or with :global(.brand-banner-card) in a component,
because Svelte scopes component styles. The Svelte components read these
slots:
| Component | Slots |
|---|---|
ConsentBanner | consentBanner, consentBannerCard, consentBannerHeader, consentBannerTitle, consentBannerDescription, consentBannerFooter, consentBannerFooterSubGroup, consentBannerRights, consentBannerRightLink, consentBannerTag, consentBannerOverlay |
ConsentDialog | consentDialog, consentDialogCard, consentDialogHeader, consentDialogTitle, consentDialogDescription, consentDialogContent, consentDialogTag |
ConsentWidget | consentWidget, consentWidgetFooter, consentWidgetFooterSubGroup, consentWidgetTag |
ConsentDialogTrigger | consentDialogTrigger, consentDialogTriggerIcon |
IABConsentBanner | iabConsentBanner, iabConsentBannerTag, iabConsentBannerOverlay |
ConsentGate | consentGate, consentGateTitle, consentGateButton |
| Buttons in every component | buttonPrimary, buttonSecondary |
Slot names are not React's components.banner.card keys; do not copy a React
configuration. Use slots when one part should change and tokens when a value
should change everywhere. class on a component, such as
<ConsentBanner class="...">, goes on its root.
Component parts explains the attributes each
element carries, and Tailwind CSS shows the
Svelte and SvelteKit setups for Tailwind 4 and 3.
Change button styles by action
theme.consentActions picks each button's style by what it does, whichever
order the policy puts the buttons in:
A per-action entry overrides primary, which overrides default. The policy
decides which action is primary.
Change the banner shape and position
Set the shape on the banner itself, or for every surface with the provider's
presentation prop:
variant | Positions |
|---|---|
floating | bottom-left (default), bottom-right, top-left, top-right, bottom-center, top-center |
bar | bottom (default), top |
widget | bottom-right (default), bottom-left, top-left, top-right |
wall | center |
blocking adds a backdrop, locks scrolling, traps focus and stops outside
clicks from closing the banner. layout and primaryButton change the button
order and emphasis. The policy wins where they conflict. A policy that requires
a reject button keeps it, whatever the layout says.
Change the copy
For one banner, the text props on ConsentBanner, such as title and
rejectButtonText, replace the copy in every mode:
For site-wide copy, pass the provider's i18n messages. In offline() mode
they merge over the bundled English copy. In hosted() mode they merge over
the backend's copy for the same language, key by key, so keys you leave out
keep the wording from your Inth project.
Translations covers both, the message keys and switching
languages. Copy and translations covers
wording for each action.
Turn off animations
disableAnimation on the provider turns off the banner and dialog animations,
and the same prop on ConsentBanner, ConsentDialog, IABConsentBanner or
IABConsentDialog overrides it for one surface. Left unset, the provider
follows the visitor's reduced motion setting.
Motion and animation covers the duration and
easing tokens.
Remove c15t's styles
Set noStyle on one component or on the provider to render the same markup
and behavior without c15t's classes. Style the data-* attributes and your
slot classes instead. For different markup, see the headless page.