Custom CSS
Custom CSS lets you style a form with your own CSS, on top of everything the Design panel does. It is included in the Pro and Enterprise plans, and everyone who edits forms in a Pro or Enterprise workspace can use it.
Add CSS to a form
- Open the form and click Design, then Customize.
- Scroll to Custom CSS at the end and click Add CSS.
- Write your CSS. The editing canvas next to the editor shows it as you type: select any question to see it there, or use the phone button in the toolbar to see the phone layout. Any problems are listed under the editor with their line numbers.
- Click Apply. Visitors get the new look the next time they open the form.
To style one question, select it, switch the Design panel to This field, and use Style this question. It opens the editor with a rule for that question already written. The Insert list in the editor has every class on this page and every question in the form.
Where it shows
- Your form link, your custom domains and every embed.
- Every screen: the password screen, each question, and the thank-you screen.
- The editing canvas, while you build. It shows one question at a time, so check the form title, progress bar, error messages and password screen with the Preview button, which shows your CSS too.
- Rules inside
@mediafollow the browser window, not the canvas's phone frame, so check phone-only rules on a phone or in a narrow window. - Not in emails, PDFs, payment and CAPTCHA boxes, pop-up notices, or quizzes.
Example
/* Rounded, roomy questions */
.wf-question {
padding: 24px;
border-radius: 16px;
background: #ffffff;
}
/* Pill-shaped buttons, a stronger submit */
.wf-button { border-radius: 999px; }
.wf-button[data-wf-action="submit"] { background: #0a7f5a; color: #fff; }
/* The chosen answer stands out */
.wf-option[data-wf-selected] { border-color: #0a7f5a; font-weight: 600; }
/* One question, by its id (copy it from the Design panel's This field) */
.wf-question[data-wf-field-id="email"] .wf-label { font-size: 1.25rem; }
/* Dark theme only */
.wf-form[data-wf-theme="dark"] .wf-input { background: #1c1917; }
/* Phones */
@media (width < 640px) {
.wf-question { padding: 16px; }
}Selectors
These class names are supported. We won't rename or remove them without notice, so CSS written against them keeps working when we update WittyForm.
| Selector | What it is | Example |
|---|---|---|
.wf-form | The whole form. Every other hook is inside it. | .wf-form { background: #fdf6ec; } |
.wf-logo | Your logo. | .wf-logo { border-radius: 50%; } |
.wf-title | The form title (single-page forms). | .wf-title { letter-spacing: -0.02em; } |
.wf-progress | The progress indicator. | .wf-progress { opacity: 0.8; } |
.wf-progress-bar | The filled part of the progress bar. | .wf-progress-bar { background: #0a7f5a; } |
.wf-question | One question. Use data-wf-type or data-wf-field-id to pick specific ones. | .wf-question[data-wf-type="email"] { max-width: 480px; } |
.wf-label | A question title. | .wf-label { font-weight: 700; } |
.wf-description | The help text under a question title. | .wf-description { font-style: italic; } |
.wf-input | A text box, text area, dropdown, or date and country picker. | .wf-input { border-radius: 999px; } |
.wf-option | A choice (multiple choice, picture choice, yes/no, rating). | .wf-option[data-wf-selected] { background: #0a7f5a; color: #fff; } |
.wf-error | A validation message. | .wf-error { font-weight: 600; } |
.wf-button | A button. Use data-wf-action to pick next, back, submit or resume. The password and thank-you screen buttons have no action; reach them with .wf-password .wf-button or .wf-thank-you .wf-button. | .wf-button[data-wf-action="submit"] { border-radius: 999px; } |
.wf-thank-you | The thank-you screen. | .wf-thank-you { text-align: center; } |
.wf-password | The password screen. | .wf-password { max-width: 420px; } |
Attributes for state and type
Combine these with the selectors above, for example .wf-question[data-wf-invalid] for a question that is showing an error.
| Attribute | On | Values |
|---|---|---|
data-wf-layout | .wf-form | conversational | linear |
data-wf-shell | .wf-form | default | editorial |
data-wf-theme | .wf-form | light | dark |
data-wf-screen | .wf-form | loading | password | question | thank-you |
data-wf-page | .wf-form | current step number (one-question-at-a-time forms) |
data-wf-mode | .wf-form | live | preview |
data-wf-locale | .wf-form | form language, e.g. en, fr |
data-wf-markup | .wf-form | hook contract version, currently 1 |
data-wf-type | .wf-question | question type, e.g. email, rating |
data-wf-field-id | .wf-question | the question id |
data-wf-required | .wf-question | present when required |
data-wf-invalid | .wf-question | present when showing an error |
data-wf-answered | .wf-question | present once answered |
data-wf-child | .wf-question | present inside a question group |
data-wf-selected | .wf-option | present when chosen |
data-wf-action | .wf-button | next | back | submit | resume |
You can also use type, dir, lang, disabled, required and the aria-invalid, aria-checked, aria-selected, aria-expanded, aria-disabled and aria-required attributes.
How your CSS is applied
- It only reaches this form. Every rule is limited to the inside of the form.
html,bodyand:rootmean the form itself. - It wins without !important. Every declaration is made important for you, so it beats the Design panel and our defaults.
- Motion respects visitors. Animations and transitions are skipped for visitors whose device asks for reduced motion.
- Nesting and modern media queries work. Nested rules and range queries such as
@media (width >= 600px)are supported. - Animation names can't clash. Your
@keyframesare renamed for this form, and youranimationrules follow them.
Variables
Name your own variables with the --x- prefix. You can also set --wf-page-width and the button variables --wf-btn-radius, --wf-btn-h, --wf-btn-px, --wf-btn-font, --wf-btn-my and --wf-btn-justify on .wf-form. Every other --wf- name is reserved.
.wf-form {
--x-brand: #0a7f5a;
--wf-page-width: 880px;
--wf-btn-radius: 999px;
}
.wf-button { background: var(--x-brand); }Fonts
Fonts from the WittyForm font library load automatically when your CSS uses them: Inter, Roboto, Open Sans, Lato, Montserrat, Poppins, Playfair Display, Merriweather, Raleway, Nunito, Nunito Sans, EB Garamond, Barlow Semi Condensed. Generic families such as serif and system-ui work too. Other font names are allowed, but they only show for visitors who already have that font installed.
What isn't allowed
The editor explains each of these and won't apply CSS that uses them.
- Images and links:
url()andimage-set(). Gradients are fine. - At-rules other than
@mediaand@keyframes, including@import,@font-face,@supports,@layerand@container. position: fixed,isolation, and browser prefixes such as-webkit-.- On the whole form (
.wf-form,htmlorbody):position,z-index,contain, anddisplay: contents. These keep the form in its own layer, so it can't cover the page around it. Use them on parts inside, like.wf-question. - Selectors on what visitors type, such as
[value]or[placeholder], and attributes not listed above. - Reaching outside the form, for example with
~or+after.wf-form. :visited,:host,::partand::slotted. The supported pseudo-classes are :hover, :focus, :focus-visible, :focus-within, :active, :disabled, :enabled, :checked, :required, :optional, :invalid, :valid, :placeholder-shown, :empty, :first-child, :last-child, :only-child, :nth-child, :nth-last-child, :nth-of-type, :nth-last-of-type, :first-of-type, :last-of-type, :only-of-type, :not, :is, :where, :has, and the supported pseudo-elements are ::before, ::after, ::placeholder, ::selection, ::marker, ::first-letter, ::first-line.
Limits
- Up to 30 KB of CSS, 1,000 rules, 20 selectors per rule and 4 levels of nesting.
- At most 3
:has()per selector,blur()up to 40px, and 4 shadows per declaration, each blurred up to 100px with a spread up to 64px. - Outlines up to 16px wide, with an offset up to 32px.
- An animation that repeats forever must last at least 1 second. Set its duration and repeat count together in the
animationshorthand: on their own,animation-durationmust be at least 1 second andanimation-iteration-countcan't beinfinite.
The editor also warns, without blocking, when CSS removes focus outlines, hides a question, or makes text smaller than 12px.
Safe mode
If your CSS hides something you need, add ?wf_css=off to the end of the form link. The form opens without your CSS, so you can check it and fix it in the editor. The link to safe mode is under the Custom CSS status in the Design panel.
Good to know
- Your CSS is public. Browsers download it to show the form, including on password-protected forms, so keep private notes out of comments.
- Duplicating a form copies its CSS. Duplicating a question gives the copy a new id, so update any
data-wf-field-idselectors. - Themes, templates and brand profiles don't carry CSS.
- Changing plans: on the Free plan the CSS stops showing but stays saved. You can still turn it off or delete it, and it comes back when you upgrade.
- After an update: if a WittyForm update ever stops your saved CSS from working, the form shows without it and the Design panel says which line needs a fix.
- Other class names in our markup, such as layout utility classes, can change at any time. CSS aimed at them may stop working, and support can only help with the selectors on this page.