Docs navigation
className overrides
Pass classes through the classNames prop to style individual elements. Use this when appearance.variables is too broad — a wider modal, a two-column reason grid, a different button color on one specific step.
Any class-based styling works: Tailwind, CSS modules, plain global classes, CSS-in-JS that emits classes. The SDK appends your class to the element's built-in classes and your CSS engine handles specificity.
Structural classNames
Top-level classNames styles the modal chrome — the dialog surface, the overlay, the close and back buttons.
<CancelFlow
classNames={{
modal: 'max-w-lg shadow-2xl',
overlay: 'bg-black/60 backdrop-blur-sm',
closeButton: 'top-4 right-4',
backButton: 'text-gray-400 hover:text-gray-600',
}}
steps={steps}
handleCancel={handleCancel}
/>| Key | Element |
|---|---|
modal | The dialog surface. |
overlay | The dimmed backdrop behind the modal. |
closeButton | The X in the corner. |
backButton | The back arrow shown on non-first steps. |
Per-step classNames
Per-step classNames live on the step config rather than at the top level. Each step type has its own className shape:
{
type: 'survey',
classNames: {
root: 'space-y-3',
title: 'text-3xl font-semibold',
reasonList: 'grid grid-cols-2 gap-2',
reasonButton: 'border-gray-200 hover:border-gray-300',
continueButton: 'bg-purple-600 hover:bg-purple-700',
},
reasons: [/* ... */],
}The full shapes:
interface SurveyClassNames {
root?: string
title?: string
description?: string
reasonList?: string
reasonButton?: string
reasonButtonSelected?: string
reasonLabel?: string
followupInput?: string
continueButton?: string
}
interface OfferClassNames {
root?: string
title?: string
description?: string
card?: string
headline?: string
body?: string
acceptButton?: string
declineButton?: string
pauseSlider?: string // pause offer only — applied to the months chip row
}
interface FeedbackClassNames {
root?: string
title?: string
description?: string
textarea?: string
characterCount?: string
submitButton?: string
}
interface ConfirmClassNames {
root?: string
title?: string
description?: string
lossList?: string
lossLabel?: string
lossItem?: string
lossBullet?: string
confirmButton?: string
goBackButton?: string
periodEndNotice?: string
}
interface SuccessClassNames {
root?: string
icon?: string
title?: string
description?: string
closeButton?: string
}OfferClassNames is shared across every offer type. pauseSlider applies only on pause offers (it targets the months chip row); the rest apply on every offer type. To restyle the plan picker, discount card, or trial-extension badge beyond what card / acceptButton reach, override the per-offer-type component — see Replacing components.
How overrides merge
The SDK emits its own class names on every element (.ck-reason-button, .ck-feedback-field, etc., with modifier suffixes like --selected or --focused). Your class is appended:
classNames={{ reasonButton: 'border-purple-300' }}
// Renders as: class="ck-reason-button border-purple-300"Specificity follows normal CSS rules. Tailwind utilities are usually authored later in the cascade, so they win automatically. With CSS modules or plain CSS, your class and the SDK's .ck-* class sit at the same specificity — you may need !important or a more specific selector to override.
Patterns
Wider modal with a tighter shadow:
classNames={{
modal: 'max-w-md rounded-2xl shadow-[0_24px_60px_rgba(0,0,0,0.18)]',
}}Two-column reason grid:
steps={[{
type: 'survey',
classNames: { reasonList: 'grid grid-cols-2 gap-2' },
reasons: [/* ... */],
}]}Brand-colored continue button on one step:
steps={[{
type: 'survey',
classNames: { continueButton: 'bg-emerald-600 hover:bg-emerald-700 text-white' },
reasons: [/* ... */],
}]}For a brand color that applies across every step, set colorPrimary in appearance.variables instead — see Theming.
When classNames isn't enough
Reach for component overrides when you need to:
- Restructure the markup — rendering reasons as cards with images, for example.
- Add elements the SDK doesn't emit — a quote alongside the discount offer, an avatar next to each reason.
- Replace an entire step's UI while keeping the state machine.
classNames don't require maintaining a React component as the SDK evolves, but they can only style what the SDK already renders. Component overrides give you total control at the cost of keeping the component in sync.
Next steps
- Replacing components — swap a sub-component when CSS isn't enough.
- Theming — color scheme and design tokens.