04 — Customization · Custom CSS
Custom CSS, scoped per field.
Every field's Style tab has a Custom CSS textarea. Whatever you paste is scoped to that one field at runtime, so you can target individual inputs without leaking styles into the rest of the form.
How scoping works
When you write a rule against input, FormPing rewrites it at runtime to
apply only to this field's input. You don't need to write the scope yourself —
just write CSS as if the field were the whole world.
/* What you write */
input {
border: 2px solid hotpink;
}
label {
text-transform: uppercase;
letter-spacing: 0.1em;
}
What's allowed
- Gradients —
linear-gradient,radial-gradient,conic-gradient - Animations —
@keyframes,animation,transition - Transforms —
transform,scale,rotate,translate - Modern color —
color-mix(),oklch(),color() - Variables & math —
var(),calc(),min(),max(),clamp() - Pseudo-classes —
:hover,:focus,:active,:disabled,:placeholder-shown - Pseudo-elements —
::before,::after,::placeholder - Filters & effects —
filter,backdrop-filter,box-shadow,text-shadow
What's blocked
For your visitors' privacy and to prevent abuse of the platform, the server sanitizes Custom CSS before it reaches the browser. The following are stripped:
- All
url(...)— no external images, no background images, no cursors. This blocks tracking pixels and unauthorized asset loading. @font-face— no custom fonts. Use the form-wide--fp-fonttheme variable instead.image-set()— same reason asurl().- Anything that looks like JavaScript —
javascript:,expression(), etc.
Custom CSS has a max size of 10 KB per field. That's enough for serious effects but stops anyone from pasting an entire framework into a single input.
Examples
Glow on focus
input {
border: 1px solid #e3e3e8;
transition: box-shadow 0.25s ease, border-color 0.25s ease;
}
input:focus {
border-color: #7c5cff;
box-shadow: 0 0 0 4px color-mix(in oklab, #7c5cff 25%, transparent);
outline: none;
}
Animated gradient submit button
/* paste this on the submit button field */
button {
background: linear-gradient(120deg, #7c5cff, #c8ff3e, #7c5cff);
background-size: 200% 200%;
animation: shift 4s ease infinite;
color: #0b0d10;
font-weight: 600;
}
@keyframes shift {
0%, 100% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
}
Floating label
label {
position: absolute;
top: 50%;
left: 14px;
transform: translateY(-50%);
pointer-events: none;
color: #999;
transition: all 0.18s ease;
background: white;
padding: 0 6px;
}
input:focus + label,
input:not(:placeholder-shown) + label {
top: 0;
font-size: 0.75rem;
color: #7c5cff;
}
Validation shake
input:invalid:not(:focus):not(:placeholder-shown) {
border-color: #d63b3b;
animation: shake 0.4s ease;
}
@keyframes shake {
0%, 100% { transform: translateX(0); }
25% { transform: translateX(-4px); }
75% { transform: translateX(4px); }
}
Custom CSS is sanitized server-side. If you paste something that includes a blocked construct (like url()), it will be stripped silently — your other rules still apply, but the offending property won't reach the browser.