Clarflow CSS Classes Reference
Target and style every part of your funnel with custom CSS. All classes follow the cf- prefix convention and are organized in three tiers: global, step-level, and instance-level.
Layout & DOM Structure
The funnel renders as a 3-child flex column that fills the viewport:
[data-clarflow-root] <- flex-col, 100dvh, overflow:hidden (also .cf-root)
|- [data-clarflow-header] <- flex-shrink:0 (logo, back, progress)
|- [data-clarflow-content] <- flex:1, overflow-y:auto (ONLY scrollable area) (also .cf-content)
| └─ .cf-step <- step container
| └─ .cf-step-content <- padded inner box (default content padding)
└─ [data-clarflow-button-portal] <- flex-shrink:0 (continue button) (also .cf-button-portal)
Protected properties (cannot be overridden by custom CSS):
[data-clarflow-root]: display, flex-direction, height, overflow[data-clarflow-content]: flex, min-height, overflow-y[data-clarflow-button-portal]: flex-shrink
Always use
!importantwhen overriding inline styles. CSS is auto-scoped inside[data-clarflow-root].
Step Classes
| Class | Description |
|---|---|
.cf-step | Every step container |
.cf-step-content | Padded inner box inside each step (carries the default content padding) |
.cf-step-{N} | Specific step by position (1-based) |
.cf-step-first | First step in the funnel |
.cf-step-last | Last step in the funnel |
.cf-step-odd | Steps in odd positions (1, 3, 5…) |
.cf-step-even | Steps in even positions (2, 4, 6…) |
.cf-step-content is the child of .cf-step that holds the step's elements with the default
padding. Zero its padding to go full-bleed / edge-to-edge (covers, hero images, custom HTML).
Examples:
/* Style only the first step */
.cf-step-first {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
}
/* Add extra padding to the last step */
.cf-step-last {
padding-bottom: 60px !important;
}
/* Full-bleed step: kill the inner padding so a cover/hero hits the edges */
.cf-step-3 .cf-step-content {
padding: 0 !important;
}
Content padding variables
.cf-step-content's padding is driven by two CSS variables (so you can adjust it without a
structural selector). Set them on a step (or globally) and they cascade into the inner box:
| Variable | Default | Controls |
|---|---|---|
--cf-content-padding-x | 24px | Left/right padding of .cf-step-content |
--cf-content-padding-y | 32px | Top/bottom padding of .cf-step-content |
/* Full-bleed cover on step 1 — zero the vertical padding via the variable */
.cf-step-1 { --cf-content-padding-y: 0; }
/* Tighter horizontal gutters across the whole funnel */
.cf-step { --cf-content-padding-x: 12px; }
Step Transition Animations
Add an animation when the funnel moves between steps. There's one catch: the renderer reuses the same .cf-step DOM node and only swaps the step class, so an animation keyed on .cf-step alone fires once on load and never re-fires. The standard fix is to key the animation off the parity classes .cf-step-odd / .cf-step-even — they flip on every navigation, which restarts the animation each step.
Define two identical but differently named keyframes (one per parity) and point each parity class at one:
@keyframes cf-slide-a {
from { opacity: 0; transform: translateX(24px); }
to { opacity: 1; transform: translateX(0); }
}
@keyframes cf-slide-b {
from { opacity: 0; transform: translateX(24px); }
to { opacity: 1; transform: translateX(0); }
}
.cf-step {
animation-duration: 0.3s !important;
animation-timing-function: cubic-bezier(0.22, 0.61, 0.36, 1) !important;
animation-fill-mode: both !important;
}
.cf-step-odd { animation-name: cf-slide-a !important; }
.cf-step-even { animation-name: cf-slide-b !important; }
Why two keyframes? A CSS animation only restarts when its
animation-nameactually changes.cf-slide-aandcf-slide-bare identical but differently named, so alternating them per parity forces the browser to re-run the animation on every step.
Swap the transform for any effect: slide up (translateY(24px)), pop (scale(0.96)), or a pure fade (drop the transform and animate opacity only).
Element Type Classes
Every sub-element gets a global class based on its type:
| Class | Element |
|---|---|
.cf-title | Title elements |
.cf-text | Text blocks |
.cf-image | Image elements |
.cf-question | Question elements |
.cf-input | Input fields |
.cf-dropdown | Dropdown selects |
.cf-loading | Loading elements |
.cf-custom-html | Custom HTML blocks |
Step-scoped: .cf-step-{N}-{type} (e.g., .cf-step-2-question)
Instance-scoped: .cf-step-{N}-el-{E} (e.g., .cf-step-2-el-1 for the first element in step 2)
Inner element hooks — target the rendered content directly (no Tailwind/structural selectors needed):
| Class | Element |
|---|---|
.cf-title-text | The title's text element (h1 / rich-text body) |
.cf-text-body | The text block's paragraph / rich-text body |
.cf-input-field | The <input> element itself |
.cf-dropdown-select | The <select> element itself |
.cf-custom-html-frame | The custom-HTML <iframe> |
Question Type & Layout Classes
| Class | Description |
|---|---|
.cf-question-single | Single-select question |
.cf-question-multi | Multi-select question |
.cf-question-layout-list | List layout |
.cf-question-layout-grid | Grid layout (2 columns) |
.cf-options | The options container (wraps all option buttons) |
.cf-options-list | Options container in list layout |
.cf-options-grid | Options container in grid layout |
Examples:
/* Make single-select options larger */
.cf-question-single .cf-option {
padding: 16px 20px !important;
font-size: 18px !important;
}
/* Add a border to grid layout questions */
.cf-question-layout-grid {
border: 2px dashed #e5e7eb !important;
border-radius: 12px !important;
padding: 16px !important;
}
Input Type Classes
| Class | Input Type |
|---|---|
.cf-input-text | Text input |
.cf-input-email | Email input |
.cf-input-number | Number input |
.cf-input-tel | Phone input |
.cf-input-url | URL input |
.cf-input-password | Password input |
Examples:
/* Style email inputs differently */
.cf-input-email .cf-input-field {
border-color: #3b82f6 !important;
}
/* Add phone icon styling */
.cf-input-tel .cf-input-field {
padding-left: 40px !important;
}
Loading Style Classes
Every loader is wrapped in .cf-loading plus a style variant. Each style exposes hooks for its inner parts.
| Class | Style variant |
|---|---|
.cf-loading-bar | Bar-style progress loader |
.cf-loading-circle | Circle/spinner loader |
.cf-loading-steps | Multi-step checklist loader |
Shared (bar + circle):
| Class | Element |
|---|---|
.cf-loading-text | Loading label / status text |
.cf-loading-percent | The percentage readout |
Bar loader:
| Class | Element |
|---|---|
.cf-loading-bar-wrap | The bar's container |
.cf-loading-bar-track | The track (background) |
.cf-loading-bar-fill | The animated fill |
Circle loader:
| Class | Element |
|---|---|
.cf-loading-circle-graphic | The circle container |
.cf-loading-circle-svg | The SVG element |
.cf-loading-circle-track | The background ring |
.cf-loading-circle-fill | The animated progress ring |
Steps loader — a checklist of rows, each moving pending → loading → completed:
| Class | Element |
|---|---|
.cf-loading-steps-wrap | The steps loader container |
.cf-loading-steps-list | The list of step rows |
.cf-loading-step | A single step row |
.cf-loading-step-pending | Step row in the pending state |
.cf-loading-step-loading | Step row in the loading state |
.cf-loading-step-completed | Step row in the completed state |
.cf-loading-step-label | The step's text label |
.cf-loading-step-percent | The step's percentage (loading state) |
.cf-loading-step-track | The step's bar track (loading state) |
.cf-loading-step-fill | The step's bar fill (loading state) |
.cf-loading-step-dot | The bullet dot (pending state) |
.cf-loading-step-check | The check badge (completed state) |
.cf-loading-step-divider | The divider line (completed state) |
Steps loader modal — an optional prompt shown during a step:
| Class | Element |
|---|---|
.cf-loading-modal-overlay | The dimmed backdrop |
.cf-loading-modal | The modal card |
.cf-loading-modal-warning | The warning line |
.cf-loading-modal-question | The question text |
.cf-loading-modal-actions | The button row |
.cf-loading-modal-confirm | The confirm (yes) button |
.cf-loading-modal-dismiss | The dismiss (no) button |
Option Classes
| Class | Description |
|---|---|
.cf-option | Every option button |
.cf-option-selected | Currently selected option |
.cf-option-has-emoji | Option that contains an emoji |
.cf-option-has-image | Option that contains an image |
.cf-option-has-subtext | Option that contains subtext |
.cf-option-content | The option's content row. In grid layout this is the footer band below the image — colour/pad it to style the label band |
.cf-option-label | The option's main label text. If the label was formatted in the editor it contains inline elements (strong, em, span…) whose inline styles beat rules set on this class — target .cf-option-label strong etc., or use !important, to override them |
.cf-option-subtext | The option's subtext line |
.cf-option-emoji | The option's emoji |
.cf-option-media | The image wrapper in grid layout (size / aspect-ratio / crop the image here) |
.cf-option-image | The <img> element itself (in grid layout it sits inside .cf-option-media) |
.cf-option-indicator | The radio/checkbox indicator |
.cf-option-indicator-radio | Single-select (radio) indicator — the outer circle |
.cf-option-indicator-checkbox | Multi-select (checkbox) indicator |
.cf-option-indicator-dot | The small inner dot of a selected radio |
.cf-option-indicator-check | Checkmark inside a selected checkbox |
Recolouring a selected radio: when a radio is selected, the outer circle (
.cf-option-indicator-radio) is filled with--cf-primaryand the inner dot (.cf-option-indicator-dot) is filled with--cf-background(so the dot shows as a hole). Settingbackgroundon.cf-option-indicator-dotalone makes the dot the same colour as the already-filled circle, so the whole control reads as a solid disc. To change the colours, style the circle and the dot separately — e.g..cf-option-indicator-radio { background: #111 !important }and.cf-option-indicator-dot { background: #fff !important }.
Step-scoped: .cf-step-{N}-option
Instance-scoped: .cf-step-{N}-el-{E}-option-{O} (e.g., .cf-step-1-el-1-option-3)
Examples:
/* Highlight options with images */
.cf-option-has-image {
border: 2px solid #10b981 !important;
}
/* Style selected state */
.cf-option-selected {
transform: scale(1.02) !important;
box-shadow: 0 4px 12px rgba(59, 130, 246, 0.3) !important;
}
/* Grid cards: square the image and colour the footer label band */
.cf-question-layout-grid .cf-option-media {
width: 100% !important;
aspect-ratio: 1 / 1 !important;
overflow: hidden !important;
}
.cf-question-layout-grid .cf-option-content {
background: var(--cf-option-bg) !important;
padding: 12px !important;
}
.cf-question-layout-grid .cf-option-selected .cf-option-content {
background: var(--cf-primary) !important;
}
Image Classes
| Class | Description |
|---|---|
.cf-image-single | Single image display |
.cf-image-carousel | Image carousel (2+ images) |
Field State Classes
| Class | Element | Description |
|---|---|---|
.cf-required | Input/Dropdown wrapper | Field is required |
.cf-label | Label element | Input or dropdown label |
.cf-input-error | Error paragraph | Input validation error message |
.cf-dropdown-error | Error paragraph | Dropdown validation error message |
Examples:
/* Style required field labels */
.cf-required .cf-label {
font-weight: 700 !important;
}
/* Custom error message styling */
.cf-input-error {
color: #dc2626 !important;
font-style: italic !important;
}
Dropdown Classes
| Class | Description |
|---|---|
.cf-dropdown | Dropdown wrapper |
.cf-dropdown-select | The <select> element itself |
.cf-dropdown-option | Every dropdown option |
.cf-dropdown-error | Dropdown validation error |
Step-scoped: .cf-step-{N}-dropdown-option
Instance-scoped: .cf-step-{N}-el-{E}-dropdown-option-{O}
Header & Button Classes
| Class | Element | Description |
|---|---|---|
.cf-root | Root container | Funnel root (class alias of [data-clarflow-root]) |
.cf-content | Content area | Scrollable content (class alias of [data-clarflow-content]) |
.cf-header | Header container | The top header bar |
.cf-header-row | Header inner row | The flex row holding back + logo + step counter (adjust its padding/alignment) |
.cf-header-back | Back button wrapper | Back navigation area |
.cf-header-logo | Logo wrapper | Brand logo area |
.cf-header-step | Step counter wrapper | The "X of Y" counter area |
.cf-header-step-count | Step counter text | The "X of Y" text element |
.cf-header-progress | Progress wrapper | Progress bar area |
.cf-header-progress-track | Progress track | The progress bar background |
.cf-header-progress-fill | Progress fill | The progress bar filled portion |
.cf-header-divider | Header divider | Border line below the header / progress bar |
.cf-button | Button container | Continue button wrapper (includes padding/shadow) |
.cf-button-text | Button element | The actual continue button |
.cf-button-portal | Portal div | Button portal target at bottom of viewport |
Examples:
/* Custom header background */
.cf-header {
background: #1a1a2e !important;
border-bottom: 2px solid #16213e !important;
}
/* Round the continue button */
.cf-button-text {
border-radius: 50px !important;
text-transform: uppercase !important;
letter-spacing: 1px !important;
}
/* Hide the progress bar */
.cf-header-progress {
display: none !important;
}
Instance Targeting
For precise control, combine step number with element index:
| Pattern | Example | Targets |
|---|---|---|
.cf-step-{N}-el-{E} | .cf-step-2-el-1 | First element in step 2 |
.cf-step-{N}-el-{E}-option-{O} | .cf-step-1-el-1-option-3 | Third option of first element in step 1 |
.cf-step-{N}-el-{E}-dropdown-option-{O} | .cf-step-3-el-2-dropdown-option-1 | First dropdown option of second element in step 3 |
All indices are 1-based (start from 1, not 0).
Real-World Examples
Dark theme override
.cf-step {
background: #0f172a !important;
color: #e2e8f0 !important;
}
.cf-option {
background: #1e293b !important;
border-color: #334155 !important;
color: #e2e8f0 !important;
}
.cf-option-selected {
border-color: #3b82f6 !important;
background: #1e3a5f !important;
}
.cf-button-text {
background: #3b82f6 !important;
color: white !important;
}
Style only email inputs on step 3
.cf-step-3 .cf-input-email .cf-input-field {
border: 2px solid #10b981 !important;
border-radius: 8px !important;
padding: 12px 16px !important;
}
.cf-step-3 .cf-input-email .cf-label {
color: #10b981 !important;
font-size: 14px !important;
}
Highlight multi-select questions
.cf-question-multi {
background: #fefce8 !important;
border: 1px solid #fbbf24 !important;
border-radius: 12px !important;
padding: 16px !important;
}
.cf-question-multi .cf-option {
border-color: #f59e0b !important;
}
Custom progress bar
.cf-header-progress-track {
height: 6px !important;
border-radius: 3px !important;
}
.cf-header-progress-fill {
background: linear-gradient(90deg, #3b82f6, #8b5cf6) !important;
}