Skip to content

Styling and theming

OctaForms ships a deliberately neutral stylesheet so a form looks tidy the moment you add it. This page shows how to make forms and the callback widget match your theme, from a one-line colour change to a full custom look.

There are two ways to style, and you will usually mix them:

  1. Set a few CSS variables. The fastest path. Change colours, borders, radius and spacing without writing a single override rule.
  2. Write your own CSS rules. For layout or anything the variables do not cover. The plugin is built to make this easy and hard to break, as long as you follow two small rules below.

Every default rule is wrapped in :where(), which means it carries zero specificity. The styles still apply, but any selector you write beats them. A plain class is enough:

.my-form-input { border: 2px solid #2563eb; }

No need to repeat .octa-forms__field input or stack extra classes to win. There is one deliberate exception: the submit button keeps real specificity so a bare button {} reset in your theme cannot wash it out to a blank control. More on that below.

OctaForms renders the same markup everywhere (the shortcode, the helper, and the widget popup), so one set of styles covers all of them.

<form class="octa-forms" data-octa-forms="{slug}">
<div class="octa-forms__field octa-forms__field--text">
<label for="">Name</label>
<input type="text" >
</div>
<div class="octa-forms__field octa-forms__field--checkbox">
<label>
<input type="checkbox" value="on" >
<span class="octa-forms__consent">I agree to the privacy policy</span>
</label>
</div>
<div class="octa-forms__actions">
<button type="submit" class="octa-forms__submit">Send</button>
</div>
</form>

Each field is a .octa-forms__field wrapper with a type modifier: --text, --email, --tel, --date, --select, --textarea, --file, --checkbox.

Two layouts matter when you write CSS:

  • Regular fields (text, email, tel, date, select, textarea, file) put the <label> above the control. The wrapper is a vertical flex column.
  • The checkbox is different. Its <label> wraps the box and the consent text side by side. The <input type="checkbox"> is a small native box, not a full-width control. This distinction is the single most common source of styling bugs. See Do not style bare input.

For the most common changes you do not need an override rule. Set a few values on .octa-forms:

.octa-forms {
--octa-forms-submit-bg: #2563eb;
--octa-forms-submit-bg-hover: #1d4ed8;
--octa-forms-control-radius: 12px;
--octa-forms-control-border: 1px solid #cbd5e1;
--octa-forms-focus-color: #2563eb;
}

Because you set them on the container, you can scope different looks to different places:

.site-footer .octa-forms { --octa-forms-submit-bg: #fff; --octa-forms-submit-color: #111; }
Variable Controls Default
--octa-forms-gap Space between fields 1rem
--octa-forms-max-width Max width of the form 640px
--octa-forms-label-size Label font size 0.9375rem
--octa-forms-label-weight Label font weight 600
--octa-forms-control-bg Input / select / textarea background #fff
--octa-forms-control-color Control text colour inherit
--octa-forms-placeholder-color Placeholder text colour #b3b3bb
--octa-forms-control-padding Control padding 0.55rem 0.7rem
--octa-forms-control-border Control border 1px solid #c7c7cf
--octa-forms-control-radius Control corner radius 6px
--octa-forms-focus-color Focus border and outline #111
--octa-forms-submit-bg Submit button background #111
--octa-forms-submit-bg-hover Submit button hover background #000
--octa-forms-submit-color Submit button text colour #fff
--octa-forms-submit-padding Submit button padding 0.6rem 1.4rem
--octa-forms-submit-radius Submit button corner radius 6px
--octa-forms-error-color Validation error colour #b91c1c
--octa-forms-thank-you-bg Thank-you panel background transparent
--octa-forms-thank-you-border Thank-you panel border transparent

When the variables are not enough, write normal CSS. Two rules keep you out of trouble.

A checkbox is an <input> too. If you style every input in a field, you also blow up the checkbox into a full-width, padded, bordered box. It then looks oversized or centred and pushes the layout around. This is the most common styling bug.

/* Wrong — this also hits the checkbox and radio */
.octa-forms__field input { width: 100%; padding: 12px; border: 1px solid #ccc; }

Always exclude checkbox and radio from generic input styling:

/* Right */
.octa-forms__field input:not([type="checkbox"]):not([type="radio"]),
.octa-forms__field select,
.octa-forms__field textarea {
width: 100%;
padding: 12px;
border: 1px solid #ccc;
border-radius: 8px;
}

Apply the same :not(...) to any :focus, background or border rule that targets input. Style the checkbox only through its own selectors:

.octa-forms__field--checkbox input[type="checkbox"] { width: 1.1em; height: 1.1em; accent-color: #2563eb; }
.octa-forms__field--checkbox label { gap: 0.5rem; align-items: flex-start; }
.octa-forms__consent { font-size: 0.9rem; line-height: 1.45; }
.octa-forms__consent a { text-decoration: underline; }

The submit button needs a class, not bare button

Section titled “The submit button needs a class, not bare button”

.octa-forms__submit keeps real specificity on purpose, so a theme reset like button { background: none } cannot strip it. To restyle the button with your own rule, use a selector that includes the class, or set the --octa-forms-submit-* variables:

.octa-forms__submit { border-radius: 999px; }
Class What it is
.octa-forms The <form> element. Set your variables here.
.octa-forms__field A single field wrapper (vertical flex column).
.octa-forms__field--{type} Type modifier: text, email, tel, date, select, textarea, file, checkbox.
.octa-forms__field label A field label.
.octa-forms__label--sr A label hidden visually but kept for screen readers (placeholder-labels mode). Leave it hidden.
.octa-forms__field--checkbox label The checkbox row (box plus consent text).
.octa-forms__consent The consent text next to a checkbox.
.octa-forms__consent a A link inside consent text.
.octa-forms__actions The submit button wrapper.
.octa-forms__submit The submit button (keeps real specificity).
.octa-forms-error / .octa-forms-error--form A field error / a form-level error (added by the helper).
.octa-forms__thank-you / -title / -text The thank-you screen that replaces the form after a successful submit.
.octa-forms__noscript The message shown when JavaScript is off.

The focus ring and the invalid-field and error colours keep their normal weight on purpose, so a light theme override does not accidentally remove those accessibility signals.

The floating handset button and its popup are neutral by default (a black button and handset). They read their colours, radius and spacing from --cb-* variables scoped to .octa-forms-callback. Set them in your theme to retint the whole widget.

--cb-primary is the widget’s brand colour. Setting it alone retints, in one line:

  • the floating button and its pulsing rings,
  • the button and tab focus outlines,
  • the active tab colour and its underline,
  • the input focus ring inside the popup,
  • the popup’s submit button.
.octa-forms-callback {
--cb-primary: #e11d2a; /* your brand colour */
}

That is the important one to know: the popup’s send button takes its colour from --cb-primary, not from --octa-forms-submit-bg. Inside the popup the widget’s own styles win. To change the popup button, set --cb-primary (or override .octa-forms-callback__popup .octa-forms__submit).

Variable Controls Default
--cb-primary Brand colour: button, rings, focus, active tab, popup focus and submit #111
--cb-white Button icon, popup surfaces var(--color-white, #fff)
--cb-black Popup text var(--color-black, #444)
--cb-gray-dark Muted text and placeholders var(--color-gray-dark, #777)
--cb-gray-medium Borders and tab separators var(--color-gray-medium, #d9dee6)
--cb-gray-light Light fills var(--color-gray-light, #f7f9fc)
--cb-radius Corner radius across the widget var(--radius, 10px)
--cb-space-* Spacing scale (xsxxl) Falls back to --spacing-* theme tokens
--cb-fs-* Font-size scale (smallhuge) Falls back to --font-size-* theme tokens

Because spacing and type fall back to your theme tokens (--spacing-*, --font-size-*), the widget often adopts your theme’s rhythm with no extra work. Override the --cb-* values only where you want to differ.

A worked example, retinting to a brand and rounding the corners:

.octa-forms-callback {
--cb-primary: #e11d2a;
--cb-radius: 16px;
--cb-gray-medium: #dfe3ea;
}

If you need finer control than the variables give, these are the pieces you will style most often.

Class What it is
.octa-forms-callback The widget host (fixed position). Set --cb-* here.
.octa-forms-callback--left / --right Which side the button sits on.
.octa-forms-callback__toggle The round floating button.
.octa-forms-callback__icon The handset icon (a CSS mask, coloured with currentColor).
.octa-forms-callback__bubble The small teaser bubble by the button.
.octa-forms-callback__popup The open popup wrapper.
.octa-forms-callback__dialog The popup panel.
.octa-forms-callback__tabs / __tab The contact-method tabs (phone, callback, message).
.octa-forms-callback__tab[aria-selected="true"] The active tab.
.octa-forms-callback__phone / __tel The phone number shown in phone mode.

The form inside the popup is the same .octa-forms markup described above, so everything in the sections before this one applies there too. Its layout rules are zero specificity, so your theme still wins.

If you would rather style everything yourself from scratch, turn the form stylesheet off with the disable_styles setting or the octa_forms_styles_enabled filter. When it is off the --octa-forms-* variables and the base layout go away too, so your theme has to supply the full layout, including the checkbox row. See Frontend assets.

  • No rule targets .octa-forms__field input without :not([type="checkbox"]):not([type="radio"]).
  • The checkbox renders as a small native box on the left, with the consent text wrapping beside it and no gap pushing the button around.
  • The submit button is styled through .octa-forms__submit or the --octa-forms-submit-* variables, not bare button.
  • The widget is retinted with --cb-primary (remember the popup send button follows it, not --octa-forms-submit-bg).
  • Focus, error and thank-you states still stand out against your theme.
  • .octa-forms__label--sr stays visually hidden.
  • Checked in every place a form appears (page sections, the widget popup), since different contexts can carry different theme styles.