Custom CSS

7 min read

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

  1. Open the form and click Design, then Customize.
  2. Scroll to Custom CSS at the end and click Add CSS.
  3. 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.
  4. 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 @media follow 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.

SelectorWhat it isExample
.wf-formThe whole form. Every other hook is inside it..wf-form { background: #fdf6ec; }
.wf-logoYour logo..wf-logo { border-radius: 50%; }
.wf-titleThe form title (single-page forms)..wf-title { letter-spacing: -0.02em; }
.wf-progressThe progress indicator..wf-progress { opacity: 0.8; }
.wf-progress-barThe filled part of the progress bar..wf-progress-bar { background: #0a7f5a; }
.wf-questionOne question. Use data-wf-type or data-wf-field-id to pick specific ones..wf-question[data-wf-type="email"] { max-width: 480px; }
.wf-labelA question title..wf-label { font-weight: 700; }
.wf-descriptionThe help text under a question title..wf-description { font-style: italic; }
.wf-inputA text box, text area, dropdown, or date and country picker..wf-input { border-radius: 999px; }
.wf-optionA choice (multiple choice, picture choice, yes/no, rating)..wf-option[data-wf-selected] { background: #0a7f5a; color: #fff; }
.wf-errorA validation message..wf-error { font-weight: 600; }
.wf-buttonA 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-youThe thank-you screen..wf-thank-you { text-align: center; }
.wf-passwordThe 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.

AttributeOnValues
data-wf-layout.wf-formconversational | linear
data-wf-shell.wf-formdefault | editorial
data-wf-theme.wf-formlight | dark
data-wf-screen.wf-formloading | password | question | thank-you
data-wf-page.wf-formcurrent step number (one-question-at-a-time forms)
data-wf-mode.wf-formlive | preview
data-wf-locale.wf-formform language, e.g. en, fr
data-wf-markup.wf-formhook contract version, currently 1
data-wf-type.wf-questionquestion type, e.g. email, rating
data-wf-field-id.wf-questionthe question id
data-wf-required.wf-questionpresent when required
data-wf-invalid.wf-questionpresent when showing an error
data-wf-answered.wf-questionpresent once answered
data-wf-child.wf-questionpresent inside a question group
data-wf-selected.wf-optionpresent when chosen
data-wf-action.wf-buttonnext | 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, body and :root mean 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 @keyframes are renamed for this form, and your animation rules 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() and image-set(). Gradients are fine.
  • At-rules other than @media and @keyframes, including @import, @font-face, @supports, @layer and @container.
  • position: fixed, isolation, and browser prefixes such as -webkit-.
  • On the whole form (.wf-form, html or body): position, z-index, contain, and display: 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, ::part and ::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 animation shorthand: on their own, animation-duration must be at least 1 second and animation-iteration-count can't be infinite.

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-id selectors.
  • 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.
$37 · paid once

Ready to Build Forms That Actually Convert?

Start free and keep the five forms for good, or pay once and unlock all of it — unlimited forms, ten team members, AI, CRM, white label and the API. No renewal, ever.

14-day money-backInstant accessNo subscription, ever
Custom CSS