You have a Google Form that works. Now you want it on your own site, ideally looking like the rest of your site rather than looking like Google.
The embed route is a two-minute job, and for some situations it’s the right call. But it has one hard limit that no amount of CSS gets around, and it’s better to know that before you spend an afternoon fighting it.
What the embed actually gives you
In Google Forms, Send → <> gives you an iframe:
<iframe
src="https://docs.google.com/forms/d/e/FORM_ID/viewform?embedded=true"
width="640"
height="800"
frameborder="0"
></iframe>
Drop that in your page and the form appears. It works, submissions go to your Sheet, and you’re done.
Here’s the part worth understanding: an iframe is a separate document. Your page’s CSS cannot reach inside it. Not with descendant selectors, not with !important, not by targeting the iframe element. The browser’s same-origin policy blocks it, and this is a security boundary, not a limitation someone forgot to remove.
So what you can change is what Google gives you in the Forms UI: a theme color, a header image, and one of a handful of fonts. What you cannot change is the layout, the input styling, the button design, the spacing, or the “Powered by Google” notice. If your site has a particular look, the form will not match it. It will look like a Google Form sitting inside your page, because that is exactly what it is.
Two smaller costs, both easy to miss:
- Page weight. The iframe pulls in Google’s own CSS and JavaScript, entirely separate from your site’s assets. On a fast static page this is often the single heaviest thing on it.
- Fixed height. You set
heightin pixels. Too small and the form scrolls inside its own box, which feels broken. Too large and you get dead whitespace. It cannot size itself to its content, and on mobile this is where it usually looks worst.
When embedding is genuinely the right answer
This is not a case where the embed is always wrong. It’s a good fit when:
- It’s internal. A team survey, an availability poll, an office lunch order. Nobody is judging your brand and the Sheet is exactly where you want the answers.
- It’s temporary. A one-off event signup you’ll delete in three weeks. Rebuilding it is wasted effort.
- You need a Sheet as the destination. If the responses feed a spreadsheet workflow, Google Forms gives you that with zero setup.
- You need Google’s question types. Linear scales, response validation, sections with branching logic. Rebuilding those in HTML is real work.
If you’re in one of those cases, embed it and move on. The rest of this post is for when you’re not.
When to rebuild it as HTML instead
Rebuild when the form is customer-facing and any of these matter:
- It has to match your design. This is the big one, and it’s the one the embed cannot solve at all.
- It’s on a page you care about converting. A contact or quote-request form that visibly belongs to a different company adds friction at the exact moment you don’t want it.
- You want replies in your inbox. Google Forms writes rows to a Sheet. Email alerts are opt-in and don’t summarize the response, so you click back into Forms to read what someone said.
- You’re getting spam. Google Forms has no built-in spam filter. Stopping bots means a third-party Workspace add-on.
There’s also a subtler one: the URL handoff. A shared Google Form lives on docs.google.com or forms.gle. A visitor reading your site who clicks through to a Google domain notices, and the good-faith reading is “this company uses Google Forms,” which is fine for an internal poll and less fine for a client intake form.
Mapping your fields to HTML
Rebuilding is mostly mechanical. Each Google Forms question type has a direct HTML equivalent:
| Google Forms | HTML |
|---|---|
| Short answer | <input type="text"> |
| Paragraph | <textarea> |
| Multiple choice | <input type="radio"> |
| Checkboxes | <input type="checkbox"> |
| Dropdown | <select> |
| Short answer, email validation | <input type="email"> |
| Date | <input type="date"> |
| File upload | <input type="file"> |
| Linear scale | <input type="range">, or radios for a discrete 1-5 |
A short-answer question with a “Required” toggle becomes:
<div>
<label for="name">Your name</label>
<input type="text" id="name" name="name" required />
</div>
Two things to carry over that are easy to lose in the rebuild:
Real <label> elements, properly associated. Google Forms handles this for you. In hand-written HTML you have to do it: every <label> needs a for matching the input’s id. Without it, screen readers announce an unlabeled field, and clicking the text doesn’t focus the input. Placeholder text is not a substitute for a label.
Your required fields. A required attribute gives you browser-native validation with no JavaScript.
Multiple choice needs one shared name across the group, which is the part people most often get wrong:
<fieldset>
<legend>How did you hear about us?</legend>
<input type="radio" id="src-search" name="source" value="search" />
<label for="src-search">Search engine</label>
<input type="radio" id="src-friend" name="source" value="friend" />
<label for="src-friend">A friend</label>
</fieldset>
Same name, different value and id. The <fieldset> and <legend> group them so assistive tech reads the question with the options.
Where the responses go
This is the real decision, and it’s worth being deliberate rather than defaulting.
Google Forms sends responses to a Sheet, with email as an afterthought. A form backend inverts that: the submission emails you, typically with reply-to set to the person who filled it in, so you answer from your own inbox and they get a reply from a human rather than a no-reply address.
If you genuinely want both, you can have both. Formpaste has a Google Sheets sync that appends each submission as a new row, so the spreadsheet workflow survives the move. Worth knowing it’s a Pro feature, whereas email notifications work on the free plan.
The honest trade-off in the other direction: Google Forms is unlimited and free. Most form backends have a monthly submission cap on their free tier, Formpaste included at 250 a month. If you’re collecting thousands of responses and don’t care what the form looks like, Google Forms wins on cost and it’s not close.
A migration checklist
If you’re switching a live form, the order matters:
- Export the existing Sheet first. Migration only affects new submissions, and your old responses stay where they are, but take the backup before you change anything.
- Rebuild the form on a page that isn’t linked yet, or behind a staging URL.
- Submit a real test and confirm it arrives in your inbox, not just that the page showed a success message.
- Check it on a phone. This is usually where a hand-built form needs the most attention, and where the old iframe was worst.
- Swap the link or embed for the new form.
- Leave the Google Form open but closed to responses for a week or two. Set it to stop accepting responses with a message pointing at the new page, so anyone with the old link isn’t stranded.
- Delete it once nothing has arrived there for a while.
Step 6 is the one people skip. Old links live in email signatures, PDFs and other people’s bookmarks for a long time.
The short version
Embedding a Google Form is fine when nobody’s judging the design and a Sheet is where you want the data. It cannot be made to look like your site, because an iframe is a separate document and your CSS cannot cross that boundary.
If the form is customer-facing, rebuilding it as real HTML is usually under an hour, and you get a form that matches your site, lands in your inbox, and can be filtered for spam.
If you want the markup to start from, the guide to adding a contact form to a static site has a complete accessible form. And since a public form attracts bots, stopping spam without CAPTCHA covers what to do about that. There’s also a fuller Google Forms comparison if you’re weighing the two side by side.