The form was still there. The labels read clearly: "Name", "Email", "Message". But the input fields had seemingly vanished. I clicked where an input should be, a text caret appeared, I typed something, and nothing showed up. This happened right after I flipped one section's background from dark to light on a client landing page that embeds a GoHighLevel (GHL) form. No console errors, no warnings, nothing red. Just inputs that had "disappeared".
The moment I opened DevTools and inspected a field, the picture was obvious:
/* computed style on the GHL input */
input {
color: rgb(255, 255, 255); /* white text */
background-color: transparent; /* over the now-white section */
border-color: transparent;
}White text on a white background. I typed a name, the characters really were in the DOM, the value was populated, but my eyes could not see them. When the theme direction was reversed (a section going from light to dark), the symptom shifted: the borders went transparent and the field melted into the dark background. Same pattern, same root.
Why this happens
The key to all of this is one fact that's easy to miss: this GHL form is DOM-injected, not rendered inside an iframe. I assumed at first it was an iframe, like most third-party embeds, so I wasn't worried. I was wrong. I inspected it, and the input, textarea, and select elements sat directly inside my page's DOM tree, not behind a frame boundary.
That difference is enormous. An iframe has its own document and host CSS does not reach inside it — which is exactly why iframe embeds are usually immune to the page's theme. But a DOM-injected embed has no such boundary. Every CSS rule on my page flows in and cascades onto the GHL form's fields, exactly like it does for any other element on the page.
This project's theme uses Tailwind, and that's where the trigger lived. Tailwind preflight and my color rules set text and background colors to follow each section's theme. When the section was dark, the default text was set to a light color so it would be legible. The moment I flipped that section to light, I only changed the section's background — but the text color being inherited into the GHL inputs stayed "light". The result: white text on a white background. The GHL form itself sets no explicit colors on its inputs, so it surrendered to whatever cascaded down from the host. And the host was the thing I'd just changed.
What makes this one sneaky is that it never shouts. No errors. Validation works, submit works, the data goes through. The fields are simply invisible. It's very easy for it to slip past review unless you happen to click in exactly the right box.
The fix
There are two paths, and I use both depending on who holds the keys.
The clean path — from the form owner's side (GHL Custom CSS). The most correct place to fix this is inside GHL itself. GHL has Custom CSS for a form, and there I set the input colors explicitly so the form carries its own colors wherever it gets embedded:
/* In GHL > the form's Custom CSS */
input,
textarea,
select {
color: #111;
background: #fff;
border: 1px solid #ccc;
}With the colors pinned at the form level, the form becomes resilient: dropped into a dark section or a light one, the inputs stay legible because they no longer hang their fate on the host's cascade.
The band-aid path — from the theme side. When I don't have access to the client's GHL account (which happens often), I patch it from the theme side. I wrap the embed in a wrapper, say .ghl-embed-wrap, then force contrasting input colors regardless of the section's theme:
.ghl-embed-wrap input,
.ghl-embed-wrap textarea,
.ghl-embed-wrap select {
color: #111;
background: #fff;
border: 1px solid #ccc;
}This works because a selector scoped to the wrapper beats the generic colors inherited from the section theme, and the fields go legible again no matter which way dark or light flips. I treat this as a band-aid: it lives in my repo, not in the form, so if the client embeds the same form elsewhere, the protection doesn't travel with it. But as a safe quick fix, it does the job.
One step I now always take first: confirm whether the embed is an iframe or DOM-injected. Open DevTools, inspect the field. If it lives inside an <iframe>, your cascade can't reach it and the problem is somewhere else. If the inputs sit directly in your DOM, you're dealing with the cascade — and you know exactly where to aim.
The takeaway
DOM-injected third-party embeds inherit your cascade; iframes don't. That single sentence explains this whole incident. The moment I flipped one section's theme, I accidentally changed the text color trickling into a form's inputs that I don't even render — and silently made them invisible. The lesson is simple but easy to forget: never let third-party form fields depend on inherited colors. Pin the input colors explicitly, ideally on the form owner's side, or at least through a rule scoped to its wrapper. And before guessing at anything, check the one small thing that decides everything: is it an iframe, or is it the DOM?
