[{"data":1,"prerenderedAt":320},["ShallowReactive",2],{"blog-how-to-create-and-share-qr-codes-for-your-forms":3},{"blogData":4,"relatedArticles":29},{"id":5,"title":6,"author":7,"authorImage":8,"authorProfile":9,"coverImg":10,"coverImgAlt":11,"createdAt":12,"description":13,"featured":14,"jsonld":15,"keywords":16,"metaDescription":17,"metaImage":18,"metaTitle":19,"publishedAt":20,"slug":21,"updatedAt":22,"__hash__":23,"body":24,"coverImgWidth":25,"coverImgHeight":26,"readingStats":27},"blog\u002Fblog\u002Fhow-to-create-and-share-qr-codes-for-your-forms.md","How to Create & Share QR Codes for Your Forms","Harsh Shah",null,"https:\u002F\u002Flinkedin.com\u002Fin\u002Fharshshahseo","https:\u002F\u002Fformester-strapi.s3.ap-south-1.amazonaws.com\u002Fan_illustration_of_how_to_create_qr_code_in_formester_2e10b94de8.webp","an illustration of how to create qr code in formester","2024-07-03T23:21:51.218Z","Learn how to create and share QR codes for your forms with Formester. Simplify access and improve engagement by using easy-to-scan QR codes.\n",false,[],"create qr code for form, forms with qr code"," Learn how to create and share QR codes for your forms with Formester. Simplify access and boost engagement by using easy-to-scan QR codes.\n",[],"How to Create & Share QR Codes for Your Forms | Formester","2026-06-22T05:06:22.803Z","how-to-create-and-share-qr-codes-for-your-forms","2026-06-22T05:06:36.973Z","1O39S8pzJpJeEyiJTZmOpcl4M7AGxR3J50dlmfYEwDE","\u003Cp style=\"font-size: inherit;\">A QR code turns your form into something people can open by pointing a phone at it. No link to type, no URL to remember. Scan, and the form loads.\u003C\u002Fp>\n\n\u003Cp>That makes QR codes the simplest way to collect responses off a poster, a table tent, a product label, or a slide at the back of a room. This guide shows you how to generate one for a form or survey, customize it, download it, and place it where people will actually scan.\u003C\u002Fp>\n\n\u003Cp>If you already build forms in Formester, the QR code lives in the Publish tab and points straight at your live form, so it keeps working even after you edit the questions.\u003C\u002Fp>\n\n\u003Ch2>Why a QR Code Beats Sharing a Link\u003C\u002Fh2>\n\n\u003Cul>\n\u003Cli>No typing. People scan and land on the form instead of copying a long URL off a screen or flyer.\u003C\u002Fli>\n\u003Cli>Works anywhere a phone goes. A QR code on a table, badge, or receipt collects responses in the moment, before the intent fades.\u003C\u002Fli>\n\u003Cli>Fewer dead ends. A scanned link cannot be mistyped, so you lose fewer people to a 404 or a wrong address.\u003C\u002Fli>\n\u003Cli>Higher response rates on print. A code on a poster or product turns a passive glance into a tap, which is why retail and events lean on them for feedback.\u003C\u002Fli>\n\u003C\u002Ful>\n\n\u003Ch2>Where QR Codes for Forms Actually Pay Off\u003C\u002Fh2>\n\n\u003Ch3>Events and conferences\u003C\u002Fh3>\n\n\u003Cp>Print the code on badges, signage, and slides so attendees register or leave feedback without queueing at a laptop.\u003C\u002Fp>\n\n\u003Ch3>Surveys and customer feedback\u003C\u002Fh3>\n\n\u003Cp>Put a QR code on a receipt, table tent, or packaging and you capture opinions while the experience is fresh. Build the survey first with Formester's \u003Ca href=\"https:\u002F\u002Fformester.com\u002Fonline-survey-maker\u002F\">online survey maker\u003C\u002Fa>, then generate the code from it.\u003C\u002Fp>\n\n\u003Ch3>Marketing campaigns\u003C\u002Fh3>\n\n\u003Cp>Add the code to flyers, ads, and product inserts to capture leads or run a giveaway. One scan replaces a typed landing-page URL.\u003C\u002Fp>\n\n\u003Ch3>Product registration\u003C\u002Fh3>\n\n\u003Cp>Link the code on the box straight to a \u003Ca href=\"https:\u002F\u002Fformester.com\u002Fblog\u002Fhow-to-make-a-registration-form\u002F\">registration form\u003C\u002Fa> so buyers activate the product in seconds.\u003C\u002Fp>\n\n\u003Ch3>Classrooms and training\u003C\u002Fh3>\n\n\u003Cp>Share quizzes and course-evaluation forms by code so students open them on their own phones instead of passing a link around.\u003C\u002Fp>\n\n\u003Ch2>What About a QR Code for a Google Form?\u003C\u002Fh2>\n\n\u003Cp>Google Forms has no built-in QR generator. The workaround is manual: open your form, click Send, copy the link, then paste it into a separate QR code generator and download the image.\u003C\u002Fp>\n\n\u003Cp>It works, but you juggle two tools and the code is a flat image you cannot recolor or track inside the form. If you want the QR code, the form, and the responses in one place, build the form where the QR code is already part of publishing.\u003C\u002Fp>\n\n\u003Cp>For the step-by-step Google Forms route, see \u003Ca href=\"https:\u002F\u002Fformester.com\u002Fblog\u002Fhow-to-make-a-qr-code-for-a-google-form\u002F\">how to make a QR code for a Google Form\u003C\u002Fa>. The rest of this guide shows the one-tool version in Formester.\u003C\u002Fp>\n\n\u003Ch2>Generate a Form QR Code in Formester (5 Steps)\u003C\u002Fh2>\n\n\u003Cp>Formester generates the QR code for you the moment your form is ready to publish. No second tool, no copy-pasting links. Here is the full flow.\u003C\u002Fp>\n\n\u003Ch3>Step 1: Log in or sign up\u003C\u002Fh3>\n\n\u003Cp>Open your Formester account. If you do not have one, \u003Ca href=\"https:\u002F\u002Fapp.formester.com\u002Fusers\u002Fsign_up\u002F\">create a free account\u003C\u002Fa>. It takes under a minute and no card is needed.\u003C\u002Fp>\n\n\u003Ch3>Step 2: Build your form or survey\u003C\u002Fh3>\n\n\u003Cp>Click Create New Form. Start from a blank canvas or pick a template, then add your questions. A survey, a registration form, and a feedback form all work the same way for the QR step.\u003C\u002Fp>\n\n\u003Ch3>Step 3: Generate the QR code\u003C\u002Fh3>\n\n\u003Cp>Open the Publish section and click Generate QR Code. Formester builds a code that points to your live form link, so any edit you make to the questions still shows up when someone scans.\u003C\u002Fp>\n\n\u003Ch3>Step 4: Customize the color and download\u003C\u002Fh3>\n\n\u003Cp>Change the QR code color to match your brand, then download it. You get JPEG, SVG, and PNG. Use SVG for anything printed, since it stays crisp at any size, from a business card to a banner.\u003C\u002Fp>\n\n\u003Cp>Keep good contrast: a dark code on a light background scans fastest. Skip light-on-dark unless you have tested it on real phones.\u003C\u002Fp>\n\n\u003Ch3>Step 5: Place the QR code where people will scan it\u003C\u002Fh3>\n\n\u003Cp>Drop the image onto a poster, slide, email, packaging, or table tent. Add one line of context next to it so people know what they get for scanning, for example \"Scan to leave 30-second feedback.\" A code with no reason to scan gets ignored.\u003C\u002Fp>\n\n\u003Ch2>Best Practices for Form QR Codes\u003C\u002Fh2>\n\n\u003Cul>\n\u003Cli>Say what the scan is for. \"Scan to register\" or \"Scan to give feedback\" beats a bare code every time.\u003C\u002Fli>\n\u003Cli>Keep it big and high-contrast. Aim for at least 2 by 2 cm on print, larger if people scan from a distance.\u003C\u002Fli>\n\u003Cli>Test on two phones before you print. Check one iPhone, one Android, in the lighting where the code will live.\u003C\u002Fli>\n\u003Cli>Place it at eye level. A code low on a wall or buried in fine print gets skipped.\u003C\u002Fli>\n\u003Cli>Give people a reason. A discount, early access, or a prize draw lifts scan rates on a campaign.\u003C\u002Fli>\n\u003C\u002Ful>\n\n\u003Ch2>QR Code Not Scanning? Fix These First\u003C\u002Fh2>\n\n\u003Ch3>The code will not scan at all\u003C\u002Fh3>\n\n\u003Cp>Usually it is too small or too low contrast. Make it bigger, use dark code on a light background, and remove any logo that covers the corner squares.\u003C\u002Fp>\n\n\u003Ch3>It scans but the form does not open\u003C\u002Fh3>\n\n\u003Cp>The link is broken or the form is unpublished. Check the form is live and the link still resolves, then regenerate the code.\u003C\u002Fp>\n\n\u003Ch3>Low scan numbers\u003C\u002Fh3>\n\n\u003Cp>Either people cannot see the code or they have no reason to act. Move it to eye level and add a clear, benefit-led prompt.\u003C\u002Fp>\n\n\u003Ch3>Glare on a printed code\u003C\u002Fh3>\n\n\u003Cp>Glossy stock reflects light and blinds the camera. Print on matte where you can, and keep the code off curved or wrinkled surfaces.\u003C\u002Fp>\n\n\u003Ch2>Turn Your Next Form Into a Scan\u003C\u002Fh2>\n\n\u003Cp>A QR code removes the one thing that kills form responses on print: making people type a link. Scan, open, fill out, done.\u003C\u002Fp>\n\n\u003Cp>Build your form or survey, generate the code from the Publish tab, recolor it, download an SVG for print, and place it where people will see it. The whole loop takes minutes.\u003C\u002Fp>\n\n\u003Cp>Want the QR code, the form, and the responses in one tool? \u003Ca href=\"https:\u002F\u002Fapp.formester.com\u002Fusers\u002Fsign_up\u002F\">Start free with Formester\u003C\u002Fa> and generate a code for your first form today. You can also see the standalone \u003Ca href=\"https:\u002F\u002Fformester.com\u002Ffeatures\u002Fqr-code-generator\u002F\">QR code generator feature\u003C\u002Fa>.\u003C\u002Fp>\n\n\u003Csection class=\"faq\">\n\u003Ch2>QR Codes for Forms: FAQ\u003C\u002Fh2>\n\u003Cdetails>\u003Csummary>How do I create a QR code for a form?\u003C\u002Fsummary>\u003Cdiv>Build your form, open the Publish section, and click Generate QR Code. The code links straight to your live form, so anyone who scans it opens the form on their phone with no typing.\u003C\u002Fdiv>\u003C\u002Fdetails>\n\u003Cdetails>\u003Csummary>Can I add a QR code to a Google Form?\u003C\u002Fsummary>\u003Cdiv>Yes, but Google Forms has no built-in generator, so you copy the form link and paste it into a separate QR code generator. With Formester the code is generated for you from the Publish section. See how to make a QR code for a Google Form.\u003C\u002Fdiv>\u003C\u002Fdetails>\n\u003Cdetails>\u003Csummary>What is the difference between a static and a dynamic QR code?\u003C\u002Fsummary>\u003Cdiv>A static code encodes the link itself, so the destination is fixed once printed. A dynamic code points to a short URL you can redirect later. A QR code tied to a hosted form keeps working as long as the form stays live.\u003C\u002Fdiv>\u003C\u002Fdetails>\n\u003Cdetails>\u003Csummary>Why is my form QR code not scanning?\u003C\u002Fsummary>\u003Cdiv>Usually the code is too small, low contrast, or the form link is broken. Print it at least 2 by 2 cm, keep dark code on a light background, and test on two phones before publishing.\u003C\u002Fdiv>\u003C\u002Fdetails>\n\u003Cdetails>\u003Csummary>Can I customize and download the QR code?\u003C\u002Fsummary>\u003Cdiv>Yes. You can change the QR code color to match your brand and download it as a JPEG, SVG, or PNG. Use SVG for print so it stays sharp at any size.\u003C\u002Fdiv>\u003C\u002Fdetails>\n\u003C\u002Fsection>\n\n",1214,630,{"text":28},"7 min read",[30,188,282,301],{"title":31,"author":32,"authorImage":8,"authorProfile":8,"coverImg":33,"coverImgAlt":34,"createdAt":35,"description":36,"featured":14,"jsonld":37,"keywords":176,"metaDescription":177,"metaImage":178,"metaTitle":53,"publishedAt":35,"slug":179,"updatedAt":180,"__hash__":181,"body":182,"id":183,"coverImgWidth":184,"coverImgHeight":185,"readingStats":186},"How to Make an Anonymous Google Form or Survey","Harish Kumar","https:\u002F\u002Fformester-strapi.s3.ap-south-1.amazonaws.com\u002Fb0b75873f83d6e61_how-to-make-anonymous-google-form-or-survey-cover.jpg","Cover art for a guide to making an anonymous Google Form or survey","2026-06-05T02:14:37.000Z","Turn off email collection, strip identifying questions, and check the Responses tab to confirm. Plus what Google still records, and the one setting that quietly breaks anonymity.",[38],{"@context":39,"@graph":40},"https:\u002F\u002Fschema.org",[41,49,60,73,100,150,170],{"@type":42,"@id":43,"url":44,"name":45,"logo":46},"Organization","https:\u002F\u002Fformester.com\u002F#organization","https:\u002F\u002Fformester.com\u002F","Formester",{"@type":47,"url":48},"ImageObject","https:\u002F\u002Fformester.com\u002Flogo.png",{"@type":50,"@id":51,"url":52,"name":53,"isPartOf":54,"breadcrumb":55,"inLanguage":57,"description":36,"datePublished":58,"dateModified":59},"WebPage","https:\u002F\u002Fformester.com\u002Fblog\u002Fhow-to-make-anonymous-google-form-or-survey\u002F#webpage","https:\u002F\u002Fformester.com\u002Fblog\u002Fhow-to-make-anonymous-google-form-or-survey\u002F","How to Make Google Forms Anonymous (and What Gets Tracked)",{"@id":43},{"@id":56},"https:\u002F\u002Fformester.com\u002Fblog\u002Fhow-to-make-anonymous-google-form-or-survey\u002F#breadcrumb","en-US","2026-06-05","2026-09-01",{"@type":61,"@id":56,"itemListElement":62},"BreadcrumbList",[63,67,71],{"@type":64,"position":65,"name":66,"item":44},"ListItem",1,"Home",{"@type":64,"position":68,"name":69,"item":70},2,"Blog","https:\u002F\u002Fformester.com\u002Fblog\u002F",{"@type":64,"position":72,"name":31,"item":52},3,{"@type":74,"@id":75,"headline":31,"image":33,"author":76,"publisher":78,"inLanguage":57,"description":36,"datePublished":58,"dateModified":59,"mainEntityOfPage":79,"about":80,"mentions":87,"citation":90},"BlogPosting","https:\u002F\u002Fformester.com\u002Fblog\u002Fhow-to-make-anonymous-google-form-or-survey\u002F#article",{"@type":77,"name":32},"Person",{"@id":43},{"@id":51},[81],{"@type":82,"name":83,"applicationCategory":84,"url":85,"operatingSystem":86},"SoftwareApplication","Google Forms","BusinessApplication","https:\u002F\u002Fdocs.google.com\u002Fforms\u002F","Web",[88],{"@id":89},"https:\u002F\u002Fformester.com\u002F#software",[91,96],{"@type":50,"name":92,"url":93,"publisher":94},"Publish & share your form with responders","https:\u002F\u002Fsupport.google.com\u002Fdocs\u002Fanswer\u002F2839588",{"@type":42,"name":95},"Google",{"@type":50,"name":97,"url":98,"publisher":99},"View & manage form responses","https:\u002F\u002Fsupport.google.com\u002Fdocs\u002Fanswer\u002F139706",{"@type":42,"name":95},{"@type":101,"@id":102,"mainEntity":103},"FAQPage","https:\u002F\u002Fformester.com\u002Fblog\u002Fhow-to-make-anonymous-google-form-or-survey\u002F#faq",[104,110,114,118,122,126,130,134,138,142,146],{"@type":105,"name":106,"acceptedAnswer":107},"Question","How do I make a Google Form anonymous?",{"@type":108,"text":109},"Answer","Open the form and click Settings. Expand Responses and set Collect email addresses to Do not collect. Then remove any question that asks for a name, employee ID, phone number, or address. Respondents can now submit without revealing who they are.",{"@type":105,"name":111,"acceptedAnswer":112},"Are Google Forms anonymous by default?",{"@type":108,"text":113},"Mostly. Google Forms does not collect emails by default, but the Settings panel has an option that turns it on, and Limit to 1 response forces a sign-in. Check that both are off and remove any other identifying questions.",{"@type":105,"name":115,"acceptedAnswer":116},"Can a quiz be anonymous in Google Forms?",{"@type":108,"text":117},"Yes, if you turn off email collection and leave Release grades set to Immediately after each submission. Setting grades to release after manual review turns email collection back on. If you need an anonymous quiz that still shows a score, Formester can show it on the confirmation page without collecting an email.",{"@type":105,"name":119,"acceptedAnswer":120},"Does Google Forms track IP addresses?",{"@type":108,"text":121},"Google Forms does not log or show respondent IP addresses to the form owner. Google's own systems may keep IP data for spam and abuse prevention, but you cannot access it.",{"@type":105,"name":123,"acceptedAnswer":124},"Can the form owner see who submitted an anonymous Google Form?",{"@type":108,"text":125},"No, as long as email collection is off and the form has no identifying questions. Responses are recorded without a name or email column.",{"@type":105,"name":127,"acceptedAnswer":128},"Can anonymous surveys be traced?",{"@type":108,"text":129},"Not to a name by the form owner, as long as email collection is off and there are no identifying questions. Timestamps and free-text answers can still narrow a response down to one person on a small team, so keep the questions broad and avoid asking for details only one person would give.",{"@type":105,"name":131,"acceptedAnswer":132},"How do I know if my Google Form is anonymous?",{"@type":108,"text":133},"Submit the form yourself, then open the Responses tab and the linked Google Sheet. If there is no Email column and no name field, the form is anonymous.",{"@type":105,"name":135,"acceptedAnswer":136},"Can I limit one anonymous response per person?",{"@type":108,"text":137},"Not in Google Forms. Limit to 1 response requires a Google sign-in, which removes the anonymity. Formester can limit each person to one response by IP address without collecting any identity.",{"@type":105,"name":139,"acceptedAnswer":140},"Is an anonymous Google Form GDPR compliant?",{"@type":108,"text":141},"A form that collects no personal data falls outside most GDPR requirements. Post a privacy notice anyway, and avoid questions that could identify someone indirectly, such as department or job title in a small team.",{"@type":105,"name":143,"acceptedAnswer":144},"Can I add a 'You are anonymous' message to the form?",{"@type":108,"text":145},"Yes. Add a line to the form description, such as \"This survey is anonymous. We do not collect your name, email, or any identifying information.\" It tells people what to expect before they start.",{"@type":105,"name":147,"acceptedAnswer":148},"Is there a better tool than Google Forms for an anonymous survey?",{"@type":108,"text":149},"Formester keeps submissions anonymous while limiting each person to one response by IP address. It also adds branded surveys and spam protection that works without identifying anyone. It is worth a look when you need both anonymity and one response per person.",{"@type":151,"@id":152,"name":153,"description":154,"step":155},"HowTo","https:\u002F\u002Fformester.com\u002Fblog\u002Fhow-to-make-anonymous-google-form-or-survey\u002F#howto","Make a Google Form anonymous","Turn off email collection, turn off Limit to 1 response, remove identifying questions, and verify on the Responses tab.",[156,160,163,166],{"@type":157,"position":65,"name":158,"text":159},"HowToStep","Turn off email collection","Open the form and click Settings. Expand Responses, then set Collect email addresses to Do not collect. On a new form this is already the default.",{"@type":157,"position":68,"name":161,"text":162},"Turn off Limit to 1 response","In the same Responses section, under Requires sign-in, make sure Limit to 1 response is off. When it is on, every respondent must sign in to a Google Account.",{"@type":157,"position":72,"name":164,"text":165},"Remove identifying questions","Delete anything that asks for a name, an employee ID, a phone number, or a department in a small team. Any question that narrows the answer to one person identifies them.",{"@type":157,"position":167,"name":168,"text":169},4,"Verify with a test submission","Fill in the form yourself and open the Responses tab. If there is no Email column there and none in the linked Google Sheet, the form is not recording anything identifying.",{"@type":82,"@id":89,"url":44,"name":45,"applicationCategory":84,"operatingSystem":86,"offers":171},{"@type":172,"price":173,"priceCurrency":174,"description":175},"Offer","0","USD","Free forever plan, no credit card required","how to make google forms anonymous,anonymous google form,are google forms anonymous,is google forms anonymous,google form anonymous feedback,anonymous google survey,how to know if a google form is anonymous","How to make Google Forms anonymous and check that it worked. Plus the settings that quietly re-identify respondents, and what Google still records.",[],"how-to-make-anonymous-google-form-or-survey","2026-09-01T00:00:00.000Z","NKZ2b7j0p1RN_PG1AE111kgzFvjbjJovCBDbz23gT68","\n![Cover art for a guide to making an anonymous Google Form or survey](https:\u002F\u002Fformester-strapi.s3.ap-south-1.amazonaws.com\u002Fb0b75873f83d6e61_how-to-make-anonymous-google-form-or-survey-cover.jpg)\n\n\u003Cp style=\"font-size: inherit;\">An anonymous Google Form is one where nothing in the response points back to the person who filled it in. No email, no name, no employee ID. To make Google Forms anonymous, turn off email collection in Settings, remove any question that asks who someone is, and submit a test response to check. The setting that is easy to miss is Limit to 1 response. It forces every respondent to sign in to a Google Account, which undoes the anonymity.\u003C\u002Fp>\n\n\u003Cdiv class=\"tldr\">\n\u003Cp>\u003Cstrong>Quick answer\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Cstrong>You want the form anonymous:\u003C\u002Fstrong> open \u003Cstrong>Settings\u003C\u002Fstrong> and expand \u003Cstrong>Responses\u003C\u002Fstrong>. Set \u003Cstrong>Collect email addresses\u003C\u002Fstrong> to \u003Cstrong>Do not collect\u003C\u002Fstrong> and leave \u003Cstrong>Limit to 1 response\u003C\u002Fstrong> off. Then delete any question that asks for a name or an ID.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>You want to check it worked:\u003C\u002Fstrong> submit the form yourself and open the Responses tab. If there is no Email column there or in the linked Sheet, nothing identifying was recorded.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>You want anonymous and one response per person:\u003C\u002Fstrong> Google Forms cannot do both. Limit to 1 response makes everyone sign in to a Google Account, which removes the anonymity.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003C\u002Fdiv>\n\n\u003Ch2 id=\"how\">How do you make a Google Form anonymous?\u003C\u002Fh2>\n\n\u003Cp>The settings take a minute. The harder part is the questions you ask and the check at the end.\u003C\u002Fp>\n\n\u003Ch3>1. Turn off email collection\u003C\u002Fh3>\n\u003Cp>Open the form and click \u003Cstrong>Settings\u003C\u002Fstrong>. Expand \u003Cstrong>Responses\u003C\u002Fstrong>, then set \u003Cstrong>Collect email addresses\u003C\u002Fstrong> to \u003Cstrong>Do not collect\u003C\u002Fstrong>. On a new form this is already the default, so you are usually confirming it rather than changing it.\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"https:\u002F\u002Fformester-strapi.s3.ap-south-1.amazonaws.com\u002F46ee6f6816ea9e6c_anon-01-do-not-collect.jpg\" alt=\"Google Forms Settings with Collect email addresses set to Do not collect, marked with a red arrow\" loading=\"lazy\" style=\"width:100%;max-width:790px;height:auto;border-radius:10px;border:1px solid #d8dce3;box-shadow:0 1px 3px rgba(16,24,40,0.08);margin:18px 0;\" \u002F>\u003C\u002Fp>\n\n\u003Ch3>2. Turn off Limit to 1 response\u003C\u002Fh3>\n\u003Cp>In the same \u003Cstrong>Responses\u003C\u002Fstrong> section, under \u003Cstrong>Requires sign-in\u003C\u002Fstrong>, make sure \u003Cstrong>Limit to 1 response\u003C\u002Fstrong> is off. \u003Ca href=\"https:\u002F\u002Fsupport.google.com\u002Fdocs\u002Fanswer\u002F2839588\" target=\"_blank\" rel=\"noopener\">Google's documentation\u003C\u002Fa> says respondents must sign in to a Google Account when it is on. You cannot block duplicate responses and keep the form anonymous at the same time.\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"https:\u002F\u002Fformester-strapi.s3.ap-south-1.amazonaws.com\u002Fe6d94b1fa71e5957_anon-02-requires-sign-in.jpg\" alt=\"The Limit to 1 response setting in Google Forms sitting under a REQUIRES SIGN IN label, marked in red\" loading=\"lazy\" style=\"width:100%;max-width:790px;height:auto;border-radius:10px;border:1px solid #d8dce3;box-shadow:0 1px 3px rgba(16,24,40,0.08);margin:18px 0;\" \u002F>\u003C\u002Fp>\n\n\u003Ch3>3. Remove identifying questions\u003C\u002Fh3>\n\u003Cp>A form can still identify people with email collection off. If the first question asks for a name, the form is not anonymous. Delete anything that asks for a name, an employee ID, a phone number, or a department in a small team. On a team of eight, asking which department someone works in is enough to identify them.\u003C\u002Fp>\n\n\u003Ch3>4. Verify with a test submission\u003C\u002Fh3>\n\u003Cp>Fill in the form yourself and open the \u003Ca href=\"https:\u002F\u002Fsupport.google.com\u002Fdocs\u002Fanswer\u002F139706\" target=\"_blank\" rel=\"noopener\">\u003Cstrong>Responses\u003C\u002Fstrong> tab\u003C\u002Fa>. If there is no Email column there, and none in the linked Google Sheet, the form is not recording anything identifying. It is the one check that shows what was recorded rather than what was configured.\u003C\u002Fp>\n\n\u003Ch2 id=\"breaks\">Which other setting quietly breaks anonymity?\u003C\u002Fh2>\n\n\u003Cp>Step 2 covers the sign-in requirement. The other setting that re-identifies people only appears on quizzes. It lives under the quiz options rather than under Responses.\u003C\u002Fp>\n\u003Cp>\u003Cstrong>Quiz grades released after manual review.\u003C\u002Fstrong> If the form is a quiz and you set \u003Cstrong>Release grades\u003C\u002Fstrong> to \u003Cstrong>Later, after manual review\u003C\u002Fstrong>, Google turns email collection back on so it has somewhere to send the score. The option says this in small gray text under the radio button. It is easy to miss.\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"https:\u002F\u002Fformester-strapi.s3.ap-south-1.amazonaws.com\u002Fe90d133ba1164749_quiz-02-release-grades.jpg\" alt=\"Google Forms Release grades options, with Later after manual review marked in red because it turns email collection back on\" loading=\"lazy\" style=\"width:100%;max-width:720px;height:auto;border-radius:10px;border:1px solid #d8dce3;box-shadow:0 1px 3px rgba(16,24,40,0.08);margin:18px 0;\" \u002F>\u003C\u002Fp>\n\n\u003Ch2 id=\"tracked\">What does Google still track on an anonymous form?\u003C\u002Fh2>\n\n\u003Cp>Turning off email collection changes what you see in the Responses tab. It does not change what Google records on its own servers. This is what is and is not recorded:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Cstrong>The form owner sees no IP address.\u003C\u002Fstrong> Google Forms does not log or display respondent IPs to you. There is no column for it in the responses or in the Sheet.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Google keeps its own logs.\u003C\u002Fstrong> Its internal systems may retain data for spam and abuse handling. You cannot see that data, but Google still has it.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Timestamps are always recorded.\u003C\u002Fstrong> On a small team, a submission time can point to one person.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Free-text answers can identify people.\u003C\u002Fstrong> Someone who describes their own project in a comment box has told you who they are.\u003C\u002Fli>\n\u003C\u002Ful>\n\n\u003Ch2 id=\"best-practice\">How do you run an anonymous survey people actually trust?\u003C\u002Fh2>\n\n\u003Cp>The settings are only part of it. People only say what they think when they believe the form is anonymous. If a form makes people sign in before they can give feedback about a manager, they hold back, whatever the privacy notice says.\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Cstrong>Say so on the form.\u003C\u002Fstrong> Add a line to the description that the survey is anonymous and that you do not collect names, emails, or any identifying information.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Keep the questions broad.\u003C\u002Fstrong> Every demographic question narrows the pool. Two or three of them on a small team can narrow the answers down to one person.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Do not promise what the tool cannot do.\u003C\u002Fstrong> If you have turned on Limit to 1 response, the form is not anonymous. Do not tell people it is anonymous when it is not.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Share the results.\u003C\u002Fstrong> People decide how much to say in the next survey based on what happened after the last one.\u003C\u002Fli>\n\u003C\u002Ful>\n\n\u003Ch3>When an anonymous survey is the right choice\u003C\u002Fh3>\n\u003Cp>With an anonymous survey you cannot go back to someone about their answer. Use it where people will only speak up if nobody can tell who said it.\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Cstrong>Anonymous feedback about a manager or a course.\u003C\u002Fstrong> People soften what they say when their name is attached.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Harassment or safety reports.\u003C\u002Fstrong> Being able to report without being identified is often the only reason a report gets made.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Pay and satisfaction surveys.\u003C\u002Fstrong> The questions are personal and the answers are only useful as a total across the team.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Research on sensitive topics.\u003C\u002Fstrong> Health, or anything people would not discuss with a colleague.\u003C\u002Fli>\n\u003C\u002Ful>\n\n\u003Ch2 id=\"formester\">Where Formester fits\u003C\u002Fh2>\n\n\u003Cp>Google Forms makes you choose between blocking duplicate responses and keeping the form anonymous. Formester does not. It can limit each person to one response by IP address, so nobody has to sign in.\u003C\u002Fp>\n\u003Cp>\u003Ca href=\"https:\u002F\u002Fformester.com\u002Ffeatures\u002Fspam-protection\u002F\">Spam protection\u003C\u002Fa> is separate from identity. Invisible reCAPTCHA and AI spam scoring both work without a respondent account. You can also restrict the form to the domains you list, or start from a \u003Ca href=\"https:\u002F\u002Fformester.com\u002Ftemplates\u002F\">survey template\u003C\u002Fa> instead of stripping identifying fields out of a blank form.\u003C\u002Fp>\n\n\u003Cdiv style=\"background:linear-gradient(135deg,#7f56d9 0%,#6941c6 100%);padding:32px 28px;margin:36px 0;border-radius:12px;color:#ffffff;font-family:inherit;text-align:center;\">\n\u003Cp style=\"margin:0 0 12px 0;font-size:18px;font-weight:700;color:#ffffff;font-family:inherit;\">Anonymous, and one response per person\u003C\u002Fp>\n\u003Cp style=\"margin:0 0 20px 0;font-size:14px;line-height:1.55;color:#f4ebff;font-family:inherit;\">Limit each person to one response by IP address, with no sign-in and no email collected. Spam protection works without identifying anyone.\u003C\u002Fp>\n\u003Ca href=\"https:\u002F\u002Fapp.formester.com\u002Fusers\u002Fsign_up\" style=\"display:inline-block;padding:12px 24px;background:#ffffff;color:#6941c6;text-decoration:none;font-weight:700;border-radius:9999px;font-family:inherit;\">Try Formester free\u003C\u002Fa>\n\u003Cp style=\"margin:12px 0 0 0;font-size:13px;color:#e9d7fe;font-family:inherit;\">Free forever · No credit card · 56,000+ teams\u003C\u002Fp>\n\u003C\u002Fdiv>\n\n\u003Ch2>Related reading\u003C\u002Fh2>\n\n\u003Cul>\n\u003Cli>\u003Ca href=\"https:\u002F\u002Fformester.com\u002Fblog\u002Fhow-to-create-a-quiz-in-google-forms-the-only-guide-youll-need-in-2023\u002F\">\u003Cstrong>Create a quiz in Google Forms\u003C\u002Fstrong>\u003C\u002Fa>, where grade release quietly turns email collection back on.\u003C\u002Fli>\n\u003Cli>\u003Ca href=\"https:\u002F\u002Fformester.com\u002Fblog\u002F5-ways-to-view-responses-in-google-forms\u002F\">\u003Cstrong>View responses in Google Forms\u003C\u002Fstrong>\u003C\u002Fa>, the tab where you confirm nothing identifying was recorded.\u003C\u002Fli>\n\u003Cli>\u003Ca href=\"https:\u002F\u002Fformester.com\u002Fblog\u002Fcaptcha-for-google-forms\u002F\">\u003Cstrong>CAPTCHA for Google Forms\u003C\u002Fstrong>\u003C\u002Fa>, for keeping an open anonymous form free of bot submissions.\u003C\u002Fli>\n\u003Cli>\u003Ca href=\"https:\u002F\u002Fformester.com\u002Fblog\u002Fhow-to-make-a-questionnaire-in-google-forms\u002F\">\u003Cstrong>Make a questionnaire in Google Forms\u003C\u002Fstrong>\u003C\u002Fa>, for structuring the questions themselves.\u003C\u002Fli>\n\u003C\u002Ful>\n\n\u003Csection class=\"faq\">\n\u003Ch2>Anonymous Google Forms FAQ\u003C\u002Fh2>\n\u003Cdetails>\u003Csummary>How do I make a Google Form anonymous?\u003C\u002Fsummary>\u003Cdiv>Open the form and click Settings. Expand Responses and set Collect email addresses to Do not collect. Then remove any question that asks for a name, employee ID, phone number, or address. Respondents can now submit without revealing who they are.\u003C\u002Fdiv>\u003C\u002Fdetails>\n\u003Cdetails>\u003Csummary>Are Google Forms anonymous by default?\u003C\u002Fsummary>\u003Cdiv>Mostly. Google Forms does not collect emails by default, but the Settings panel has an option that turns it on, and Limit to 1 response forces a sign-in. Check that both are off and remove any other identifying questions.\u003C\u002Fdiv>\u003C\u002Fdetails>\n\u003Cdetails>\u003Csummary>Can a quiz be anonymous in Google Forms?\u003C\u002Fsummary>\u003Cdiv>Yes, if you turn off email collection and leave Release grades set to Immediately after each submission. Setting grades to release after manual review turns email collection back on. If you need an anonymous quiz that still shows a score, Formester can show it on the confirmation page without collecting an email.\u003C\u002Fdiv>\u003C\u002Fdetails>\n\u003Cdetails>\u003Csummary>Does Google Forms track IP addresses?\u003C\u002Fsummary>\u003Cdiv>Google Forms does not log or show respondent IP addresses to the form owner. Google's own systems may keep IP data for spam and abuse prevention, but you cannot access it.\u003C\u002Fdiv>\u003C\u002Fdetails>\n\u003Cdetails>\u003Csummary>Can the form owner see who submitted an anonymous Google Form?\u003C\u002Fsummary>\u003Cdiv>No, as long as email collection is off and the form has no identifying questions. Responses are recorded without a name or email column.\u003C\u002Fdiv>\u003C\u002Fdetails>\n\u003Cdetails>\u003Csummary>Can anonymous surveys be traced?\u003C\u002Fsummary>\u003Cdiv>Not to a name by the form owner, as long as email collection is off and there are no identifying questions. Timestamps and free-text answers can still narrow a response down to one person on a small team, so keep the questions broad and avoid asking for details only one person would give.\u003C\u002Fdiv>\u003C\u002Fdetails>\n\u003Cdetails>\u003Csummary>How do I know if my Google Form is anonymous?\u003C\u002Fsummary>\u003Cdiv>Submit the form yourself, then open the Responses tab and the linked Google Sheet. If there is no Email column and no name field, the form is anonymous.\u003C\u002Fdiv>\u003C\u002Fdetails>\n\u003Cdetails>\u003Csummary>Can I limit one anonymous response per person?\u003C\u002Fsummary>\u003Cdiv>Not in Google Forms. Limit to 1 response requires a Google sign-in, which removes the anonymity. Formester can limit each person to one response by IP address without collecting any identity.\u003C\u002Fdiv>\u003C\u002Fdetails>\n\u003Cdetails>\u003Csummary>Is an anonymous Google Form GDPR compliant?\u003C\u002Fsummary>\u003Cdiv>A form that collects no personal data falls outside most GDPR requirements. Post a privacy notice anyway, and avoid questions that could identify someone indirectly, such as department or job title in a small team.\u003C\u002Fdiv>\u003C\u002Fdetails>\n\u003Cdetails>\u003Csummary>Can I add a 'You are anonymous' message to the form?\u003C\u002Fsummary>\u003Cdiv>Yes. Add a line to the form description, such as \"This survey is anonymous. We do not collect your name, email, or any identifying information.\" It tells people what to expect before they start.\u003C\u002Fdiv>\u003C\u002Fdetails>\n\u003Cdetails>\u003Csummary>Is there a better tool than Google Forms for an anonymous survey?\u003C\u002Fsummary>\u003Cdiv>Formester keeps submissions anonymous while limiting each person to one response by IP address. It also adds branded surveys and spam protection that works without identifying anyone. It is worth a look when you need both anonymity and one response per person.\u003C\u002Fdiv>\u003C\u002Fdetails>\n\u003C\u002Fsection>\n","blog\u002Fblog\u002Fhow-to-make-anonymous-google-form-or-survey.md",2400,1350,{"text":187},"9 min read",{"title":189,"author":7,"authorImage":8,"authorProfile":9,"coverImg":190,"coverImgAlt":191,"createdAt":192,"description":193,"featured":14,"jsonld":194,"keywords":272,"metaDescription":193,"metaImage":273,"metaTitle":274,"publishedAt":275,"slug":276,"updatedAt":277,"__hash__":278,"body":279,"id":280,"coverImgWidth":25,"coverImgHeight":26,"readingStats":281},"How to Send HTML Form Data to Google Sheets for Free","https:\u002F\u002Fformester-strapi.s3.ap-south-1.amazonaws.com\u002FHow_to_Make_User_Research_Survey_1_ec282fa0b6.png","a cover of a blog post that talks about sending contact form data to google sheets","2025-03-06T18:34:23.526Z","Push HTML form submissions straight into Google Sheets, free. Working Apps Script code, a no-code option, and a method-by-method comparison so you pick once.",[195],{"@graph":196,"@context":39},[197,207,233,267],{"@id":198,"@type":199,"image":190,"author":200,"headline":189,"publisher":202,"description":193,"dateModified":204,"datePublished":205,"mainEntityOfPage":206},"https:\u002F\u002Fformester.com\u002Fblog\u002Fhow-to-send-contact-form-data-to-google-sheets-free\u002F#article","Article",{"url":201,"name":32,"@type":77},"https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Fharish-kumar2424\u002F",{"logo":203,"name":45,"@type":42},{"url":48,"@type":47},"2026-06-09","2025-03-06","https:\u002F\u002Fformester.com\u002Fblog\u002Fhow-to-send-contact-form-data-to-google-sheets-free\u002F",{"name":208,"step":209,"tool":222,"@type":151,"totalTime":230,"estimatedCost":231},"How to send HTML form data to Google Sheets with Apps Script",[210,213,216,219],{"name":211,"text":212,"@type":157},"Create the Sheet","Open Google Sheets, create a new spreadsheet, name the tab Submissions, and add column headers in row 1 that match the name attributes on your HTML form inputs.",{"name":214,"text":215,"@type":157},"Open Apps Script and paste the doPost function","Inside the Sheet, open Extensions then Apps Script. Paste the doPost script provided in this guide. Save the project.",{"name":217,"text":218,"@type":157},"Run initialSetup and deploy the web app","Pick initialSetup in the function dropdown and click Run. Approve the OAuth prompt. Click Deploy, New deployment, Web app, Execute as Me, Anyone has access. Copy the deployment URL.",{"name":220,"text":221,"@type":157},"Wire the deployment URL into your HTML form","Point your form's fetch endpoint or action attribute at the deployment URL. Submit a test entry. The row appears in the Sheet within a second.",[223,226,228],{"name":224,"@type":225},"Google Sheets","HowToTool",{"name":227,"@type":225},"Google Apps Script",{"name":229,"@type":225},"HTML form on your site","PT30M",{"@type":232,"value":173,"currency":174},"MonetaryAmount",{"@type":101,"mainEntity":234},[235,239,243,247,251,255,259,263],{"name":236,"@type":105,"acceptedAnswer":237},"Is it really free to send HTML form data to Google Sheets?",{"text":238,"@type":108},"Yes. Google Apps Script is free with any Google account, capped at one Sheets write per second per user. Google Forms is free. Formester's free plan includes unlimited submissions.",{"name":240,"@type":105,"acceptedAnswer":241},"How secure is form data in Google Sheets?",{"text":242,"@type":108},"Google encrypts data at rest and in transit. Lock sharing to specific accounts, neutralize formula characters on input to prevent CSV injection, and do not use a Sheet for payment data or passwords.",{"name":244,"@type":105,"acceptedAnswer":245},"What is the rate limit on Apps Script writes to Sheets?",{"text":246,"@type":108},"Roughly 100 requests per 100 seconds per user, per Google's published quotas. A contact form sustaining one submission per second sits comfortably inside that envelope.",{"name":248,"@type":105,"acceptedAnswer":249},"Can I send file uploads from the form into Google Sheets?",{"text":250,"@type":108},"Sheets cannot hold a file. Write the file to Google Drive via Apps Script and store the Drive URL in the cell, or use a no-code builder that handles file uploads natively.",{"name":252,"@type":105,"acceptedAnswer":253},"How do I add CAPTCHA or spam protection?",{"text":254,"@type":108},"The script in this guide ships a honeypot field. For more, add Google reCAPTCHA v3 on the client and verify the token server-side before writing to the Sheet.",{"name":256,"@type":105,"acceptedAnswer":257},"How do I get an email when someone submits the form?",{"text":258,"@type":108},"Add MailApp.sendEmail inside the doPost function in Apps Script. Or use the autoresponder feature in a no-code builder and skip the code.",{"name":260,"@type":105,"acceptedAnswer":261},"Can I use this on Netlify, Vercel, or any static site?",{"text":262,"@type":108},"Yes. The Apps Script deployment URL is a fetch target. It works from any frontend, hosted anywhere, with no backend on your side.",{"name":264,"@type":105,"acceptedAnswer":265},"Can I move from this setup to a database later?",{"text":266,"@type":108},"Easily. Sheets is a great starter store. When you cross a few hundred submissions a week, route the same form to a database or CRM in parallel with the Sheet.",{"@type":61,"itemListElement":268},[269,270,271],{"item":44,"name":66,"@type":64,"position":65},{"item":70,"name":69,"@type":64,"position":68},{"item":206,"name":189,"@type":64,"position":72},"how to send contact form data to google sheets free,\ncontact form template,\ncontact form automation,",[],"HTML Form to Google Sheets: 3 Free Methods (Code)","2026-06-15T04:53:58.393Z","how-to-send-contact-form-data-to-google-sheets-free","2026-06-15T04:53:58.398Z","SpJtH4MN2xn0shG-jzP6RaMox4pENmrLXV3OuYWeFbk","![a cover of a blog post that talks about sending contact form data to google sheets](https:\u002F\u002Fformester-strapi.s3.ap-south-1.amazonaws.com\u002FHow_to_Make_User_Research_Survey_1_ec282fa0b6.png)\n\n\u003Cstyle>\n\u002F* batch-1 blog normalisation *\u002F\n.fmstr-blog-lead {\n  font-size: 17px !important;\n  line-height: 1.65 !important;\n  color: #475467 !important;\n  font-weight: 400 !important;\n  margin: 0 0 16px !important;\n}\n.fmstr-blog-lead a { color: #6941c6 !important; font-weight: 500; }\n.fmstr-blog-lead a:hover { text-decoration: underline !important; }\n.fmstr-blog-lead strong { color: #101828; font-weight: 700; }\nsection[class^=\"fmstr-cmp-\"], section[class*=\" fmstr-cmp-\"] {\n  padding-top: 28px !important;\n  padding-bottom: 28px !important;\n}\n@media (max-width: 540px) {\n  section[class^=\"fmstr-cmp-\"], section[class*=\" fmstr-cmp-\"] {\n    padding-top: 24px !important;\n    padding-bottom: 24px !important;\n  }\n}\n\u003C\u002Fstyle>\n\n\u003Cstyle id=\"fmstr-blog-mobile-fullwidth-v3\">\n@media (max-width: 760px) {\n  .art-section { padding-left: 12px !important; padding-right: 12px !important; }\n}\n@media (max-width: 540px) {\n  .art-section { padding-left: 6px !important; padding-right: 6px !important; padding-top: 24px !important; }\n  section[class^=\"fmstr-cmp-\"], section[class*=\" fmstr-cmp-\"] {\n    padding-left: 0 !important; padding-right: 0 !important;\n    overflow-x: hidden !important; box-sizing: border-box !important;\n  }\n  section[class^=\"fmstr-cmp-\"] *, section[class^=\"fmstr-cmp-\"] *::before, section[class^=\"fmstr-cmp-\"] *::after { box-sizing: border-box !important; }\n  section[class^=\"fmstr-cmp-\"] > *, section[class^=\"fmstr-cmp-\"] > * > * { min-width: 0 !important; }\n  section[class^=\"fmstr-cmp-\"] [class*=\"__container\"] {\n    padding-left: 0 !important; padding-right: 0 !important;\n    max-width: 100% !important; width: 100% !important;\n  }\n  section[class^=\"fmstr-cmp-\"] [class*=\"__card\"],\n  section[class^=\"fmstr-cmp-\"] [class*=\"__step\"],\n  section[class^=\"fmstr-cmp-\"] [class*=\"__panel\"],\n  section[class^=\"fmstr-cmp-\"] [class*=\"__tool\"],\n  section[class^=\"fmstr-cmp-\"] [class*=\"__verdict\"],\n  section[class^=\"fmstr-cmp-\"] [class*=\"__row\"],\n  section[class^=\"fmstr-cmp-\"] [class*=\"__fix\"],\n  section[class^=\"fmstr-cmp-\"] [class*=\"__callout\"],\n  section[class^=\"fmstr-cmp-\"] [class*=\"__quote\"],\n  section[class^=\"fmstr-cmp-\"] [class*=\"__tldr\"],\n  section[class^=\"fmstr-cmp-\"] [class*=\"__answer\"],\n  section[class^=\"fmstr-cmp-\"] [class*=\"__faq\"],\n  section[class^=\"fmstr-cmp-\"] details {\n    padding-left: 14px !important; padding-right: 14px !important;\n    margin-left: 0 !important; margin-right: 0 !important;\n  }\n  section[class^=\"fmstr-cmp-\"] p, section[class^=\"fmstr-cmp-\"] li { font-size: 15px !important; line-height: 1.6 !important; }\n  section[class^=\"fmstr-cmp-\"] h2 { font-size: 22px !important; line-height: 1.22 !important; }\n  section[class^=\"fmstr-cmp-\"] h3 { font-size: 18px !important; line-height: 1.3 !important; }\n  section[class^=\"fmstr-cmp-\"] h4 { font-size: 16px !important; line-height: 1.35 !important; }\n  section[class^=\"fmstr-cmp-\"] table { display: block; overflow-x: auto; -webkit-overflow-scrolling: touch; width: 100% !important; }\n  section[class^=\"fmstr-cmp-\"] img, section[class^=\"fmstr-cmp-\"] iframe, section[class^=\"fmstr-cmp-\"] video { max-width: 100% !important; height: auto !important; }\n  section[class^=\"fmstr-cmp-\"] pre, section[class^=\"fmstr-cmp-\"] code {\n    white-space: pre-wrap !important; overflow-wrap: anywhere !important; word-break: break-word !important;\n  }\n  section[class^=\"fmstr-cmp-\"] pre { overflow-x: auto; }\n  .fmstr-blog-lead { font-size: 16.5px !important; }\n}\n\u003C\u002Fstyle>\n\n\u003Cp class=\"fmstr-blog-lead\">If you have a contact form, an opt-in widget, or a custom HTML form on your site, you can route every submission straight into a Google Sheet without a database, a Zapier subscription, or a paid backend. Three free methods get you there. Two need code. One does not.\u003C\u002Fp>\n\n\u003Cp class=\"fmstr-blog-lead\">This guide gives you the working Apps Script (paste-ready), the no-code path, and a side-by-side comparison so you know which one to pick before you start.\u003C\u002Fp>\n\n\u003Cstyle>\n.fmstr-cmp-tmpl-tldr a { text-decoration: none !important; }\n.fmstr-cmp-tmpl-tldr {\n--c-card: #f7f3ff;\n--c-fg-1: #101828; --c-fg-2: #475467; --c-fg-3: #697586;\n--c-violet-500: #7f56d9; --c-violet-600: #6941c6; --c-violet-700: #5b34b1;\n--c-edge: #e4d7ff; --c-border: #d6c2f7;\n--c-shadow: 0 1px 3px rgba(16,24,40,.05);\nbackground: transparent;\npadding: 28px 0 40px;\nfont-family: inherit;\ncolor: var(--c-fg-1);\ntext-align: left !important; overflow-x: hidden; -webkit-text-size-adjust: 100%;}\n.fmstr-cmp-tmpl-tldr *, .fmstr-cmp-tmpl-tldr *::before, .fmstr-cmp-tmpl-tldr *::after { box-sizing: border-box; }\n.fmstr-cmp-tmpl-tldr__container { max-width: 1200px; margin: 0 auto; }\n.fmstr-cmp-tmpl-tldr__card {\nbackground: var(--c-card);\nborder: 1px solid var(--c-border);\nborder-left: 4px solid var(--c-violet-500);\nborder-radius: 14px;\npadding: 22px 26px;\nbox-shadow: var(--c-shadow);\ndisplay: flex; flex-direction: column; gap: 12px;\n}\n.fmstr-cmp-tmpl-tldr__label {\nfont-size: 12px !important;\nfont-weight: 700 !important;\nletter-spacing: 0.08em !important;\ntext-transform: uppercase;\ncolor: var(--c-violet-700) !important;\ndisplay: inline-flex;\nalign-items: center;\ngap: 8px;\nmargin: 0 !important;\n}\n.fmstr-cmp-tmpl-tldr__label::before {\ncontent: \"\";\nwidth: 8px; height: 8px; border-radius: 9999px;\nbackground: var(--c-violet-500);\ndisplay: inline-block;\n}\n.fmstr-cmp-tmpl-tldr__body {\nfont-size: 16px !important;\nline-height: 1.65 !important;\ncolor: var(--c-fg-1);\nmargin: 0 !important;\nfont-weight: 500 !important;\n}\n.fmstr-cmp-tmpl-tldr__body strong { color: var(--c-violet-700); font-weight: 700; }\n.fmstr-cmp-tmpl-tldr__list {\nmargin: 0 !important; padding: 0 0 0 20px !important;\ndisplay: flex; flex-direction: column; gap: 8px;\nfont-size: 15.5px; line-height: 1.6; color: var(--c-fg-1);\n}\n.fmstr-cmp-tmpl-tldr__list li { margin: 0; }\n.fmstr-cmp-tmpl-tldr__list strong { color: var(--c-violet-700); font-weight: 700; }\n\n@media (max-width: 540px) {\n.fmstr-cmp-tmpl-tldr { padding: 20px 0 28px; }\n.fmstr-cmp-tmpl-tldr__card { padding: 18px 20px; }\n.fmstr-cmp-tmpl-tldr__body { font-size: 15px !important; }\n.fmstr-cmp-tmpl-tldr__list { font-size: 14.5px; }\n}\n\n\n\u002F* mobile-safety-v2 *\u002F\n.fmstr-cmp-tmpl-tldr img, .fmstr-cmp-tmpl-tldr table, .fmstr-cmp-tmpl-tldr pre, .fmstr-cmp-tmpl-tldr iframe, .fmstr-cmp-tmpl-tldr video { max-width: 100%; }\n.fmstr-cmp-tmpl-tldr > * { min-width: 0; }\n.fmstr-cmp-tmpl-tldr [class*='__grid'] > *, .fmstr-cmp-tmpl-tldr [class*='__list'] > *, .fmstr-cmp-tmpl-tldr [class*='__cards'] > * { min-width: 0; max-width: 100%; }\n@media (max-width: 540px) {\n  .fmstr-cmp-tmpl-tldr pre { overflow-x: auto; -webkit-overflow-scrolling: touch; }\n  .fmstr-cmp-tmpl-tldr table { display: block; overflow-x: auto; -webkit-overflow-scrolling: touch; }\n}\n\u003C\u002Fstyle>\n\n\u003Csection class=\"fmstr-cmp-tmpl-tldr\" aria-labelledby=\"fmstr-cmp-tmpl-tldr-label\">\n\u003Cdiv class=\"fmstr-cmp-tmpl-tldr__container\">\n\u003Cdiv class=\"fmstr-cmp-tmpl-tldr__card\">\n\u003Cp class=\"fmstr-cmp-tmpl-tldr__label\" id=\"fmstr-cmp-tmpl-tldr-label\">Quick answer\u003C\u002Fp>\n\u003Cp class=\"fmstr-cmp-tmpl-tldr__body\">You can push HTML form submissions into a Google Sheet for free with three methods. Pick one in 30 seconds:\u003C\u002Fp>\n\u003Cul class=\"fmstr-cmp-tmpl-tldr__list\">\n\u003Cli>\u003Cstrong>Google Forms\u003C\u002Fstrong> (2 minutes, no code): use it when the form does not need to live on your own domain.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Google Apps Script\u003C\u002Fstrong> (20-40 minutes, paste-ready code below): use it when you already have an HTML form on your site and are fine maintaining a script.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>No-code builder like \u003Ca href=\"https:\u002F\u002Fformester.com\u002F\">Formester\u003C\u002Fa>\u003C\u002Fstrong> (5 minutes, no code): use it when you want spam control, conditional logic, and Sheets sync in one place.\u003C\u002Fli>\n\u003Cli>Apps Script caps at roughly one Sheets write per second per user, which is plenty for a contact form.\u003C\u002Fli>\n\u003Cli>Never store payment data or passwords in Sheets. It is a great inbox, not a vault.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003C\u002Fdiv>\n\u003C\u002Fdiv>\n\u003C\u002Fsection>\n\n\n\u003Cstyle>\n.fmstr-cmp-tmpl-cmp a { text-decoration: none !important; }\n.fmstr-cmp-tmpl-cmp a.fmstr-cmp-tmpl-cmp__link { color: var(--c-violet-600) !important; font-weight: 600; }\n.fmstr-cmp-tmpl-cmp a.fmstr-cmp-tmpl-cmp__link:hover { text-decoration: underline !important; }\n.fmstr-cmp-tmpl-cmp {\n--c-card: #ffffff;\n--c-fg-1: #101828; --c-fg-2: #475467; --c-fg-3: #697586;\n--c-violet-500: #7f56d9; --c-violet-600: #6941c6; --c-violet-700: #5b34b1;\n--c-tint: #f7f3ff; --c-edge: #e4d7ff;\n--c-border: #eaecf0;\n--c-shadow: 0 1px 3px rgba(16,24,40,.05);\n--c-good: #12b76a; --c-bad: #f04438;\nbackground: transparent;\npadding: 48px 0;\nfont-family: inherit;\ncolor: var(--c-fg-1);\ntext-align: left !important;\noverflow-x: hidden;\n}\n.fmstr-cmp-tmpl-cmp *, .fmstr-cmp-tmpl-cmp *::before, .fmstr-cmp-tmpl-cmp *::after { box-sizing: border-box; }\n.fmstr-cmp-tmpl-cmp > *, .fmstr-cmp-tmpl-cmp > * > * { min-width: 0; }\n.fmstr-cmp-tmpl-cmp__container { max-width: 1200px; margin: 0 auto; }\n.fmstr-cmp-tmpl-cmp__head { margin: 0 0 28px !important; }\n.fmstr-cmp-tmpl-cmp__h2 {\nfont-size: clamp(26px, 3vw, 36px) !important; font-weight: 700 !important; line-height: 1.15 !important;\nletter-spacing: -.02em !important; margin: 0 !important; color: var(--c-fg-1);\n}\n.fmstr-cmp-tmpl-cmp__intro { color: var(--c-fg-3); font-size: 17px !important; line-height: 1.6 !important; margin: 14px 0 0 !important; }\n.fmstr-cmp-tmpl-cmp__grid {\ndisplay: grid; grid-template-columns: repeat(3, 1fr); gap: 14px;\n}\n.fmstr-cmp-tmpl-cmp__card {\nbackground: var(--c-card);\nborder: 1px solid var(--c-border);\nborder-radius: 14px;\npadding: 22px;\nbox-shadow: var(--c-shadow);\ndisplay: flex; flex-direction: column; gap: 12px;\nmin-width: 0;\n}\n.fmstr-cmp-tmpl-cmp__card--featured {\nborder-color: var(--c-edge);\nbackground: var(--c-tint);\nbox-shadow: 0 4px 18px rgba(105,65,198,.10);\n}\n.fmstr-cmp-tmpl-cmp__chip {\ndisplay: inline-flex; align-items: center;\nfont-size: 11px !important; font-weight: 700 !important; letter-spacing: 0.08em !important;\ntext-transform: uppercase; color: var(--c-violet-700) !important;\nbackground: var(--c-tint); border: 1px solid var(--c-edge);\npadding: 4px 10px; border-radius: 9999px;\nalign-self: flex-start;\n}\n.fmstr-cmp-tmpl-cmp__name {\nfont-size: 18px !important; font-weight: 700 !important; color: var(--c-fg-1);\nmargin: 0 !important; line-height: 1.3 !important;\n}\n.fmstr-cmp-tmpl-cmp__best {\nfont-size: 13.5px !important; color: var(--c-fg-3); margin: 0 !important;\n}\n.fmstr-cmp-tmpl-cmp__best strong { color: var(--c-fg-1); font-weight: 600; }\n.fmstr-cmp-tmpl-cmp__divider {\nheight: 1px; background: var(--c-border); margin: 4px 0; border: 0;\n}\n.fmstr-cmp-tmpl-cmp__list {\nmargin: 0; padding: 0; list-style: none;\ndisplay: flex; flex-direction: column; gap: 8px;\n}\n.fmstr-cmp-tmpl-cmp__item {\ndisplay: block; position: relative; padding-left: 26px;\nfont-size: 14px; line-height: 1.5; color: var(--c-fg-2);\n}\n.fmstr-cmp-tmpl-cmp__item::before {\ncontent: \"\\2713\";\nposition: absolute; left: 0; top: 0.05em;\ncolor: var(--c-good); font-weight: 700; line-height: 1.45;\n}\n.fmstr-cmp-tmpl-cmp__item--con::before { content: \"\\2717\"; color: var(--c-bad); position: absolute; left: 0; top: 0.05em; font-weight: 700; }\n.fmstr-cmp-tmpl-cmp__rules {\nmargin: 28px 0 0; padding: 18px 22px;\nbackground: var(--c-tint); border: 1px solid var(--c-edge);\nborder-radius: 12px;\ndisplay: flex; flex-direction: column; gap: 8px;\n}\n.fmstr-cmp-tmpl-cmp__rules-label {\nfont-size: 11px !important; font-weight: 700 !important; letter-spacing: 0.08em !important;\ntext-transform: uppercase; color: var(--c-violet-700) !important; margin: 0 !important;\n}\n.fmstr-cmp-tmpl-cmp__rules-list {\nmargin: 0 !important; padding: 0 0 0 20px !important;\nfont-size: 14.5px; line-height: 1.6; color: var(--c-fg-1);\ndisplay: flex; flex-direction: column; gap: 6px;\n}\n\n@media (max-width: 920px) {\n.fmstr-cmp-tmpl-cmp__grid { grid-template-columns: 1fr; gap: 12px; }\n}\n@media (max-width: 540px) {\n.fmstr-cmp-tmpl-cmp { padding: 36px 0; }\n.fmstr-cmp-tmpl-cmp__card { padding: 18px 20px; }\n}\n\n\n\u002F* mobile-safety-v2 *\u002F\n.fmstr-cmp-tmpl-cmp img, .fmstr-cmp-tmpl-cmp table, .fmstr-cmp-tmpl-cmp pre, .fmstr-cmp-tmpl-cmp iframe, .fmstr-cmp-tmpl-cmp video { max-width: 100%; }\n.fmstr-cmp-tmpl-cmp > * { min-width: 0; }\n.fmstr-cmp-tmpl-cmp [class*='__grid'] > *, .fmstr-cmp-tmpl-cmp [class*='__list'] > *, .fmstr-cmp-tmpl-cmp [class*='__cards'] > * { min-width: 0; max-width: 100%; }\n@media (max-width: 540px) {\n  .fmstr-cmp-tmpl-cmp pre { overflow-x: auto; -webkit-overflow-scrolling: touch; }\n  .fmstr-cmp-tmpl-cmp table { display: block; overflow-x: auto; -webkit-overflow-scrolling: touch; }\n}\n\u003C\u002Fstyle>\n\n\u003Csection class=\"fmstr-cmp-tmpl-cmp\" aria-labelledby=\"fmstr-cmp-tmpl-cmp-h2\">\n\u003Cdiv class=\"fmstr-cmp-tmpl-cmp__container\">\n\u003Cdiv class=\"fmstr-cmp-tmpl-cmp__head\">\n\u003Ch2 class=\"fmstr-cmp-tmpl-cmp__h2\" id=\"fmstr-cmp-tmpl-cmp-h2\">Which method should you pick?\u003C\u002Fh2>\n\u003Cp class=\"fmstr-cmp-tmpl-cmp__intro\">Three free routes from form submission to a Google Sheet row. Match the method to where you already are.\u003C\u002Fp>\n\u003C\u002Fdiv>\n\u003Cdiv class=\"fmstr-cmp-tmpl-cmp__grid\">\n\n\u003Cdiv class=\"fmstr-cmp-tmpl-cmp__card\">\n\u003Cspan class=\"fmstr-cmp-tmpl-cmp__chip\">Method 1\u003C\u002Fspan>\n\u003Ch3 class=\"fmstr-cmp-tmpl-cmp__name\">Google Forms\u003C\u002Fh3>\n\u003Cp class=\"fmstr-cmp-tmpl-cmp__best\">\u003Cstrong>Best for:\u003C\u002Fstrong> A form you do not need to embed on your own site.\u003C\u002Fp>\n\u003Chr class=\"fmstr-cmp-tmpl-cmp__divider\">\n\u003Cul class=\"fmstr-cmp-tmpl-cmp__list\">\n\u003Cli class=\"fmstr-cmp-tmpl-cmp__item\">2-minute setup, no code at all.\u003C\u002Fli>\n\u003Cli class=\"fmstr-cmp-tmpl-cmp__item\">Free with any Google account.\u003C\u002Fli>\n\u003Cli class=\"fmstr-cmp-tmpl-cmp__item\">Responses auto-link to a Sheet.\u003C\u002Fli>\n\u003Cli class=\"fmstr-cmp-tmpl-cmp__item fmstr-cmp-tmpl-cmp__item--con\">Lives on a Google URL, not your domain.\u003C\u002Fli>\n\u003Cli class=\"fmstr-cmp-tmpl-cmp__item fmstr-cmp-tmpl-cmp__item--con\">Limited design control.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003C\u002Fdiv>\n\n\u003Cdiv class=\"fmstr-cmp-tmpl-cmp__card\">\n\u003Cspan class=\"fmstr-cmp-tmpl-cmp__chip\">Method 2\u003C\u002Fspan>\n\u003Ch3 class=\"fmstr-cmp-tmpl-cmp__name\">Google Apps Script\u003C\u002Fh3>\n\u003Cp class=\"fmstr-cmp-tmpl-cmp__best\">\u003Cstrong>Best for:\u003C\u002Fstrong> A custom HTML form you already have on your site.\u003C\u002Fp>\n\u003Chr class=\"fmstr-cmp-tmpl-cmp__divider\">\n\u003Cul class=\"fmstr-cmp-tmpl-cmp__list\">\n\u003Cli class=\"fmstr-cmp-tmpl-cmp__item\">Free forever, no usage cap on Sheets writes (within Google quotas).\u003C\u002Fli>\n\u003Cli class=\"fmstr-cmp-tmpl-cmp__item\">Paste-ready code, no edits required.\u003C\u002Fli>\n\u003Cli class=\"fmstr-cmp-tmpl-cmp__item\">Stays on your domain, no third-party branding.\u003C\u002Fli>\n\u003Cli class=\"fmstr-cmp-tmpl-cmp__item fmstr-cmp-tmpl-cmp__item--con\">20-40 minute setup.\u003C\u002Fli>\n\u003Cli class=\"fmstr-cmp-tmpl-cmp__item fmstr-cmp-tmpl-cmp__item--con\">You maintain the script and the deployment.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003C\u002Fdiv>\n\n\u003Cdiv class=\"fmstr-cmp-tmpl-cmp__card fmstr-cmp-tmpl-cmp__card--featured\">\n\u003Cspan class=\"fmstr-cmp-tmpl-cmp__chip\">Method 3 &middot; No-code\u003C\u002Fspan>\n\u003Ch3 class=\"fmstr-cmp-tmpl-cmp__name\">Formester\u003C\u002Fh3>\n\u003Cp class=\"fmstr-cmp-tmpl-cmp__best\">\u003Cstrong>Best for:\u003C\u002Fstrong> Embedding on any site with spam control, conditional logic, and Sheets sync.\u003C\u002Fp>\n\u003Chr class=\"fmstr-cmp-tmpl-cmp__divider\">\n\u003Cul class=\"fmstr-cmp-tmpl-cmp__list\">\n\u003Cli class=\"fmstr-cmp-tmpl-cmp__item\">5-minute setup, no code at all.\u003C\u002Fli>\n\u003Cli class=\"fmstr-cmp-tmpl-cmp__item\">Free plan includes unlimited responses.\u003C\u002Fli>\n\u003Cli class=\"fmstr-cmp-tmpl-cmp__item\">Native \u003Ca class=\"fmstr-cmp-tmpl-cmp__link\" href=\"https:\u002F\u002Fformester.com\u002Fintegrations\u002F\">Google Sheets integration\u003C\u002Fa>, OAuth, retries handled.\u003C\u002Fli>\n\u003Cli class=\"fmstr-cmp-tmpl-cmp__item\">Spam filtering, conditional logic, analytics built in.\u003C\u002Fli>\n\u003Cli class=\"fmstr-cmp-tmpl-cmp__item fmstr-cmp-tmpl-cmp__item--con\">Branded footer on the free plan.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003C\u002Fdiv>\n\n\u003C\u002Fdiv>\n\n\u003Cdiv class=\"fmstr-cmp-tmpl-cmp__rules\">\n\u003Cp class=\"fmstr-cmp-tmpl-cmp__rules-label\">Decision rule\u003C\u002Fp>\n\u003Cul class=\"fmstr-cmp-tmpl-cmp__rules-list\">\n\u003Cli>If the form already exists in HTML and you are fine maintaining a script, use Apps Script.\u003C\u002Fli>\n\u003Cli>If you do not need to embed the form on your own domain, use Google Forms.\u003C\u002Fli>\n\u003Cli>If you want zero maintenance, spam control, conditional logic, and Google Sheets sync in one place, use a no-code form builder like Formester.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003C\u002Fdiv>\n\u003C\u002Fdiv>\n\u003C\u002Fsection>\n\n\n\u003Cstyle>\n.fmstr-cmp-tmpl-steps a { text-decoration: none !important; }\n.fmstr-cmp-tmpl-steps a.fmstr-cmp-tmpl-steps__link { color: var(--c-violet-600) !important; font-weight: 600; }\n.fmstr-cmp-tmpl-steps a.fmstr-cmp-tmpl-steps__link:hover { text-decoration: underline !important; }\n.fmstr-cmp-tmpl-steps {\n--c-card: #ffffff;\n--c-fg-1: #101828; --c-fg-2: #475467; --c-fg-3: #697586;\n--c-violet-500: #7f56d9; --c-violet-600: #6941c6; --c-violet-700: #5b34b1;\n--c-tint: #f7f3ff; --c-edge: #e4d7ff;\n--c-border: #eaecf0;\n--c-code-bg: #0f172a; --c-code-fg: #e2e8f0;\n--c-shadow: 0 1px 3px rgba(16,24,40,.05);\nbackground: transparent;\npadding: 48px 0;\nfont-family: inherit;\ncolor: var(--c-fg-1);\ntext-align: left !important;\noverflow-x: hidden;\n}\n.fmstr-cmp-tmpl-steps *, .fmstr-cmp-tmpl-steps *::before, .fmstr-cmp-tmpl-steps *::after { box-sizing: border-box; }\n.fmstr-cmp-tmpl-steps > *, .fmstr-cmp-tmpl-steps > * > * { min-width: 0; }\n.fmstr-cmp-tmpl-steps__container { max-width: 1200px; margin: 0 auto; }\n.fmstr-cmp-tmpl-steps__head { margin: 0 0 28px !important; }\n.fmstr-cmp-tmpl-steps__h2 {\nfont-size: clamp(26px, 3vw, 36px) !important; font-weight: 700 !important; line-height: 1.15 !important;\nletter-spacing: -.02em !important; margin: 0 !important; color: var(--c-fg-1);\n}\n.fmstr-cmp-tmpl-steps__intro { color: var(--c-fg-3); font-size: 17px !important; line-height: 1.6 !important; margin: 14px 0 0 !important; }\n.fmstr-cmp-tmpl-steps__list {\ndisplay: flex; flex-direction: column; gap: 14px;\nmargin: 0; padding: 0; list-style: none;\n}\n.fmstr-cmp-tmpl-steps__item {\nbackground: var(--c-card);\nborder: 1px solid var(--c-border);\nborder-radius: 14px;\npadding: 22px 24px;\nbox-shadow: var(--c-shadow);\ndisplay: flex; gap: 12px;\nalign-items: flex-start;\nmin-width: 0;\n}\n.fmstr-cmp-tmpl-steps__num {\nflex-shrink: 0;\nwidth: 26px; line-height: 1; height: 26px; border-radius: 7px;\nbackground: var(--c-tint);\nborder: 1px solid var(--c-edge);\ncolor: var(--c-violet-700) !important;\nfont-weight: 800; font-size: 13px;\ndisplay: inline-flex; align-items: center; justify-content: center;\n}\n.fmstr-cmp-tmpl-steps__main { flex: 1; min-width: 0; }\n.fmstr-cmp-tmpl-steps__title {\nfont-size: 17px !important; font-weight: 700 !important; line-height: 1.3 !important;\ncolor: var(--c-fg-1); margin: 0 0 6px !important;\n}\n.fmstr-cmp-tmpl-steps__body {\nfont-size: 15px !important; line-height: 1.6 !important;\ncolor: var(--c-fg-2); margin: 0 0 10px !important;\n}\n.fmstr-cmp-tmpl-steps__body:last-child { margin-bottom: 0 !important; }\n.fmstr-cmp-tmpl-steps__body code {\nbackground: #f4f4f7; padding: 1px 6px; border-radius: 5px;\nfont-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\nfont-size: 13.5px; color: var(--c-violet-700);\nborder: 1px solid var(--c-border);\n}\n.fmstr-cmp-tmpl-steps__code {\nmargin: 12px 0 4px;\nbackground: var(--c-code-bg);\ncolor: var(--c-code-fg);\nborder-radius: 10px;\npadding: 16px 18px;\noverflow-x: auto;\nfont-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\nfont-size: 13px;\nline-height: 1.6;\nwhite-space: pre;\nmax-width: 100%;\n}\n.fmstr-cmp-tmpl-steps__code-label {\ndisplay: block; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\nfont-size: 11.5px; font-weight: 700; letter-spacing: 0.06em;\ntext-transform: uppercase; color: #94a3b8;\nmargin: 0 0 10px;\n}\n.fmstr-cmp-tmpl-steps__note {\nmargin: 12px 0 0 !important; padding: 12px 14px;\nbackground: var(--c-tint); border: 1px solid var(--c-edge);\nborder-radius: 10px;\nfont-size: 14px !important; line-height: 1.55 !important;\ncolor: var(--c-fg-1);\n}\n.fmstr-cmp-tmpl-steps__note strong { color: var(--c-violet-700); font-weight: 700; }\n\n@media (max-width: 540px) {\n.fmstr-cmp-tmpl-steps { padding: 36px 0; }\n.fmstr-cmp-tmpl-steps__item { padding: 18px 20px; gap: 14px; }\n.fmstr-cmp-tmpl-steps__num { width: 34px; height: 34px; font-size: 15px; }\n.fmstr-cmp-tmpl-steps__title { font-size: 16px !important; }\n.fmstr-cmp-tmpl-steps__body { font-size: 14.5px !important; }\n.fmstr-cmp-tmpl-steps__code { font-size: 12px; padding: 14px 16px; }\n}\n\n\n\u002F* mobile-safety-v2 *\u002F\n.fmstr-cmp-tmpl-steps img, .fmstr-cmp-tmpl-steps table, .fmstr-cmp-tmpl-steps pre, .fmstr-cmp-tmpl-steps iframe, .fmstr-cmp-tmpl-steps video { max-width: 100%; }\n.fmstr-cmp-tmpl-steps > * { min-width: 0; }\n.fmstr-cmp-tmpl-steps [class*='__grid'] > *, .fmstr-cmp-tmpl-steps [class*='__list'] > *, .fmstr-cmp-tmpl-steps [class*='__cards'] > * { min-width: 0; max-width: 100%; }\n@media (max-width: 540px) {\n  .fmstr-cmp-tmpl-steps pre { overflow-x: auto; -webkit-overflow-scrolling: touch; }\n  .fmstr-cmp-tmpl-steps table { display: block; overflow-x: auto; -webkit-overflow-scrolling: touch; }\n}\n\n\n\n\u002F* mobile-inline-num *\u002F\n@media (max-width: 540px) {\n  .fmstr-cmp-tmpl-steps__item { padding: 18px 16px; gap: 10px; flex-direction: row; align-items: flex-start; }\n  .fmstr-cmp-tmpl-steps__num { width: 28px; height: 28px; font-size: 13px; border-radius: 8px; }\n}\n\n\u002F* step-inline-num-restructure *\u002F\n.fmstr-cmp-tmpl-steps__item { display: block !important; }\n.fmstr-cmp-tmpl-steps__title { display: block; }\n.fmstr-cmp-tmpl-steps__num { display: inline-block !important; vertical-align: 2px; margin-right: 8px; padding: 2px 8px; width: auto !important; height: auto !important; border-radius: 6px; font-size: 12.5px !important; line-height: 1.3 !important; }\n@media (max-width: 540px) {\n  .fmstr-cmp-tmpl-steps__num { font-size: 11.5px !important; padding: 2px 7px; margin-right: 6px; }\n}\n\u003C\u002Fstyle>\n\n\u003Csection class=\"fmstr-cmp-tmpl-steps\" aria-labelledby=\"fmstr-cmp-tmpl-steps-h2\">\n\u003Cdiv class=\"fmstr-cmp-tmpl-steps__container\">\n\u003Cdiv class=\"fmstr-cmp-tmpl-steps__head\">\n\u003Ch2 class=\"fmstr-cmp-tmpl-steps__h2\" id=\"fmstr-cmp-tmpl-steps-h2\">Method 2: Google Apps Script, full working setup\u003C\u002Fh2>\n\u003Cp class=\"fmstr-cmp-tmpl-steps__intro\">\u003Cstrong>Method 1 is one click in Google Forms. Method 3 is a no-code toggle in Formester.\u003C\u002Fstrong> The only method that needs a real walkthrough is Method 2. Here it is, in full.\u003C\u002Fp>\n\u003Cp class=\"fmstr-cmp-tmpl-steps__intro\">Paste-ready code that handles any field name in your HTML form, sanitizes against \u003Ca class=\"fmstr-cmp-tmpl-steps__link\" href=\"https:\u002F\u002Fowasp.org\u002Fwww-community\u002Fattacks\u002FCSV_Injection\">CSV formula injection\u003C\u002Fa>, and works with both \u003Ccode>application\u002Fjson\u003C\u002Fcode> and standard form-encoded submissions.\u003C\u002Fp>\n\u003C\u002Fdiv>\n\u003Col class=\"fmstr-cmp-tmpl-steps__list\">\n\n\u003Cli class=\"fmstr-cmp-tmpl-steps__item\">\n\u003Ch3 class=\"fmstr-cmp-tmpl-steps__title\">\u003Cspan class=\"fmstr-cmp-tmpl-steps__num\" aria-hidden=\"true\">1\u003C\u002Fspan>Create the Sheet\u003C\u002Fh3>\n\u003Cp class=\"fmstr-cmp-tmpl-steps__body\">Open \u003Ca class=\"fmstr-cmp-tmpl-steps__link\" href=\"https:\u002F\u002Fdocs.google.com\u002Fspreadsheets\u002F\">Google Sheets\u003C\u002Fa> and create a new spreadsheet. Name the tab \u003Ccode>Submissions\u003C\u002Fcode>. In row 1, add column headers that match the \u003Ccode>name\u003C\u002Fcode> attributes on your form inputs. Add \u003Ccode>timestamp\u003C\u002Fcode> as the first column. The script reads row 1 as the source of truth for column mapping, so a typo in a header is a typo in the data.\u003C\u002Fp>\n\u003Cp class=\"fmstr-cmp-tmpl-steps__body\">Example row 1: \u003Ccode>timestamp | name | email | message\u003C\u002Fcode>\u003C\u002Fp>\n\u003C\u002Fli>\n\n\u003Cli class=\"fmstr-cmp-tmpl-steps__item\">\n\u003Ch3 class=\"fmstr-cmp-tmpl-steps__title\">\u003Cspan class=\"fmstr-cmp-tmpl-steps__num\" aria-hidden=\"true\">2\u003C\u002Fspan>Open Apps Script and paste the code\u003C\u002Fh3>\n\u003Cp class=\"fmstr-cmp-tmpl-steps__body\">Inside the Sheet, go to Extensions, then Apps Script. Delete the boilerplate and paste this:\u003C\u002Fp>\n\u003Cpre class=\"fmstr-cmp-tmpl-steps__code\">\u003Cspan class=\"fmstr-cmp-tmpl-steps__code-label\">Code.gs\u003C\u002Fspan>const SHEET_NAME = 'Submissions';\nconst SCRIPT_PROP = PropertiesService.getScriptProperties();\n\nfunction initialSetup() {\n  const activeSpreadsheet = SpreadsheetApp.getActiveSpreadsheet();\n  SCRIPT_PROP.setProperty('key', activeSpreadsheet.getId());\n}\n\nfunction doPost(e) {\n  const lock = LockService.getScriptLock();\n  lock.tryLock(10000);\n\n  try {\n    const doc = SpreadsheetApp.openById(SCRIPT_PROP.getProperty('key'));\n    const sheet = doc.getSheetByName(SHEET_NAME);\n\n    const headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0];\n    const nextRow = sheet.getLastRow() + 1;\n\n    \u002F\u002F Honeypot: if a hidden field named \"website\" is filled, drop the submission.\n    if (e.parameter.website) {\n      return ContentService.createTextOutput(JSON.stringify({ result: 'ignored' }))\n        .setMimeType(ContentService.MimeType.JSON);\n    }\n\n    const sanitize = (value) =&gt; {\n      if (typeof value !== 'string') return value;\n      \u002F\u002F Block CSV \u002F formula injection\n      return \u002F^[=+\\-@]\u002F.test(value) ? \"'\" + value : value;\n    };\n\n    const newRow = headers.map((header) =&gt; {\n      if (header === 'timestamp') return new Date();\n      return sanitize(e.parameter[header] || '');\n    });\n\n    sheet.getRange(nextRow, 1, 1, newRow.length).setValues([newRow]);\n\n    return ContentService\n      .createTextOutput(JSON.stringify({ result: 'success', row: nextRow }))\n      .setMimeType(ContentService.MimeType.JSON);\n  } catch (err) {\n    return ContentService\n      .createTextOutput(JSON.stringify({ result: 'error', error: err.toString() }))\n      .setMimeType(ContentService.MimeType.JSON);\n  } finally {\n    lock.releaseLock();\n  }\n}\u003C\u002Fpre>\n\u003Cp class=\"fmstr-cmp-tmpl-steps__body\">Save the script. Then in the function dropdown at the top of the editor, pick \u003Ccode>initialSetup\u003C\u002Fcode> and click Run once. Approve the OAuth prompt when Google asks. You will only do this once.\u003C\u002Fp>\n\u003C\u002Fli>\n\n\u003Cli class=\"fmstr-cmp-tmpl-steps__item\">\n\u003Ch3 class=\"fmstr-cmp-tmpl-steps__title\">\u003Cspan class=\"fmstr-cmp-tmpl-steps__num\" aria-hidden=\"true\">3\u003C\u002Fspan>Deploy as a web app\u003C\u002Fh3>\n\u003Cp class=\"fmstr-cmp-tmpl-steps__body\">Click Deploy, then New deployment. Pick Web app. Set Execute as: Me. Set Who has access: Anyone. Click Deploy. Copy the long URL that ends in \u003Ccode>\u002Fexec\u003C\u002Fcode>. That URL is your form endpoint.\u003C\u002Fp>\n\u003Cdiv class=\"fmstr-cmp-tmpl-steps__note\">\u003Cstrong>Heads-up:\u003C\u002Fstrong> every time you change the script, redeploy and grab the new URL. Old URLs keep working at the old script version, which is the most common cause of \"I updated my code and nothing changed\" complaints.\u003C\u002Fdiv>\n\u003C\u002Fli>\n\n\u003Cli class=\"fmstr-cmp-tmpl-steps__item\">\n\u003Ch3 class=\"fmstr-cmp-tmpl-steps__title\">\u003Cspan class=\"fmstr-cmp-tmpl-steps__num\" aria-hidden=\"true\">4\u003C\u002Fspan>Wire up your HTML form\u003C\u002Fh3>\n\u003Cp class=\"fmstr-cmp-tmpl-steps__body\">Drop this into your page. Replace \u003Ccode>PASTE_YOUR_DEPLOYMENT_URL_HERE\u003C\u002Fcode> with the URL from step 3.\u003C\u002Fp>\n\u003Cpre class=\"fmstr-cmp-tmpl-steps__code\">\u003Cspan class=\"fmstr-cmp-tmpl-steps__code-label\">index.html\u003C\u002Fspan>&lt;form id=\"contact-form\"&gt;\n  &lt;input type=\"text\" name=\"name\" required placeholder=\"Name\" \u002F&gt;\n  &lt;input type=\"email\" name=\"email\" required placeholder=\"Email\" \u002F&gt;\n  &lt;textarea name=\"message\" required placeholder=\"Message\"&gt;&lt;\u002Ftextarea&gt;\n  &lt;!-- Honeypot: hidden from humans, filled by bots --&gt;\n  &lt;input type=\"text\" name=\"website\" tabindex=\"-1\" autocomplete=\"off\" style=\"position:absolute;left:-9999px\" \u002F&gt;\n  &lt;button type=\"submit\"&gt;Send&lt;\u002Fbutton&gt;\n&lt;\u002Fform&gt;\n\n&lt;script&gt;\n  const form = document.getElementById('contact-form');\n  const endpoint = 'PASTE_YOUR_DEPLOYMENT_URL_HERE';\n\n  form.addEventListener('submit', async (e) =&gt; {\n    e.preventDefault();\n    const data = new FormData(form);\n    try {\n      await fetch(endpoint, { method: 'POST', body: data });\n      form.reset();\n      alert('Thanks. We will be in touch.');\n    } catch (err) {\n      alert('Something went wrong. Try again in a minute.');\n    }\n  });\n&lt;\u002Fscript&gt;\u003C\u002Fpre>\n\u003Cp class=\"fmstr-cmp-tmpl-steps__body\">Submit a test entry. The row should appear in your Sheet within a second.\u003C\u002Fp>\n\u003Cdiv class=\"fmstr-cmp-tmpl-steps__note\">\u003Cstrong>Rate limit to know about:\u003C\u002Fstrong> Google caps the Sheets-backed Apps Script at roughly \u003Ca class=\"fmstr-cmp-tmpl-steps__link\" href=\"https:\u002F\u002Fdevelopers.google.com\u002Fsheets\u002Fapi\u002Flimits\">100 requests per 100 seconds per user\u003C\u002Fa>, or one write per second. For a contact form that is plenty. If you expect bursts (a launch, a paid ad campaign), queue submissions or use a builder that handles retries.\u003C\u002Fdiv>\n\u003C\u002Fli>\n\n\u003C\u002Fol>\n\u003C\u002Fdiv>\n\u003C\u002Fsection>\n\n\u003Cstyle>\n.fmstr-cmp-tmpl-midcta a { text-decoration: none !important; }\n.fmstr-cmp-tmpl-midcta { background: transparent; padding: 48px 0; font-family: inherit; color: #101828; overflow-x: hidden; }\n.fmstr-cmp-tmpl-midcta *, .fmstr-cmp-tmpl-midcta *::before, .fmstr-cmp-tmpl-midcta *::after { box-sizing: border-box; }\n.fmstr-cmp-tmpl-midcta__container { max-width: 1200px; margin: 0 auto; }\n.fmstr-cmp-tmpl-midcta__card { width: 100%; background: linear-gradient(135deg, #f7f3ff 0%, #faf7ff 100%); border: 1px solid #e4d7ff; border-radius: 18px; padding: 48px 32px; text-align: center; box-shadow: 0 4px 24px rgba(127, 86, 217, 0.08); }\n.fmstr-cmp-tmpl-midcta__inner { max-width: 760px; margin: 0 auto; }\n.fmstr-cmp-tmpl-midcta__eyebrow { display: inline-block; padding: 4px 12px; background: #ffffff; border: 1px solid #e4d7ff; border-radius: 9999px; color: #5b34b1 !important; font-size: 11.5px !important; font-weight: 700 !important; letter-spacing: 0.06em !important; text-transform: uppercase; margin: 0 0 14px !important; }\n.fmstr-cmp-tmpl-midcta__h2 { font-size: clamp(22px, 3vw, 28px) !important; font-weight: 700 !important; line-height: 1.2 !important; letter-spacing: -0.02em !important; margin: 0 0 12px !important; color: #101828 !important; }\n.fmstr-cmp-tmpl-midcta__body { font-size: 16px !important; line-height: 1.55 !important; color: #475467 !important; margin: 0 0 22px !important; }\n.fmstr-cmp-tmpl-midcta__cta { display: inline-flex !important; align-items: center; gap: 8px; background: #7f56d9 !important; color: #ffffff !important; border: 1px solid #7f56d9 !important; padding: 12px 26px !important; border-radius: 9999px !important; font-size: 15px !important; font-weight: 600 !important; text-decoration: none !important; transition: background .15s ease, transform .15s ease; }\n.fmstr-cmp-tmpl-midcta__cta:hover { background: #6941c6 !important; border-color: #6941c6 !important; color: #ffffff !important; text-decoration: none !important; transform: translateY(-1px); }\n.fmstr-cmp-tmpl-midcta__cta::after { content: \"\\2192\"; transition: transform .15s ease; }\n.fmstr-cmp-tmpl-midcta__cta:hover::after { transform: translateX(2px); }\n.fmstr-cmp-tmpl-midcta__strip { font-size: 13px !important; color: #697586 !important; margin: 20px 0 0 !important; display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: 6px 14px; width: 100%; }\n.fmstr-cmp-tmpl-midcta__strip span { color: #d6c2f7; }\n@media (max-width: 760px) {\n  .fmstr-cmp-tmpl-midcta__card { padding: 36px 22px; }\n}\n@media (max-width: 540px) {\n  .fmstr-cmp-tmpl-midcta { padding: 32px 0; }\n  .fmstr-cmp-tmpl-midcta__card { padding: 26px 16px; border-radius: 14px; }\n  .fmstr-cmp-tmpl-midcta__h2 { font-size: 20px !important; }\n  .fmstr-cmp-tmpl-midcta__body { font-size: 15px !important; }\n  .fmstr-cmp-tmpl-midcta__cta { padding: 11px 22px !important; font-size: 14.5px !important; width: 100%; justify-content: center; }\n  .fmstr-cmp-tmpl-midcta__strip { font-size: 12.5px !important; gap: 4px 10px; }\n}\n\u003C\u002Fstyle>\n\n\u003Csection class=\"fmstr-cmp-tmpl-midcta\" aria-labelledby=\"fmstr-cmp-tmpl-midcta-h2\">\n\u003Cdiv class=\"fmstr-cmp-tmpl-midcta__container\">\n\u003Cdiv class=\"fmstr-cmp-tmpl-midcta__card\">\n\u003Cdiv class=\"fmstr-cmp-tmpl-midcta__inner\">\n\u003Cspan class=\"fmstr-cmp-tmpl-midcta__eyebrow\">No-code path\u003C\u002Fspan>\n\u003Ch2 class=\"fmstr-cmp-tmpl-midcta__h2\" id=\"fmstr-cmp-tmpl-midcta-h2\">Send HTML form data to Google Sheets, without writing a single line of code\u003C\u002Fh2>\n\u003Cp class=\"fmstr-cmp-tmpl-midcta__body\">Drop in a Formester form, connect Google Sheets, done. Two-way sync, free plan, no script to maintain.\u003C\u002Fp>\n\u003Ca class=\"fmstr-cmp-tmpl-midcta__cta\" href=\"https:\u002F\u002Fapp.formester.com\u002Fusers\u002Fsign_up\" style=\"background: #7f56d9 !important; color: #ffffff !important; border-color: #7f56d9 !important; text-decoration: none !important;\">Start free on Formester\u003C\u002Fa>\n\u003Cp class=\"fmstr-cmp-tmpl-midcta__strip\">Free forever plan\u003Cspan>&bull;\u003C\u002Fspan>No credit card\u003Cspan>&bull;\u003C\u002Fspan>Setup in 2 minutes\u003C\u002Fp>\n\u003C\u002Fdiv>\n\u003C\u002Fdiv>\n\u003C\u002Fdiv>\n\u003C\u002Fsection>\n\n\u003Cstyle>\n\u002F* host-link-override *\u002F\n.fmstr-cmp-tmpl-faq a { text-decoration: none !important; }\n.fmstr-cmp-tmpl-faq {\n--c-card: #ffffff;\n--c-fg-1: #101828; --c-fg-2: #475467; --c-fg-3: #697586;\n--c-violet-600: #6941c6;\n--c-tint: #f7f3ff; --c-edge: #e4d7ff;\n--c-border: #eaecf0; --c-chip-bg: #f4f4f7;\n--c-shadow: 0 1px 3px rgba(16,24,40,.05);\n\nbackground: transparent; padding: 56px 24px;\nfont-family: inherit;\ncolor: var(--c-fg-1);\ntext-align: left !important; overflow-x: hidden; -webkit-text-size-adjust: 100%;}\n.fmstr-cmp-tmpl-faq *, .fmstr-cmp-tmpl-faq *::before, .fmstr-cmp-tmpl-faq *::after { box-sizing: border-box; }\n.fmstr-cmp-tmpl-faq__container { max-width: 1200px; margin: 0 auto; }\n.fmstr-cmp-tmpl-faq__h2 { font-size: clamp(26px, 3vw, 36px) !important; font-weight: 700 !important; line-height: 1.15 !important; letter-spacing: -.02em !important; margin: 0 !important; color: var(--c-fg-1); text-align: left; }\n.fmstr-cmp-tmpl-faq__intro { color: var(--c-fg-3); font-size: 17px !important; line-height: 1.6 !important; margin: 14px 0 28px !important; text-align: left; }\n.fmstr-cmp-tmpl-faq__list { display: flex; flex-direction: column; gap: 12px; }\n.fmstr-cmp-tmpl-faq__item {\nbackground: var(--c-card); border: 1px solid var(--c-border);\nborder-radius: 14px; box-shadow: var(--c-shadow); overflow: hidden;\n}\n.fmstr-cmp-tmpl-faq__item > summary {\npadding: 18px 22px; cursor: pointer; font-weight: 600; font-size: 16.5px;\ncolor: var(--c-fg-1); display: flex; align-items: center; gap: 14px;\nlist-style: none;\n}\n.fmstr-cmp-tmpl-faq__item > summary::-webkit-details-marker { display: none; }\n.fmstr-cmp-tmpl-faq__item > summary::before {\ncontent: \"\"; width: 28px; height: 28px; border-radius: 8px; flex-shrink: 0;\nbackground-color: var(--c-chip-bg);\nbackground-image: url(\"data:image\u002Fsvg+xml,%3Csvg xmlns='http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg' width='14' height='14' viewBox='0 0 14 14' fill='none' stroke='%2375747f' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 5l4 4 4-4'\u002F%3E%3C\u002Fsvg%3E\");\nbackground-repeat: no-repeat; background-position: center;\ntransition: transform .15s ease, background-color .15s ease;\n}\n.fmstr-cmp-tmpl-faq__item[open] > summary::before { transform: rotate(180deg); background-color: var(--c-tint); }\n.fmstr-cmp-tmpl-faq__item[open] > summary { color: var(--c-violet-600) !important; }\n.fmstr-cmp-tmpl-faq__answer { padding: 0 22px 22px 64px; color: var(--c-fg-2); font-size: 15.5px; line-height: 1.7; }\n.fmstr-cmp-tmpl-faq__answer a { color: var(--c-violet-600) !important; text-decoration: none !important; font-weight: 600; }\n.fmstr-cmp-tmpl-faq__answer a:hover { text-decoration: underline !important; }\n.fmstr-cmp-tmpl-faq__answer code {\nbackground: var(--c-chip-bg); padding: 1px 6px; border-radius: 5px;\nfont-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\nfont-size: 13.5px; color: var(--c-violet-600);\nborder: 1px solid var(--c-border);\n}\n\n@media (max-width: 760px) {\n.fmstr-cmp-tmpl-faq { padding: 40px 16px; }\n.fmstr-cmp-tmpl-faq__intro { font-size: 15.5px !important; text-align: left; }\n.fmstr-cmp-tmpl-faq__item > summary { padding: 16px 16px; font-size: 15.5px; gap: 12px; }\n.fmstr-cmp-tmpl-faq__item > summary::before { width: 26px; height: 26px; }\n.fmstr-cmp-tmpl-faq__answer { padding: 0 16px 18px 16px; font-size: 15px; line-height: 1.65; }\n}\n\n\n\u002F* mobile-safety-v2 *\u002F\n.fmstr-cmp-tmpl-faq img, .fmstr-cmp-tmpl-faq table, .fmstr-cmp-tmpl-faq pre, .fmstr-cmp-tmpl-faq iframe, .fmstr-cmp-tmpl-faq video { max-width: 100%; }\n.fmstr-cmp-tmpl-faq > * { min-width: 0; }\n.fmstr-cmp-tmpl-faq [class*='__grid'] > *, .fmstr-cmp-tmpl-faq [class*='__list'] > *, .fmstr-cmp-tmpl-faq [class*='__cards'] > * { min-width: 0; max-width: 100%; }\n@media (max-width: 540px) {\n  .fmstr-cmp-tmpl-faq pre { overflow-x: auto; -webkit-overflow-scrolling: touch; }\n  .fmstr-cmp-tmpl-faq table { display: block; overflow-x: auto; -webkit-overflow-scrolling: touch; }\n}\n\u003C\u002Fstyle>\n\n\u003Csection class=\"fmstr-cmp-tmpl-faq\" aria-labelledby=\"fmstr-cmp-tmpl-faq-h2\">\n\u003Cdiv class=\"fmstr-cmp-tmpl-faq__container\">\n\u003Ch2 class=\"fmstr-cmp-tmpl-faq__h2\" id=\"fmstr-cmp-tmpl-faq-h2\">Frequently asked questions\u003C\u002Fh2>\n\u003Cp class=\"fmstr-cmp-tmpl-faq__intro\">Common questions about routing HTML form data into Google Sheets for free.\u003C\u002Fp>\n\u003Cdiv class=\"fmstr-cmp-tmpl-faq__list\">\n\n\u003Cdetails class=\"fmstr-cmp-tmpl-faq__item\">\n\u003Csummary>Is it really free to send HTML form data to Google Sheets?\u003C\u002Fsummary>\n\u003Cdiv class=\"fmstr-cmp-tmpl-faq__answer\">Yes. Google Apps Script is free with any Google account, with the rate limit of one Sheets write per second per user. Google Forms is free. Formester's free plan includes unlimited submissions. You only start paying when your volume crosses Google's API quota or a builder's free-plan cap.\u003C\u002Fdiv>\n\u003C\u002Fdetails>\n\n\u003Cdetails class=\"fmstr-cmp-tmpl-faq__item\">\n\u003Csummary>How secure is form data in Google Sheets?\u003C\u002Fsummary>\n\u003Cdiv class=\"fmstr-cmp-tmpl-faq__answer\">Google encrypts data at rest and in transit. The risk is in sharing and CSV injection, not the storage. Lock down sharing to specific accounts, do not share by link, neutralize formula characters on input (the script above does this), and never use a Sheet for payment data or passwords.\u003C\u002Fdiv>\n\u003C\u002Fdetails>\n\n\u003Cdetails class=\"fmstr-cmp-tmpl-faq__item\">\n\u003Csummary>What is the rate limit on Apps Script writes to Sheets?\u003C\u002Fsummary>\n\u003Cdiv class=\"fmstr-cmp-tmpl-faq__answer\">Roughly 100 requests per 100 seconds per user, per Google's published quotas. For a contact form that allows a sustained one submission per second, with bursts handled by retries.\u003C\u002Fdiv>\n\u003C\u002Fdetails>\n\n\u003Cdetails class=\"fmstr-cmp-tmpl-faq__item\">\n\u003Csummary>Can I send file uploads from the form into Google Sheets?\u003C\u002Fsummary>\n\u003Cdiv class=\"fmstr-cmp-tmpl-faq__answer\">Sheets cannot hold a file, but it can hold a link. With Apps Script, you can write the file to Google Drive and write the Drive URL into the cell. With a no-code builder, the \u003Ca href=\"https:\u002F\u002Fformester.com\u002Ffeatures\u002F\">file upload field in Formester\u003C\u002Fa> handles this and stores the file separately.\u003C\u002Fdiv>\n\u003C\u002Fdetails>\n\n\u003Cdetails class=\"fmstr-cmp-tmpl-faq__item\">\n\u003Csummary>How do I add CAPTCHA or spam protection?\u003C\u002Fsummary>\n\u003Cdiv class=\"fmstr-cmp-tmpl-faq__answer\">The script above includes a honeypot field. For more, add Google reCAPTCHA v3 on the client and verify the token server-side before writing to the Sheet. Builders ship CAPTCHA, rate limiting, and IP blocks as a toggle.\u003C\u002Fdiv>\n\u003C\u002Fdetails>\n\n\u003Cdetails class=\"fmstr-cmp-tmpl-faq__item\">\n\u003Csummary>How do I get an email when someone submits the form?\u003C\u002Fsummary>\n\u003Cdiv class=\"fmstr-cmp-tmpl-faq__answer\">Add \u003Ccode>MailApp.sendEmail({ to: 'you@example.com', subject: 'New form submission', body: JSON.stringify(e.parameter) })\u003C\u002Fcode> inside the \u003Ccode>doPost\u003C\u002Fcode> function in the script. Or use the \u003Ca href=\"https:\u002F\u002Fformester.com\u002Ffeatures\u002Fautoresponder-email\u002F\">autoresponder feature\u003C\u002Fa> in Formester and skip the code.\u003C\u002Fdiv>\n\u003C\u002Fdetails>\n\n\u003Cdetails class=\"fmstr-cmp-tmpl-faq__item\">\n\u003Csummary>Can I use this on Netlify, Vercel, or any static site?\u003C\u002Fsummary>\n\u003Cdiv class=\"fmstr-cmp-tmpl-faq__answer\">Yes. The Apps Script deployment URL is just a \u003Ccode>fetch\u003C\u002Fcode> target. It works from any frontend, hosted anywhere, with no backend on your side.\u003C\u002Fdiv>\n\u003C\u002Fdetails>\n\n\u003Cdetails class=\"fmstr-cmp-tmpl-faq__item\">\n\u003Csummary>Can I move from this setup to a database later?\u003C\u002Fsummary>\n\u003Cdiv class=\"fmstr-cmp-tmpl-faq__answer\">Easily. Sheets is a great starter store. When you cross a few hundred submissions a week, route the same form to a database or CRM in parallel with the Sheet. Most CRMs ship a Google Sheets sync, so you can keep the Sheet for the team and the CRM for the system of record.\u003C\u002Fdiv>\n\u003C\u002Fdetails>\n\n\u003C\u002Fdiv>\n\u003C\u002Fdiv>\n\u003C\u002Fsection>\n\n\n\u003Cstyle>\n\u002F* host-link-override *\u002F\n.fmstr-cmp-tmpl-rel a { text-decoration: none !important; }\n.fmstr-cmp-tmpl-rel {\n--c-card: #ffffff;\n--c-fg-1: #101828; --c-fg-2: #475467; --c-fg-3: #697586;\n--c-violet-500: #7f56d9; --c-violet-600: #6941c6;\n--c-tint: #f7f3ff; --c-edge: #e4d7ff;\n--c-border: #eaecf0;\n--c-shadow: 0 4px 20px rgba(16,24,40,.06);\n\nbackground: transparent;\npadding: 56px 24px;\nfont-family: inherit;\ncolor: var(--c-fg-1);\ntext-align: left !important; overflow-x: hidden; -webkit-text-size-adjust: 100%;}\n.fmstr-cmp-tmpl-rel *, .fmstr-cmp-tmpl-rel *::before, .fmstr-cmp-tmpl-rel *::after { box-sizing: border-box; }\n.fmstr-cmp-tmpl-rel__container { max-width: 1200px; margin: 0 auto; }\n.fmstr-cmp-tmpl-rel__head { margin: 0 0 28px !important; text-align: left; }\n.fmstr-cmp-tmpl-rel__h2 { font-size: clamp(26px, 3vw, 36px) !important; font-weight: 700 !important; line-height: 1.15 !important; letter-spacing: -.02em !important; margin: 0 !important; color: var(--c-fg-1); text-align: left; }\n.fmstr-cmp-tmpl-rel__intro { color: var(--c-fg-3); font-size: 17px !important; line-height: 1.6 !important; margin: 14px 0 0 !important; text-align: left; }\n\n.fmstr-cmp-tmpl-rel__grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }\n.fmstr-cmp-tmpl-rel__card {\nbackground: var(--c-card); border: 1px solid var(--c-border);\nborder-radius: 14px; padding: 20px 22px; display: flex; flex-direction: column; gap: 8px;\ntext-decoration: none !important; color: inherit !important; transition: all .15s ease;\nposition: relative;\n}\n.fmstr-cmp-tmpl-rel__card:hover { border-color: var(--c-edge); box-shadow: var(--c-shadow); transform: translateY(-1px); }\n.fmstr-cmp-tmpl-rel__chip {\ndisplay: inline-block; padding: 3px 10px; border-radius: 9999px;\nbackground: var(--c-tint); border: 1px solid var(--c-edge);\ncolor: var(--c-violet-600); font-size: 11.5px; font-weight: 600; letter-spacing: .02em;\ntext-transform: uppercase; align-self: flex-start;\nmargin-bottom: 2px;\n}\n.fmstr-cmp-tmpl-rel__title {\nfont-size: 16px !important; font-weight: 700 !important; color: var(--c-fg-1); margin: 0 !important; line-height: 1.3 !important; text-align: left; }\n.fmstr-cmp-tmpl-rel__body { font-size: 14.5px !important; line-height: 1.55 !important; color: var(--c-fg-2); margin: 0 !important; }\n.fmstr-cmp-tmpl-rel__arrow {\nmargin-top: 6px; color: var(--c-violet-600); font-size: 14px; font-weight: 600;\ndisplay: inline-flex; align-items: center; gap: 6px;\n}\n.fmstr-cmp-tmpl-rel__arrow::after {\ncontent: \"\\2192\"; transition: transform .15s ease; display: inline-block;\n}\n.fmstr-cmp-tmpl-rel__card:hover .fmstr-cmp-tmpl-rel__arrow::after { transform: translateX(3px); }\n\n@media (max-width: 880px) { .fmstr-cmp-tmpl-rel__grid { grid-template-columns: 1fr 1fr; gap: 14px; } }\n@media (max-width: 540px) {\n.fmstr-cmp-tmpl-rel { padding: 40px 16px; }\n.fmstr-cmp-tmpl-rel__grid { grid-template-columns: 1fr; gap: 12px; }\n.fmstr-cmp-tmpl-rel__card { padding: 18px 20px; }\n}\n\n\n\u002F* mobile-safety-v2 *\u002F\n.fmstr-cmp-tmpl-rel img, .fmstr-cmp-tmpl-rel table, .fmstr-cmp-tmpl-rel pre, .fmstr-cmp-tmpl-rel iframe, .fmstr-cmp-tmpl-rel video { max-width: 100%; }\n.fmstr-cmp-tmpl-rel > * { min-width: 0; }\n.fmstr-cmp-tmpl-rel [class*='__grid'] > *, .fmstr-cmp-tmpl-rel [class*='__list'] > *, .fmstr-cmp-tmpl-rel [class*='__cards'] > * { min-width: 0; max-width: 100%; }\n@media (max-width: 540px) {\n  .fmstr-cmp-tmpl-rel pre { overflow-x: auto; -webkit-overflow-scrolling: touch; }\n  .fmstr-cmp-tmpl-rel table { display: block; overflow-x: auto; -webkit-overflow-scrolling: touch; }\n}\n\u003C\u002Fstyle>\n\n\u003Csection class=\"fmstr-cmp-tmpl-rel\" aria-labelledby=\"fmstr-cmp-tmpl-rel-h2\">\n\u003Cdiv class=\"fmstr-cmp-tmpl-rel__container\">\n\u003Cdiv class=\"fmstr-cmp-tmpl-rel__head\">\n\u003Ch2 class=\"fmstr-cmp-tmpl-rel__h2\" id=\"fmstr-cmp-tmpl-rel-h2\">More on connecting forms to Google Sheets\u003C\u002Fh2>\n\u003Cp class=\"fmstr-cmp-tmpl-rel__intro\">More on connecting forms to Google Sheets, building APIs around them, and picking the right builder.\u003C\u002Fp>\n\u003C\u002Fdiv>\n\u003Cdiv class=\"fmstr-cmp-tmpl-rel__grid\">\n\n\u003Ca class=\"fmstr-cmp-tmpl-rel__card\" href=\"https:\u002F\u002Fformester.com\u002Fblog\u002Fbest-form-builders-compatible-with-google-sheets\u002F\">\n\u003Cspan class=\"fmstr-cmp-tmpl-rel__chip\">Listicle\u003C\u002Fspan>\n\u003Ch3 class=\"fmstr-cmp-tmpl-rel__title\">Best form builders compatible with Google Sheets\u003C\u002Fh3>\n\u003Cp class=\"fmstr-cmp-tmpl-rel__body\">Side-by-side on price, sync mode, and field mapping.\u003C\u002Fp>\n\u003Cspan class=\"fmstr-cmp-tmpl-rel__arrow\">Read\u003C\u002Fspan>\n\u003C\u002Fa>\n\n\u003Ca class=\"fmstr-cmp-tmpl-rel__card\" href=\"https:\u002F\u002Fformester.com\u002Fblog\u002Fhow-to-link-google-sheets-to-google-forms\u002F\">\n\u003Cspan class=\"fmstr-cmp-tmpl-rel__chip\">How-to\u003C\u002Fspan>\n\u003Ch3 class=\"fmstr-cmp-tmpl-rel__title\">How to link Google Sheets to Google Forms\u003C\u002Fh3>\n\u003Cp class=\"fmstr-cmp-tmpl-rel__body\">The 2-minute setup for the Google Forms route.\u003C\u002Fp>\n\u003Cspan class=\"fmstr-cmp-tmpl-rel__arrow\">Read\u003C\u002Fspan>\n\u003C\u002Fa>\n\n\u003Ca class=\"fmstr-cmp-tmpl-rel__card\" href=\"https:\u002F\u002Fformester.com\u002Fblog\u002Fhow-to-pre-fill-forms-using-google-sheets-and-formester\u002F\">\n\u003Cspan class=\"fmstr-cmp-tmpl-rel__chip\">How-to\u003C\u002Fspan>\n\u003Ch3 class=\"fmstr-cmp-tmpl-rel__title\">Pre-fill forms using Google Sheets and Formester\u003C\u002Fh3>\n\u003Cp class=\"fmstr-cmp-tmpl-rel__body\">Reverse the flow: pull Sheet data into a form before it loads.\u003C\u002Fp>\n\u003Cspan class=\"fmstr-cmp-tmpl-rel__arrow\">Read\u003C\u002Fspan>\n\u003C\u002Fa>\n\n\u003Ca class=\"fmstr-cmp-tmpl-rel__card\" href=\"https:\u002F\u002Fformester.com\u002Fblog\u002Fhow-to-link-squarespace-forms-to-google-sheets\u002F\">\n\u003Cspan class=\"fmstr-cmp-tmpl-rel__chip\">How-to\u003C\u002Fspan>\n\u003Ch3 class=\"fmstr-cmp-tmpl-rel__title\">How to link Squarespace forms to Google Sheets\u003C\u002Fh3>\n\u003Cp class=\"fmstr-cmp-tmpl-rel__body\">Same idea, scoped to a Squarespace site.\u003C\u002Fp>\n\u003Cspan class=\"fmstr-cmp-tmpl-rel__arrow\">Read\u003C\u002Fspan>\n\u003C\u002Fa>\n\n\u003Ca class=\"fmstr-cmp-tmpl-rel__card\" href=\"https:\u002F\u002Fformester.com\u002Fintegrations\u002F\">\n\u003Cspan class=\"fmstr-cmp-tmpl-rel__chip\">Formester\u003C\u002Fspan>\n\u003Ch3 class=\"fmstr-cmp-tmpl-rel__title\">Google Sheets integration\u003C\u002Fh3>\n\u003Cp class=\"fmstr-cmp-tmpl-rel__body\">Native sync with OAuth, header mapping, and retries handled.\u003C\u002Fp>\n\u003Cspan class=\"fmstr-cmp-tmpl-rel__arrow\">Open\u003C\u002Fspan>\n\u003C\u002Fa>\n\n\u003C\u002Fdiv>\n\u003C\u002Fdiv>\n\u003C\u002Fsection>\n\n\n","blog\u002Fblog\u002Fhow-to-send-contact-form-data-to-google-sheets-free.md",{"text":187},{"title":283,"author":32,"authorImage":8,"authorProfile":201,"coverImg":284,"coverImgAlt":285,"createdAt":286,"description":287,"featured":14,"jsonld":288,"keywords":289,"metaDescription":290,"metaImage":291,"metaTitle":292,"publishedAt":293,"slug":294,"updatedAt":295,"__hash__":296,"body":297,"id":298,"coverImgWidth":25,"coverImgHeight":26,"readingStats":299},"How to Make a Feedback Form in HTML (with Code, CSS, and a Backend)","https:\u002F\u002Fformester-strapi.s3.ap-south-1.amazonaws.com\u002Fan_illustration_of_how_to_make_feedback_form_in_html_c6203dc935.png","an illustration of how to make feedback form in html","2024-06-27T06:19:40.031Z","Learn how to create a feedback form in HTML with easy steps. Set up an HTML document, add form fields, style with CSS, and add JavaScript for validation. Test your form and start collecting feedback.",[],"feedback forms, fillable freedback form, how to make feedback form in html, style feedback form with css, feedback form html code","Build a working feedback form in HTML with copy-paste code, CSS styling, JavaScript validation, accessibility, and a backend that stores submissions without a server.",[],"How to Make a Feedback Form in HTML (Code, CSS, Validation, Backend)","2026-05-17T04:46:01.940Z","how-to-make-feedback-form-in-html","2026-05-17T04:46:01.948Z","wyyctYTKwdEs6QGo1-xhuZdxYoLFow0lRYEcN7glo1g","![an illustration of how to make feedback form in html](https:\u002F\u002Fformester-strapi.s3.ap-south-1.amazonaws.com\u002Fan_illustration_of_how_to_make_feedback_form_in_html_c6203dc935.png)\n\n\u003Cstyle>\n\u002F* host-link-override *\u002F\n.fmstr-cmp-ffh-body a { text-decoration: none !important; }\n.fmstr-cmp-ffh-body {\n--c-bg-card: #ffffff;\n--c-bg-soft: #f9fafb;\n--c-fg-1: #101828; --c-fg-2: #475467; --c-fg-3: #697586;\n--c-violet-500: #7f56d9; --c-violet-600: #6941c6;\n--c-tint: #f7f3ff; --c-edge: #e4d7ff; --c-border: #eaecf0;\n--c-code-bg: #0f172a; --c-code-fg: #e2e8f0;\n--c-code-keyword: #a78bfa; --c-code-attr: #67e8f9; --c-code-string: #fcd34d; --c-code-comment: #64748b;\n--c-warn-bg: #fef3c7; --c-warn-fg: #92400e; --c-warn-edge: #fde68a;\n\nbackground: transparent; padding: 24px;\nfont-family: inherit;\ncolor: var(--c-fg-1);\n}\n.fmstr-cmp-ffh-body *, .fmstr-cmp-ffh-body *::before, .fmstr-cmp-ffh-body *::after { box-sizing: border-box; }\n.fmstr-cmp-ffh-body__container { max-width: 820px; margin: 0 auto; }\n\n.fmstr-cmp-ffh-body__intro p { font-size: 17px; line-height: 1.7; color: var(--c-fg-2); margin: 0 0 16px; }\n.fmstr-cmp-ffh-body__intro a { color: var(--c-violet-600) !important; text-decoration: none !important; font-weight: 500; }\n.fmstr-cmp-ffh-body__intro a:hover { text-decoration: underline !important; }\n.fmstr-cmp-ffh-body__intro code { background: var(--c-tint); color: var(--c-violet-600); padding: 2px 6px; border-radius: 4px; font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 14.5px; border: 1px solid var(--c-edge); }\n\n.fmstr-cmp-ffh-body__h2 {\nfont-size: 28px; font-weight: 700; line-height: 1.25; letter-spacing: -.02em;\nmargin: 40px 0 16px; color: var(--c-fg-1);\n}\n.fmstr-cmp-ffh-body__h3 {\nfont-size: 20px; font-weight: 700; line-height: 1.35; letter-spacing: -.01em;\nmargin: 28px 0 12px; color: var(--c-fg-1);\n}\n.fmstr-cmp-ffh-body p { font-size: 16px; line-height: 1.7; color: var(--c-fg-2); margin: 0 0 14px; }\n.fmstr-cmp-ffh-body p strong { color: var(--c-fg-1); }\n.fmstr-cmp-ffh-body a { color: var(--c-violet-600) !important; text-decoration: none !important; font-weight: 500; }\n.fmstr-cmp-ffh-body a:hover { text-decoration: underline !important; }\n.fmstr-cmp-ffh-body ul, .fmstr-cmp-ffh-body ol { margin: 0 0 16px; padding-left: 22px; }\n.fmstr-cmp-ffh-body li { font-size: 16px; line-height: 1.7; color: var(--c-fg-2); margin: 6px 0; }\n.fmstr-cmp-ffh-body li strong { color: var(--c-fg-1); }\n.fmstr-cmp-ffh-body code { background: var(--c-tint); color: var(--c-violet-600); padding: 2px 6px; border-radius: 4px; font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 14.5px; border: 1px solid var(--c-edge); }\n\n.fmstr-cmp-ffh-body__code {\nbackground: var(--c-code-bg); color: var(--c-code-fg);\nborder-radius: 12px; padding: 18px 20px; margin: 8px 0 18px;\noverflow-x: auto;\nfont-family: ui-monospace, Menlo, Consolas, monospace; font-size: 13.5px; line-height: 1.6;\n}\n.fmstr-cmp-ffh-body__code pre { margin: 0; }\n.fmstr-cmp-ffh-body__code code {\nbackground: transparent !important; color: inherit !important; padding: 0; border: 0;\nfont-family: inherit !important; font-size: inherit;\n}\n.fmstr-cmp-ffh-body__code .kw { color: var(--c-code-keyword); }\n.fmstr-cmp-ffh-body__code .at { color: var(--c-code-attr); }\n.fmstr-cmp-ffh-body__code .st { color: var(--c-code-string); }\n.fmstr-cmp-ffh-body__code .cm { color: var(--c-code-comment); font-style: italic; }\n.fmstr-cmp-ffh-body__code .lang { display: inline-block; font-size: 11px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; padding: 3px 10px; border-radius: 6px; background: rgba(255,255,255,.1); color: rgba(255,255,255,.7); margin: 0 0 12px; }\n\n.fmstr-cmp-ffh-body__note {\nmargin: 14px 0 18px; padding: 14px 18px;\nbackground: var(--c-bg-soft); border-left: 3px solid var(--c-violet-500);\nborder-radius: 8px; font-size: 15.5px; color: var(--c-fg-2); line-height: 1.6;\n}\n.fmstr-cmp-ffh-body__note strong { color: var(--c-fg-1); }\n.fmstr-cmp-ffh-body__note--warn { background: var(--c-warn-bg); border-left-color: var(--c-warn-fg); }\n.fmstr-cmp-ffh-body__note--warn strong { color: var(--c-warn-fg); }\n\n.fmstr-cmp-ffh-body__variants {\ndisplay: grid; grid-template-columns: 1fr; gap: 14px; margin: 12px 0 24px;\n}\n.fmstr-cmp-ffh-body__variant {\nbackground: var(--c-bg-card); border: 1px solid var(--c-border); border-radius: 14px;\npadding: 18px 22px;\n}\n.fmstr-cmp-ffh-body__variant h4 {\nfont-size: 16px; font-weight: 700; color: var(--c-fg-1);\nmargin: 0 0 8px; line-height: 1.35;\n}\n.fmstr-cmp-ffh-body__variant p { font-size: 15px; line-height: 1.65; color: var(--c-fg-2); margin: 0; }\n\n@media (max-width: 760px) {\n.fmstr-cmp-ffh-body { padding: 16px; }\n.fmstr-cmp-ffh-body__intro p, .fmstr-cmp-ffh-body p, .fmstr-cmp-ffh-body li { font-size: 15.5px; }\n.fmstr-cmp-ffh-body__h2 { font-size: 24px; margin-top: 32px; }\n.fmstr-cmp-ffh-body__h3 { font-size: 18.5px; }\n.fmstr-cmp-ffh-body__code { padding: 14px 16px; font-size: 12.5px; border-radius: 10px; }\n.fmstr-cmp-ffh-body__variant { padding: 16px 18px; }\n}\n\u003C\u002Fstyle>\n\n\u003Csection class=\"fmstr-cmp-ffh-body\" aria-label=\"How to make a feedback form in HTML\">\n\u003Cdiv class=\"fmstr-cmp-ffh-body__container\">\n\n\u003Cdiv class=\"fmstr-cmp-ffh-body__intro\">\n\u003Cp>A feedback form in HTML is twenty lines of markup, a bit of CSS, and one decision that trips up almost everyone: what happens after the user clicks Submit?\u003C\u002Fp>\n\u003Cp>This guide ships the full pattern. You'll get a working \u003Ccode>&lt;form&gt;\u003C\u002Fcode> with name, email, and message fields, CSS that styles it without a framework, JavaScript validation that doesn't break keyboard users, and three honest options for the backend, including one that needs zero server code. Paste the snippets in order, swap the action URL, and you have a live feedback form on your site in about ten minutes.\u003C\u002Fp>\n\u003Cp>If you want to skip the code entirely, \u003Ca href=\"https:\u002F\u002Fformester.com\u002Ffeatures\u002Fdrag-and-drop-form-builder\u002F\">Formester's drag-and-drop builder\u003C\u002Fa> ships a feedback form you can \u003Ca href=\"https:\u002F\u002Fformester.com\u002Ffeatures\u002Fembed-forms\u002F\">embed in any HTML page\u003C\u002Fa> with one snippet. Keep reading for the hand-coded path.\u003C\u002Fp>\n\u003C\u002Fdiv>\n\n\u003Ch2 class=\"fmstr-cmp-ffh-body__h2\">What a feedback form in HTML actually needs\u003C\u002Fh2>\n\u003Cp>Four pieces, in order:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Cstrong>A \u003Ccode>&lt;form&gt;\u003C\u002Fcode> element\u003C\u002Fstrong> with the right \u003Ccode>action\u003C\u002Fcode> and \u003Ccode>method\u003C\u002Fcode> so the browser knows where to send data.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Labeled inputs\u003C\u002Fstrong> for the fields you care about (name, email, rating, message), with \u003Ccode>name\u003C\u002Fcode> attributes so the server can read them.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Validation\u003C\u002Fstrong> on the client (for user experience) and on the server (for trust).\u003C\u002Fli>\n\u003Cli>\u003Cstrong>A backend\u003C\u002Fstrong> that receives the submission, stores it, and ideally notifies you. This is the part most tutorials skip; it's the part you need most.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>Below, each piece is a separate step with a copy-paste block. The last step is a single complete file you can save as \u003Ccode>feedback.html\u003C\u002Fcode> and open in a browser.\u003C\u002Fp>\n\n\u003Ch2 class=\"fmstr-cmp-ffh-body__h2\">Step 1: Set up the HTML document\u003C\u002Fh2>\n\u003Cp>Save this as \u003Ccode>feedback.html\u003C\u002Fcode>. It's the shell every form goes inside.\u003C\u002Fp>\n\u003Cdiv class=\"fmstr-cmp-ffh-body__code\">\u003Cspan class=\"lang\">HTML\u003C\u002Fspan>\n\u003Cpre>\u003Ccode>&lt;!DOCTYPE html&gt;\n&lt;html lang=\"en\"&gt;\n&lt;head&gt;\n&#160;&#160;&lt;meta charset=\"UTF-8\"&gt;\n&#160;&#160;&lt;meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"&gt;\n&#160;&#160;&lt;title&gt;Feedback Form&lt;\u002Ftitle&gt;\n&lt;\u002Fhead&gt;\n&lt;body&gt;\n&#160;&#160;&lt;h1&gt;Tell us what you think&lt;\u002Fh1&gt;\n&#160;&#160;&lt;!-- form goes here --&gt;\n&lt;\u002Fbody&gt;\n&lt;\u002Fhtml&gt;\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C\u002Fdiv>\n\u003Cp>Two small things that matter later: \u003Ccode>lang=\"en\"\u003C\u002Fcode> helps screen readers pick the right voice, and the viewport meta tag makes the form usable on phones.\u003C\u002Fp>\n\n\u003Ch2 class=\"fmstr-cmp-ffh-body__h2\">Step 2: Add the form fields\u003C\u002Fh2>\n\u003Cp>Paste this inside \u003Ccode>&lt;body&gt;\u003C\u002Fcode>, where the comment says \"form goes here\":\u003C\u002Fp>\n\u003Cdiv class=\"fmstr-cmp-ffh-body__code\">\u003Cspan class=\"lang\">HTML\u003C\u002Fspan>\n\u003Cpre>\u003Ccode>&lt;form id=\"feedback-form\" action=\"\u002Fsubmit-feedback\" method=\"post\" novalidate&gt;\n&#160;&#160;&lt;div class=\"field\"&gt;\n&#160;&#160;&#160;&#160;&lt;label for=\"name\"&gt;Name&lt;\u002Flabel&gt;\n&#160;&#160;&#160;&#160;&lt;input type=\"text\" id=\"name\" name=\"name\" autocomplete=\"name\" required&gt;\n&#160;&#160;&lt;\u002Fdiv&gt;\n\n&#160;&#160;&lt;div class=\"field\"&gt;\n&#160;&#160;&#160;&#160;&lt;label for=\"email\"&gt;Email&lt;\u002Flabel&gt;\n&#160;&#160;&#160;&#160;&lt;input type=\"email\" id=\"email\" name=\"email\" autocomplete=\"email\" required&gt;\n&#160;&#160;&lt;\u002Fdiv&gt;\n\n&#160;&#160;&lt;div class=\"field\"&gt;\n&#160;&#160;&#160;&#160;&lt;label for=\"rating\"&gt;How was your experience?&lt;\u002Flabel&gt;\n&#160;&#160;&#160;&#160;&lt;select id=\"rating\" name=\"rating\" required&gt;\n&#160;&#160;&#160;&#160;&#160;&#160;&lt;option value=\"\"&gt;Pick one&lt;\u002Foption&gt;\n&#160;&#160;&#160;&#160;&#160;&#160;&lt;option value=\"5\"&gt;Loved it&lt;\u002Foption&gt;\n&#160;&#160;&#160;&#160;&#160;&#160;&lt;option value=\"4\"&gt;Good&lt;\u002Foption&gt;\n&#160;&#160;&#160;&#160;&#160;&#160;&lt;option value=\"3\"&gt;Okay&lt;\u002Foption&gt;\n&#160;&#160;&#160;&#160;&#160;&#160;&lt;option value=\"2\"&gt;Not great&lt;\u002Foption&gt;\n&#160;&#160;&#160;&#160;&#160;&#160;&lt;option value=\"1\"&gt;Bad&lt;\u002Foption&gt;\n&#160;&#160;&#160;&#160;&lt;\u002Fselect&gt;\n&#160;&#160;&lt;\u002Fdiv&gt;\n\n&#160;&#160;&lt;div class=\"field\"&gt;\n&#160;&#160;&#160;&#160;&lt;label for=\"message\"&gt;Your feedback&lt;\u002Flabel&gt;\n&#160;&#160;&#160;&#160;&lt;textarea id=\"message\" name=\"message\" rows=\"5\" required&gt;&lt;\u002Ftextarea&gt;\n&#160;&#160;&lt;\u002Fdiv&gt;\n\n&#160;&#160;&lt;button type=\"submit\"&gt;Send feedback&lt;\u002Fbutton&gt;\n&lt;\u002Fform&gt;\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C\u002Fdiv>\n\u003Cp>Three details that beginners miss:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Cstrong>Every input has a matching \u003Ccode>&lt;label for&gt;\u003C\u002Fcode>.\u003C\u002Fstrong> Click the label, the input focuses. Screen readers read the label out loud. Skip this and the form fails accessibility and loses keyboard users.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>\u003Ccode>name\u003C\u002Fcode> attributes are not cosmetic.\u003C\u002Fstrong> The server reads submissions by \u003Ccode>name\u003C\u002Fcode>, so \u003Ccode>name=\"email\"\u003C\u002Fcode> is what makes the email value reach your inbox. Missing \u003Ccode>name\u003C\u002Fcode> = silent data loss.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>\u003Ccode>autocomplete=\"name\"\u003C\u002Fcode> and \u003Ccode>autocomplete=\"email\"\u003C\u002Fcode>\u003C\u002Fstrong> let browsers pre-fill from saved info. One line, measurable bump in completion.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cdiv class=\"fmstr-cmp-ffh-body__note\">\u003Cstrong>Note:\u003C\u002Fstrong> \u003Ccode>novalidate\u003C\u002Fcode> on the form tag turns off the browser's default error bubbles so you can show your own (covered in Step 4). Drop it if you want native validation only.\u003C\u002Fdiv>\n\n\u003Ch2 class=\"fmstr-cmp-ffh-body__h2\">Step 3: Style it with CSS\u003C\u002Fh2>\n\u003Cp>Paste this inside \u003Ccode>&lt;head&gt;\u003C\u002Fcode> between \u003Ccode>&lt;title&gt;\u003C\u002Fcode> and the closing \u003Ccode>&lt;\u002Fhead&gt;\u003C\u002Fcode>:\u003C\u002Fp>\n\u003Cdiv class=\"fmstr-cmp-ffh-body__code\">\u003Cspan class=\"lang\">CSS\u003C\u002Fspan>\n\u003Cpre>\u003Ccode>&lt;style&gt;\n&#160;&#160;body {\n&#160;&#160;&#160;&#160;font-family: system-ui, -apple-system, \"Segoe UI\", Roboto, sans-serif;\n&#160;&#160;&#160;&#160;background: #f7f7f9;\n&#160;&#160;&#160;&#160;margin: 0;\n&#160;&#160;&#160;&#160;padding: 40px 16px;\n&#160;&#160;&#160;&#160;color: #1a1a1a;\n&#160;&#160;}\n&#160;&#160;h1 { font-size: 1.5rem; margin: 0 0 24px; text-align: center; }\n&#160;&#160;form {\n&#160;&#160;&#160;&#160;max-width: 480px;\n&#160;&#160;&#160;&#160;margin: 0 auto;\n&#160;&#160;&#160;&#160;background: #fff;\n&#160;&#160;&#160;&#160;padding: 24px;\n&#160;&#160;&#160;&#160;border-radius: 12px;\n&#160;&#160;&#160;&#160;box-shadow: 0 2px 12px rgba(0,0,0,0.06);\n&#160;&#160;}\n&#160;&#160;.field { margin-bottom: 16px; }\n&#160;&#160;label {\n&#160;&#160;&#160;&#160;display: block;\n&#160;&#160;&#160;&#160;font-weight: 600;\n&#160;&#160;&#160;&#160;font-size: 0.9rem;\n&#160;&#160;&#160;&#160;margin-bottom: 6px;\n&#160;&#160;}\n&#160;&#160;input, select, textarea {\n&#160;&#160;&#160;&#160;width: 100%;\n&#160;&#160;&#160;&#160;box-sizing: border-box;\n&#160;&#160;&#160;&#160;padding: 10px 12px;\n&#160;&#160;&#160;&#160;font: inherit;\n&#160;&#160;&#160;&#160;border: 1px solid #d0d0d6;\n&#160;&#160;&#160;&#160;border-radius: 8px;\n&#160;&#160;&#160;&#160;background: #fff;\n&#160;&#160;}\n&#160;&#160;input:focus, select:focus, textarea:focus {\n&#160;&#160;&#160;&#160;outline: 2px solid #5b6cff;\n&#160;&#160;&#160;&#160;outline-offset: 1px;\n&#160;&#160;&#160;&#160;border-color: #5b6cff;\n&#160;&#160;}\n&#160;&#160;input[aria-invalid=\"true\"],\n&#160;&#160;select[aria-invalid=\"true\"],\n&#160;&#160;textarea[aria-invalid=\"true\"] {\n&#160;&#160;&#160;&#160;border-color: #d33;\n&#160;&#160;}\n&#160;&#160;.error {\n&#160;&#160;&#160;&#160;display: block;\n&#160;&#160;&#160;&#160;color: #d33;\n&#160;&#160;&#160;&#160;font-size: 0.8rem;\n&#160;&#160;&#160;&#160;margin-top: 4px;\n&#160;&#160;&#160;&#160;min-height: 1em;\n&#160;&#160;}\n&#160;&#160;button {\n&#160;&#160;&#160;&#160;width: 100%;\n&#160;&#160;&#160;&#160;padding: 12px;\n&#160;&#160;&#160;&#160;background: #5b6cff;\n&#160;&#160;&#160;&#160;color: #fff;\n&#160;&#160;&#160;&#160;font-weight: 600;\n&#160;&#160;&#160;&#160;border: none;\n&#160;&#160;&#160;&#160;border-radius: 8px;\n&#160;&#160;&#160;&#160;cursor: pointer;\n&#160;&#160;}\n&#160;&#160;button:hover { background: #4a59e0; }\n&lt;\u002Fstyle&gt;\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C\u002Fdiv>\n\u003Cp>Two things this stylesheet does that the typical tutorial skips:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>Keeps the focus outline visible. Default focus styles are ugly, so most tutorials remove them. Removing them breaks keyboard users. Replace, don't remove.\u003C\u002Fli>\n\u003Cli>Uses \u003Ccode>system-ui\u003C\u002Fcode> for fonts, so the form inherits the host site's native typography on macOS, Windows, iOS, and Android without shipping a font file.\u003C\u002Fli>\n\u003C\u002Ful>\n\n\u003Ch2 class=\"fmstr-cmp-ffh-body__h2\">Step 4: Add accessible JavaScript validation\u003C\u002Fh2>\n\u003Cp>The alert-on-submit pattern works but it's the worst possible UX. This version shows inline errors, marks invalid fields for screen readers with \u003Ccode>aria-invalid\u003C\u002Fcode>, and keeps focus where the user can fix the problem.\u003C\u002Fp>\n\u003Cp>Paste this right before \u003Ccode>&lt;\u002Fbody&gt;\u003C\u002Fcode>:\u003C\u002Fp>\n\u003Cdiv class=\"fmstr-cmp-ffh-body__code\">\u003Cspan class=\"lang\">JavaScript\u003C\u002Fspan>\n\u003Cpre>\u003Ccode>&lt;script&gt;\n&#160;&#160;const form = document.getElementById('feedback-form');\n\n&#160;&#160;function setError(input, message) {\n&#160;&#160;&#160;&#160;input.setAttribute('aria-invalid', 'true');\n&#160;&#160;&#160;&#160;let errorEl = input.parentElement.querySelector('.error');\n&#160;&#160;&#160;&#160;if (!errorEl) {\n&#160;&#160;&#160;&#160;&#160;&#160;errorEl = document.createElement('span');\n&#160;&#160;&#160;&#160;&#160;&#160;errorEl.className = 'error';\n&#160;&#160;&#160;&#160;&#160;&#160;errorEl.id = input.id + '-error';\n&#160;&#160;&#160;&#160;&#160;&#160;input.parentElement.appendChild(errorEl);\n&#160;&#160;&#160;&#160;}\n&#160;&#160;&#160;&#160;errorEl.textContent = message;\n&#160;&#160;&#160;&#160;input.setAttribute('aria-describedby', errorEl.id);\n&#160;&#160;}\n\n&#160;&#160;function clearError(input) {\n&#160;&#160;&#160;&#160;input.setAttribute('aria-invalid', 'false');\n&#160;&#160;&#160;&#160;const errorEl = input.parentElement.querySelector('.error');\n&#160;&#160;&#160;&#160;if (errorEl) errorEl.textContent = '';\n&#160;&#160;}\n\n&#160;&#160;form.addEventListener('submit', function (event) {\n&#160;&#160;&#160;&#160;let firstInvalid = null;\n\n&#160;&#160;&#160;&#160;[...form.querySelectorAll('input, select, textarea')].forEach((input) =&gt; {\n&#160;&#160;&#160;&#160;&#160;&#160;clearError(input);\n&#160;&#160;&#160;&#160;&#160;&#160;if (!input.value.trim()) {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;setError(input, 'This field is required.');\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;firstInvalid = firstInvalid || input;\n&#160;&#160;&#160;&#160;&#160;&#160;} else if (input.type === 'email' &amp;&amp; !\u002F^\\S+@\\S+\\.\\S+$\u002F.test(input.value)) {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;setError(input, 'Enter a valid email address.');\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;firstInvalid = firstInvalid || input;\n&#160;&#160;&#160;&#160;&#160;&#160;}\n&#160;&#160;&#160;&#160;});\n\n&#160;&#160;&#160;&#160;if (firstInvalid) {\n&#160;&#160;&#160;&#160;&#160;&#160;event.preventDefault();\n&#160;&#160;&#160;&#160;&#160;&#160;firstInvalid.focus();\n&#160;&#160;&#160;&#160;}\n&#160;&#160;});\n&lt;\u002Fscript&gt;\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C\u002Fdiv>\n\u003Cp>What this does that the original snippet missed:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>Sets \u003Ccode>aria-invalid=\"true\"\u003C\u002Fcode> and \u003Ccode>aria-describedby\u003C\u002Fcode> so screen readers announce the error.\u003C\u002Fli>\n\u003Cli>Inserts the error message next to the field, not in a modal.\u003C\u002Fli>\n\u003Cli>Focuses the first invalid field on failed submit, so a keyboard user lands exactly where they need to fix.\u003C\u002Fli>\n\u003Cli>Doesn't trust the email regex to be perfect (it isn't); always re-validate on the server.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cdiv class=\"fmstr-cmp-ffh-body__note\">\u003Cstrong>Rule of thumb:\u003C\u002Fstrong> client-side validation is for UX. Server-side validation is for trust. Do both.\u003C\u002Fdiv>\n\n\u003Ch2 class=\"fmstr-cmp-ffh-body__h2\">Step 5: Test the form locally\u003C\u002Fh2>\n\u003Cp>Open \u003Ccode>feedback.html\u003C\u002Fcode> in a browser. Run this checklist:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>Tab through every field with the keyboard. Focus should be visible at every stop.\u003C\u002Fli>\n\u003Cli>Try to submit empty. You should see inline error messages, focus should jump to the first empty field.\u003C\u002Fli>\n\u003Cli>Type a malformed email. You should see \"Enter a valid email address.\"\u003C\u002Fli>\n\u003Cli>Open the browser's network tab, submit a valid form. You should see a POST to \u003Ccode>\u002Fsubmit-feedback\u003C\u002Fcode>. That request will currently 404 because you don't have a backend yet. Step 6 fixes that.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>If you want to skip the backend setup entirely, the next step shows the \u003Ca href=\"https:\u002F\u002Fformester.com\u002Ffeatures\u002Fhtml-form-backend\u002F\">Formester HTML form backend\u003C\u002Fa> path: change one \u003Ccode>action\u003C\u002Fcode> attribute and your form starts collecting submissions.\u003C\u002Fp>\n\n\u003Ch2 class=\"fmstr-cmp-ffh-body__h2\" id=\"step-6-backend\">Step 6: Wire up a backend that stores submissions\u003C\u002Fh2>\n\u003Cp>A feedback form without a backend is a dead form. The browser POSTs the data, the server returns 404, the user sees an error page, the feedback is gone. You have three real options, compared side-by-side below.\u003C\u002Fp>\n\n\u003C\u002Fdiv>\n\u003C\u002Fsection>\n\n\u003Cstyle>\n\u002F* host-link-override *\u002F\n.fmstr-cmp-ffh-back a { text-decoration: none !important; }\n.fmstr-cmp-ffh-back {\n--fmstr-cmp-ffh-back-bg-card: #ffffff;\n--fmstr-cmp-ffh-back-bg-code: #0f172a;\n--fmstr-cmp-ffh-back-fg-1: #101828;\n--fmstr-cmp-ffh-back-fg-2: #475467;\n--fmstr-cmp-ffh-back-fg-3: #697586;\n--fmstr-cmp-ffh-back-violet-500: #7f56d9;\n--fmstr-cmp-ffh-back-violet-600: #6941c6;\n--fmstr-cmp-ffh-back-tint: #f7f3ff;\n--fmstr-cmp-ffh-back-edge: #e4d7ff;\n--fmstr-cmp-ffh-back-border: #eaecf0;\n--fmstr-cmp-ffh-back-red: #dc2626;\n--fmstr-cmp-ffh-back-red-bg: #fef2f2;\n--fmstr-cmp-ffh-back-red-edge: #fecaca;\n--fmstr-cmp-ffh-back-amber: #d97706;\n--fmstr-cmp-ffh-back-amber-bg: #fffbeb;\n--fmstr-cmp-ffh-back-amber-edge: #fde68a;\n--fmstr-cmp-ffh-back-green: #15803d;\n--fmstr-cmp-ffh-back-green-bg: #f0fdf4;\n--fmstr-cmp-ffh-back-green-edge: #bbf7d0;\n--fmstr-cmp-ffh-back-code-fg: #e2e8f0;\n--fmstr-cmp-ffh-back-shadow: 0 4px 20px rgba(16,24,40,.06), 0 2px 6px rgba(16,24,40,.04);\n\nbackground: transparent; padding: 56px 24px;\nfont-family: inherit; color: var(--fmstr-cmp-ffh-back-fg-1);\n}\n.fmstr-cmp-ffh-back *, .fmstr-cmp-ffh-back *::before, .fmstr-cmp-ffh-back *::after { box-sizing: border-box; }\n.fmstr-cmp-ffh-back__container { max-width: 820px; margin: 0 auto; }\n.fmstr-cmp-ffh-back__head { margin: 0 0 28px; }\n.fmstr-cmp-ffh-back__eyebrow {\ndisplay: inline-block; padding: 5px 12px; border-radius: 9999px;\nbackground: var(--fmstr-cmp-ffh-back-tint); color: var(--fmstr-cmp-ffh-back-violet-600);\nfont-size: 12px; font-weight: 600; letter-spacing: .04em;\ntext-transform: uppercase; border: 1px solid var(--fmstr-cmp-ffh-back-edge); margin: 0 0 14px;\n}\n.fmstr-cmp-ffh-back__h2 { font-size: clamp(26px, 3vw, 36px); font-weight: 700; line-height: 1.15; letter-spacing: -.02em; margin: 0; }\n.fmstr-cmp-ffh-back__intro { color: var(--fmstr-cmp-ffh-back-fg-3); font-size: 17px; line-height: 1.6; margin: 14px 0 0; }\n\n.fmstr-cmp-ffh-back__grid { display: grid; grid-template-columns: 1fr; gap: 16px; }\n.fmstr-cmp-ffh-back__card {\nbackground: var(--fmstr-cmp-ffh-back-bg-card);\nborder: 1px solid var(--fmstr-cmp-ffh-back-border);\nborder-radius: 18px; padding: 24px 26px; display: flex; flex-direction: column; gap: 16px;\nbox-shadow: var(--fmstr-cmp-ffh-back-shadow); position: relative;\n}\n.fmstr-cmp-ffh-back__card--red { border-top: 4px solid var(--fmstr-cmp-ffh-back-red); }\n.fmstr-cmp-ffh-back__card--amber { border-top: 4px solid var(--fmstr-cmp-ffh-back-amber); }\n.fmstr-cmp-ffh-back__card--green { border-top: 4px solid var(--fmstr-cmp-ffh-back-violet-500); background: linear-gradient(180deg, #fdfbff 0%, #fff 60%); }\n\n.fmstr-cmp-ffh-back__verdict {\ndisplay: inline-flex; align-items: center; gap: 8px; align-self: flex-start;\npadding: 5px 12px; border-radius: 9999px; font-size: 11.5px; font-weight: 700;\nletter-spacing: .04em; text-transform: uppercase;\n}\n.fmstr-cmp-ffh-back__verdict--red { background: var(--fmstr-cmp-ffh-back-red-bg); color: var(--fmstr-cmp-ffh-back-red); border: 1px solid var(--fmstr-cmp-ffh-back-red-edge); }\n.fmstr-cmp-ffh-back__verdict--amber { background: var(--fmstr-cmp-ffh-back-amber-bg); color: var(--fmstr-cmp-ffh-back-amber); border: 1px solid var(--fmstr-cmp-ffh-back-amber-edge); }\n.fmstr-cmp-ffh-back__verdict--green { background: var(--fmstr-cmp-ffh-back-tint); color: var(--fmstr-cmp-ffh-back-violet-600); border: 1px solid var(--fmstr-cmp-ffh-back-edge); }\n\n.fmstr-cmp-ffh-back__name { font-size: 19px; font-weight: 700; margin: 0; letter-spacing: -.01em; color: var(--fmstr-cmp-ffh-back-fg-1); }\n.fmstr-cmp-ffh-back__sub { font-size: 13.5px; color: var(--fmstr-cmp-ffh-back-fg-3); margin: -8px 0 0; line-height: 1.5; }\n\n.fmstr-cmp-ffh-back__code {\nbackground: var(--fmstr-cmp-ffh-back-bg-code);\nborder-radius: 10px; padding: 14px 16px;\nfont-family: ui-monospace, Menlo, Monaco, monospace;\nfont-size: 12px; line-height: 1.55;\ncolor: var(--fmstr-cmp-ffh-back-code-fg);\noverflow-x: auto; margin: 0; white-space: pre;\n}\n.fmstr-cmp-ffh-back__code code { font-family: inherit; }\n.fmstr-cmp-ffh-back__code .t { color: #f472b6; }\n.fmstr-cmp-ffh-back__code .a { color: #a5b4fc; }\n.fmstr-cmp-ffh-back__code .s { color: #86efac; }\n.fmstr-cmp-ffh-back__code .c { color: #64748b; font-style: italic; }\n\n.fmstr-cmp-ffh-back__list { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 8px; }\n.fmstr-cmp-ffh-back__row { display: flex; gap: 10px; font-size: 14px; line-height: 1.5; color: var(--fmstr-cmp-ffh-back-fg-2); }\n.fmstr-cmp-ffh-back__row::before {\ncontent: \"\"; width: 16px; height: 16px; border-radius: 50%; flex-shrink: 0; margin-top: 3px;\nbackground-repeat: no-repeat; background-position: center;\n}\n.fmstr-cmp-ffh-back__row--bad::before { background-color: var(--fmstr-cmp-ffh-back-red-bg); background-image: url(\"data:image\u002Fsvg+xml,%3Csvg xmlns='http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg' width='10' height='10' viewBox='0 0 10 10' fill='none' stroke='%23dc2626' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='M2 2 L8 8 M8 2 L2 8'\u002F%3E%3C\u002Fsvg%3E\"); }\n.fmstr-cmp-ffh-back__row--meh::before { background-color: var(--fmstr-cmp-ffh-back-amber-bg); background-image: url(\"data:image\u002Fsvg+xml,%3Csvg xmlns='http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg' width='10' height='10' viewBox='0 0 10 10' fill='none' stroke='%23d97706' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='M2 5 L8 5'\u002F%3E%3C\u002Fsvg%3E\"); }\n.fmstr-cmp-ffh-back__row--good::before { background-color: var(--fmstr-cmp-ffh-back-green-bg); background-image: url(\"data:image\u002Fsvg+xml,%3Csvg xmlns='http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg' width='10' height='10' viewBox='0 0 10 10' fill='none' stroke='%2315803d' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2 5 L4 7 L8 3'\u002F%3E%3C\u002Fsvg%3E\"); }\n.fmstr-cmp-ffh-back__row strong { color: var(--fmstr-cmp-ffh-back-fg-1); font-weight: 600; }\n\n.fmstr-cmp-ffh-back__cta {\nmargin-top: auto; padding-top: 4px;\ndisplay: inline-flex; align-items: center; gap: 8px;\ncolor: var(--fmstr-cmp-ffh-back-violet-600) !important;\nfont-weight: 600; font-size: 14.5px;\ntext-decoration: none !important;\n}\n.fmstr-cmp-ffh-back__cta:hover { text-decoration: underline !important; }\n\n@media (max-width: 760px) {\n.fmstr-cmp-ffh-back { padding: 40px 16px; }\n.fmstr-cmp-ffh-back__card { padding: 22px; }\n.fmstr-cmp-ffh-back__intro { font-size: 15.5px; }\n.fmstr-cmp-ffh-back__code { font-size: 11.5px; padding: 12px 14px; }\n}\n\u003C\u002Fstyle>\n\n\u003Csection class=\"fmstr-cmp-ffh-back\" aria-labelledby=\"fmstr-cmp-ffh-back-h2\">\n\u003Cdiv class=\"fmstr-cmp-ffh-back__container\">\n\u003Cdiv class=\"fmstr-cmp-ffh-back__head\">\n\u003Cspan class=\"fmstr-cmp-ffh-back__eyebrow\">Three honest paths\u003C\u002Fspan>\n\u003Ch2 class=\"fmstr-cmp-ffh-back__h2\" id=\"fmstr-cmp-ffh-back-h2\">What happens after the user clicks Submit\u003C\u002Fh2>\n\u003Cp class=\"fmstr-cmp-ffh-back__intro\">Without a backend, a feedback form is a dead form. The browser POSTs the data, the server returns 404, the user sees an error page. Here are the three real options, ranked by how much pain each one ships with.\u003C\u002Fp>\n\u003C\u002Fdiv>\n\n\u003Cdiv class=\"fmstr-cmp-ffh-back__grid\">\n\n\u003Carticle class=\"fmstr-cmp-ffh-back__card fmstr-cmp-ffh-back__card--red\">\n\u003Cspan class=\"fmstr-cmp-ffh-back__verdict fmstr-cmp-ffh-back__verdict--red\">Don&rsquo;t ship this\u003C\u002Fspan>\n\u003Ch3 class=\"fmstr-cmp-ffh-back__name\">Path 1: \u003Ccode>mailto:\u003C\u002Fcode>\u003C\u002Fh3>\n\u003Cp class=\"fmstr-cmp-ffh-back__sub\">The \"no server\" hack that loses about half your submissions.\u003C\u002Fp>\n\u003Cpre class=\"fmstr-cmp-ffh-back__code\">\u003Ccode>\u003Cspan class=\"c\">&lt;!-- Opens the user's mail client --&gt;\u003C\u002Fspan>\n\u003Cspan class=\"t\">&lt;form\u003C\u002Fspan>\n\u003Cspan class=\"a\">action\u003C\u002Fspan>=\u003Cspan class=\"s\">\"mailto:you@example.com\"\u003C\u002Fspan>\n\u003Cspan class=\"a\">method\u003C\u002Fspan>=\u003Cspan class=\"s\">\"post\"\u003C\u002Fspan>\n\u003Cspan class=\"a\">enctype\u003C\u002Fspan>=\u003Cspan class=\"s\">\"text\u002Fplain\"\u003C\u002Fspan>\u003Cspan class=\"t\">&gt;\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cul class=\"fmstr-cmp-ffh-back__list\">\n\u003Cli class=\"fmstr-cmp-ffh-back__row fmstr-cmp-ffh-back__row--bad\">\u003Cspan>\u003Cstrong>User-action required.\u003C\u002Fstrong> Browser opens a draft email. They have to click Send manually. Half won&rsquo;t.\u003C\u002Fspan>\u003C\u002Fli>\n\u003Cli class=\"fmstr-cmp-ffh-back__row fmstr-cmp-ffh-back__row--bad\">\u003Cspan>\u003Cstrong>Breaks on mobile.\u003C\u002Fstrong> Many phones have no configured mail client.\u003C\u002Fspan>\u003C\u002Fli>\n\u003Cli class=\"fmstr-cmp-ffh-back__row fmstr-cmp-ffh-back__row--bad\">\u003Cspan>\u003Cstrong>Spam-filter bait.\u003C\u002Fstrong> Resulting messages are unsigned and easy to flag.\u003C\u002Fspan>\u003C\u002Fli>\n\u003C\u002Ful>\n\u003C\u002Farticle>\n\n\u003Carticle class=\"fmstr-cmp-ffh-back__card fmstr-cmp-ffh-back__card--amber\">\n\u003Cspan class=\"fmstr-cmp-ffh-back__verdict fmstr-cmp-ffh-back__verdict--amber\">You&rsquo;ll maintain it\u003C\u002Fspan>\n\u003Ch3 class=\"fmstr-cmp-ffh-back__name\">Path 2: Your own server\u003C\u002Fh3>\n\u003Cp class=\"fmstr-cmp-ffh-back__sub\">PHP, Node, or whatever you already run. Full control, full ownership.\u003C\u002Fp>\n\u003Cpre class=\"fmstr-cmp-ffh-back__code\">\u003Ccode>\u003Cspan class=\"c\">\u002F\u002F minimal Node\u002FExpress receiver\u003C\u002Fspan>\napp.\u003Cspan class=\"t\">post\u003C\u002Fspan>(\u003Cspan class=\"s\">'\u002Fsubmit-feedback'\u003C\u002Fspan>, (req, res) =&gt; {\n\u003Cspan class=\"t\">const\u003C\u002Fspan> { name, email, message } = req.body;\n\u003Cspan class=\"t\">if\u003C\u002Fspan> (!validate(email)) \u003Cspan class=\"t\">return\u003C\u002Fspan> res.\u003Cspan class=\"t\">status\u003C\u002Fspan>(400);\ndb.\u003Cspan class=\"t\">insert\u003C\u002Fspan>({ name, email, message });\nres.\u003Cspan class=\"t\">redirect\u003C\u002Fspan>(\u003Cspan class=\"s\">'\u002Fthank-you'\u003C\u002Fspan>);\n});\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cul class=\"fmstr-cmp-ffh-back__list\">\n\u003Cli class=\"fmstr-cmp-ffh-back__row fmstr-cmp-ffh-back__row--meh\">\u003Cspan>\u003Cstrong>You own the server.\u003C\u002Fstrong> Hosting, TLS, scaling, uptime monitoring are yours.\u003C\u002Fspan>\u003C\u002Fli>\n\u003Cli class=\"fmstr-cmp-ffh-back__row fmstr-cmp-ffh-back__row--meh\">\u003Cspan>\u003Cstrong>Spam protection is on you.\u003C\u002Fstrong> Honeypot, rate limiting, CAPTCHA, all DIY.\u003C\u002Fspan>\u003C\u002Fli>\n\u003Cli class=\"fmstr-cmp-ffh-back__row fmstr-cmp-ffh-back__row--good\">\u003Cspan>\u003Cstrong>Maximum control.\u003C\u002Fstrong> Custom logic, database, queues, webhooks however you want.\u003C\u002Fspan>\u003C\u002Fli>\n\u003C\u002Ful>\n\u003C\u002Farticle>\n\n\u003Carticle class=\"fmstr-cmp-ffh-back__card fmstr-cmp-ffh-back__card--green\">\n\u003Cspan class=\"fmstr-cmp-ffh-back__verdict fmstr-cmp-ffh-back__verdict--green\">Skip the server\u003C\u002Fspan>\n\u003Ch3 class=\"fmstr-cmp-ffh-back__name\">Path 3: Formester HTML form backend\u003C\u002Fh3>\n\u003Cp class=\"fmstr-cmp-ffh-back__sub\">One \u003Ccode>action\u003C\u002Fcode> attribute swap. No server code, no infra.\u003C\u002Fp>\n\u003Cpre class=\"fmstr-cmp-ffh-back__code\">\u003Ccode>\u003Cspan class=\"c\">&lt;!-- The only change vs. Path 2 --&gt;\u003C\u002Fspan>\n\u003Cspan class=\"t\">&lt;form\u003C\u002Fspan>\n\u003Cspan class=\"a\">action\u003C\u002Fspan>=\u003Cspan class=\"s\">\"https:\u002F\u002Fapp.formester.com\u002F\u003C\u002Fspan>\n\u003Cspan class=\"s\">    api\u002Fv1\u002Fforms\u002FYOUR_ID\u002Fsubmissions\"\u003C\u002Fspan>\n\u003Cspan class=\"a\">method\u003C\u002Fspan>=\u003Cspan class=\"s\">\"post\"\u003C\u002Fspan>\u003Cspan class=\"t\">&gt;\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cul class=\"fmstr-cmp-ffh-back__list\">\n\u003Cli class=\"fmstr-cmp-ffh-back__row fmstr-cmp-ffh-back__row--good\">\u003Cspan>\u003Cstrong>Submissions land in the dashboard.\u003C\u002Fstrong> View, filter, \u003Ca href=\"https:\u002F\u002Fformester.com\u002Ffeatures\u002Fexport-form-submission-pdf\u002F\">export to PDF\u003C\u002Fa>, push to Sheets\u002FSlack\u002FHubSpot.\u003C\u002Fspan>\u003C\u002Fli>\n\u003Cli class=\"fmstr-cmp-ffh-back__row fmstr-cmp-ffh-back__row--good\">\u003Cspan>\u003Cstrong>Spam protection built in.\u003C\u002Fstrong> Honeypot plus \u003Ca href=\"https:\u002F\u002Fformester.com\u002Ffeatures\u002Fspam-protection\u002F\">reCAPTCHA-style checks\u003C\u002Fa> on every submission.\u003C\u002Fspan>\u003C\u002Fli>\n\u003Cli class=\"fmstr-cmp-ffh-back__row fmstr-cmp-ffh-back__row--good\">\u003Cspan>\u003Cstrong>Free with unlimited submissions.\u003C\u002Fstrong> Email notifications, dashboard, integrations included. Used by 56,000+ teams.\u003C\u002Fspan>\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ca class=\"fmstr-cmp-ffh-back__cta\" href=\"https:\u002F\u002Fformester.com\u002Ffeatures\u002Fhtml-form-backend\u002F\">See the HTML form backend &rarr;\u003C\u002Fa>\n\u003C\u002Farticle>\n\n\u003C\u002Fdiv>\n\u003C\u002Fdiv>\n\u003C\u002Fsection>\n\n\u003Cstyle>\n\u002F* host-link-override *\u002F\n.fmstr-cmp-ffh-code a { text-decoration: none !important; }\n.fmstr-cmp-ffh-code {\n--fmstr-cmp-ffh-code-bg-card: #ffffff;\n--fmstr-cmp-ffh-code-bg-code: #0f172a;\n--fmstr-cmp-ffh-code-bg-preview: #f7f7f9;\n--fmstr-cmp-ffh-code-fg-1: #101828;\n--fmstr-cmp-ffh-code-fg-2: #475467;\n--fmstr-cmp-ffh-code-fg-3: #697586;\n--fmstr-cmp-ffh-code-violet-500: #7f56d9;\n--fmstr-cmp-ffh-code-violet-600: #6941c6;\n--fmstr-cmp-ffh-code-tint: #f7f3ff;\n--fmstr-cmp-ffh-code-edge: #e4d7ff;\n--fmstr-cmp-ffh-code-border: #eaecf0;\n--fmstr-cmp-ffh-code-code-fg: #e2e8f0;\n--fmstr-cmp-ffh-code-code-tag: #f472b6;\n--fmstr-cmp-ffh-code-code-attr: #a5b4fc;\n--fmstr-cmp-ffh-code-code-str: #86efac;\n--fmstr-cmp-ffh-code-code-comment: #64748b;\n--fmstr-cmp-ffh-code-shadow: 0 4px 20px rgba(16,24,40,.06), 0 2px 6px rgba(16,24,40,.04);\n\nbackground: transparent; padding: 56px 24px;\nfont-family: inherit; color: var(--fmstr-cmp-ffh-code-fg-1);\n}\n.fmstr-cmp-ffh-code *, .fmstr-cmp-ffh-code *::before, .fmstr-cmp-ffh-code *::after { box-sizing: border-box; }\n.fmstr-cmp-ffh-code__container { max-width: 820px; margin: 0 auto; }\n.fmstr-cmp-ffh-code__head { max-width: 780px; margin: 0 0 32px; }\n.fmstr-cmp-ffh-code__eyebrow {\ndisplay: inline-block; padding: 5px 12px; border-radius: 9999px;\nbackground: var(--fmstr-cmp-ffh-code-tint); color: var(--fmstr-cmp-ffh-code-violet-600);\nfont-size: 12px; font-weight: 600; letter-spacing: .04em;\ntext-transform: uppercase; border: 1px solid var(--fmstr-cmp-ffh-code-edge); margin: 0 0 14px;\n}\n.fmstr-cmp-ffh-code__h2 { font-size: clamp(26px, 3vw, 36px); font-weight: 700; line-height: 1.15; letter-spacing: -.02em; margin: 0; }\n.fmstr-cmp-ffh-code__intro { color: var(--fmstr-cmp-ffh-code-fg-3); font-size: 17px; line-height: 1.6; margin: 14px 0 0; }\n\n.fmstr-cmp-ffh-code__grid {\ndisplay: grid; grid-template-columns: 1fr; gap: 0;\nbackground: var(--fmstr-cmp-ffh-code-bg-card);\nborder: 1px solid var(--fmstr-cmp-ffh-code-border);\nborder-radius: 20px; overflow: hidden;\nbox-shadow: var(--fmstr-cmp-ffh-code-shadow);\n}\n\n.fmstr-cmp-ffh-code__preview-pane {\nbackground: var(--fmstr-cmp-ffh-code-bg-preview);\npadding: 28px 24px;\ndisplay: flex; flex-direction: column; gap: 14px;\nborder-bottom: 1px solid var(--fmstr-cmp-ffh-code-border);\n}\n.fmstr-cmp-ffh-code__preview-label {\nfont-size: 11px; font-weight: 700; letter-spacing: .08em;\ntext-transform: uppercase; color: var(--fmstr-cmp-ffh-code-fg-3);\ndisplay: flex; align-items: center; gap: 8px;\n}\n.fmstr-cmp-ffh-code__preview-label::before {\ncontent: \"\"; width: 8px; height: 8px; border-radius: 50%;\nbackground: #22c55e; flex-shrink: 0;\n}\n.fmstr-cmp-ffh-code__preview-form {\nbackground: #fff; padding: 22px 20px; border-radius: 12px;\nbox-shadow: 0 2px 12px rgba(0,0,0,0.06);\ndisplay: flex; flex-direction: column; gap: 14px;\n}\n.fmstr-cmp-ffh-code__preview-h { font-size: 16px; font-weight: 700; text-align: center; margin: 0 0 4px; color: var(--fmstr-cmp-ffh-code-fg-1); }\n.fmstr-cmp-ffh-code__preview-field { display: flex; flex-direction: column; gap: 6px; }\n.fmstr-cmp-ffh-code__preview-label-row { font-size: 12.5px; font-weight: 600; color: var(--fmstr-cmp-ffh-code-fg-1); }\n.fmstr-cmp-ffh-code__preview-input {\nbackground: #fff; border: 1px solid #d0d0d6; border-radius: 8px;\npadding: 9px 11px; font-size: 12.5px; color: var(--fmstr-cmp-ffh-code-fg-3);\n}\n.fmstr-cmp-ffh-code__preview-input--focus { outline: 2px solid var(--fmstr-cmp-ffh-code-violet-500); outline-offset: 1px; border-color: var(--fmstr-cmp-ffh-code-violet-500); color: var(--fmstr-cmp-ffh-code-fg-1); }\n.fmstr-cmp-ffh-code__preview-select {\nbackground: #fff; border: 1px solid #d0d0d6; border-radius: 8px;\npadding: 9px 11px; font-size: 12.5px; color: var(--fmstr-cmp-ffh-code-fg-3);\ndisplay: flex; justify-content: space-between; align-items: center;\n}\n.fmstr-cmp-ffh-code__preview-textarea {\nbackground: #fff; border: 1px solid #d0d0d6; border-radius: 8px;\npadding: 9px 11px; font-size: 12.5px; color: var(--fmstr-cmp-ffh-code-fg-3);\nmin-height: 54px;\n}\n.fmstr-cmp-ffh-code__preview-btn {\nbackground: var(--fmstr-cmp-ffh-code-violet-500); color: #fff;\npadding: 10px; border-radius: 8px; text-align: center;\nfont-weight: 600; font-size: 13px; margin-top: 4px;\n}\n.fmstr-cmp-ffh-code__preview-caption {\nfont-size: 12px; color: var(--fmstr-cmp-ffh-code-fg-3); line-height: 1.5; margin: 4px 0 0;\n}\n\n.fmstr-cmp-ffh-code__code-pane {\nbackground: var(--fmstr-cmp-ffh-code-bg-code);\nposition: relative; max-height: 560px;\ndisplay: flex; flex-direction: column;\n}\n.fmstr-cmp-ffh-code__code-header {\ndisplay: flex; align-items: center; justify-content: space-between;\npadding: 14px 18px; border-bottom: 1px solid rgba(255,255,255,0.08);\ncolor: var(--fmstr-cmp-ffh-code-code-comment);\nfont-family: ui-monospace, Menlo, Monaco, monospace; font-size: 12px;\n}\n.fmstr-cmp-ffh-code__code-filename { display: flex; align-items: center; gap: 8px; }\n.fmstr-cmp-ffh-code__code-filename::before {\ncontent: \"\"; width: 10px; height: 10px; border-radius: 50%; background: #f87171;\nbox-shadow: 16px 0 0 #fbbf24, 32px 0 0 #34d399;\nmargin-right: 12px;\n}\n.fmstr-cmp-ffh-code__code-copy {\nbackground: rgba(127, 86, 217, 0.18) !important;\ncolor: #c4b5fd !important; border: 1px solid rgba(127, 86, 217, 0.4);\npadding: 6px 14px; border-radius: 6px; font-size: 12px; font-weight: 600;\ncursor: pointer; font-family: ui-monospace, Menlo, Monaco, monospace;\ndisplay: inline-flex; align-items: center; gap: 6px;\n}\n.fmstr-cmp-ffh-code__code-copy:hover { background: rgba(127, 86, 217, 0.28) !important; }\n.fmstr-cmp-ffh-code__code-body {\nmargin: 0; padding: 18px 20px;\nfont-family: ui-monospace, Menlo, Monaco, monospace;\nfont-size: 12.5px; line-height: 1.65;\ncolor: var(--fmstr-cmp-ffh-code-code-fg);\noverflow: auto; flex-grow: 1;\nwhite-space: pre;\nscrollbar-width: thin; scrollbar-color: rgba(167,139,250,.35) transparent;\n}\n.fmstr-cmp-ffh-code__code-body::-webkit-scrollbar { width: 10px; height: 10px; }\n.fmstr-cmp-ffh-code__code-body::-webkit-scrollbar-track { background: transparent; }\n.fmstr-cmp-ffh-code__code-body::-webkit-scrollbar-thumb { background: rgba(167,139,250,.3); border-radius: 5px; }\n.fmstr-cmp-ffh-code__code-body::-webkit-scrollbar-thumb:hover { background: rgba(167,139,250,.5); }\n.fmstr-cmp-ffh-code__code-body code { font-family: inherit; }\n.fmstr-cmp-ffh-code__tag { color: var(--fmstr-cmp-ffh-code-code-tag); }\n.fmstr-cmp-ffh-code__attr { color: var(--fmstr-cmp-ffh-code-code-attr); }\n.fmstr-cmp-ffh-code__str { color: var(--fmstr-cmp-ffh-code-code-str); }\n.fmstr-cmp-ffh-code__cmt { color: var(--fmstr-cmp-ffh-code-code-comment); font-style: italic; }\n\n.fmstr-cmp-ffh-code__foot {\nmargin: 20px auto 0; max-width: 780px; text-align: center;\ncolor: var(--fmstr-cmp-ffh-code-fg-3); font-size: 14.5px; line-height: 1.6;\n}\n.fmstr-cmp-ffh-code__foot a { color: var(--fmstr-cmp-ffh-code-violet-600) !important; font-weight: 600; }\n.fmstr-cmp-ffh-code__foot a:hover { text-decoration: underline !important; }\n\n@media (max-width: 760px) {\n.fmstr-cmp-ffh-code { padding: 40px 16px; }\n.fmstr-cmp-ffh-code__grid { border-radius: 16px; }\n.fmstr-cmp-ffh-code__preview-pane { padding: 22px 18px; }\n.fmstr-cmp-ffh-code__code-pane { max-height: 420px; }\n.fmstr-cmp-ffh-code__code-body { font-size: 11.5px; padding: 14px 16px; }\n.fmstr-cmp-ffh-code__intro { font-size: 15.5px; }\n}\n\u003C\u002Fstyle>\n\n\u003Csection class=\"fmstr-cmp-ffh-code\" aria-labelledby=\"fmstr-cmp-ffh-code-h2\">\n\u003Cdiv class=\"fmstr-cmp-ffh-code__container\">\n\u003Cdiv class=\"fmstr-cmp-ffh-code__head\">\n\u003Cspan class=\"fmstr-cmp-ffh-code__eyebrow\">Copy, paste, ship\u003C\u002Fspan>\n\u003Ch2 class=\"fmstr-cmp-ffh-code__h2\" id=\"fmstr-cmp-ffh-code-h2\">The complete feedback form, in one file\u003C\u002Fh2>\n\u003Cp class=\"fmstr-cmp-ffh-code__intro\">Structure, styling, and accessible JavaScript validation in a single working file. Save as \u003Ccode>feedback.html\u003C\u002Fcode>, swap the \u003Ccode>action\u003C\u002Fcode> URL, and the form is live.\u003C\u002Fp>\n\u003C\u002Fdiv>\n\n\u003Cdiv class=\"fmstr-cmp-ffh-code__grid\">\n\u003Cdiv class=\"fmstr-cmp-ffh-code__preview-pane\">\n\u003Cdiv class=\"fmstr-cmp-ffh-code__preview-label\">Live preview\u003C\u002Fdiv>\n\u003Cdiv class=\"fmstr-cmp-ffh-code__preview-form\">\n\u003Ch3 class=\"fmstr-cmp-ffh-code__preview-h\">Tell us what you think\u003C\u002Fh3>\n\u003Cdiv class=\"fmstr-cmp-ffh-code__preview-field\">\n\u003Cspan class=\"fmstr-cmp-ffh-code__preview-label-row\">Name\u003C\u002Fspan>\n\u003Cdiv class=\"fmstr-cmp-ffh-code__preview-input\">Jane Doe\u003C\u002Fdiv>\n\u003C\u002Fdiv>\n\u003Cdiv class=\"fmstr-cmp-ffh-code__preview-field\">\n\u003Cspan class=\"fmstr-cmp-ffh-code__preview-label-row\">Email\u003C\u002Fspan>\n\u003Cdiv class=\"fmstr-cmp-ffh-code__preview-input fmstr-cmp-ffh-code__preview-input--focus\">jane@example.com\u003C\u002Fdiv>\n\u003C\u002Fdiv>\n\u003Cdiv class=\"fmstr-cmp-ffh-code__preview-field\">\n\u003Cspan class=\"fmstr-cmp-ffh-code__preview-label-row\">How was your experience?\u003C\u002Fspan>\n\u003Cdiv class=\"fmstr-cmp-ffh-code__preview-select\">\u003Cspan>Loved it\u003C\u002Fspan>\u003Cspan>&#9662;\u003C\u002Fspan>\u003C\u002Fdiv>\n\u003C\u002Fdiv>\n\u003Cdiv class=\"fmstr-cmp-ffh-code__preview-field\">\n\u003Cspan class=\"fmstr-cmp-ffh-code__preview-label-row\">Your feedback\u003C\u002Fspan>\n\u003Cdiv class=\"fmstr-cmp-ffh-code__preview-textarea\">The dashboard is fast and the export to PDF saved my week.\u003C\u002Fdiv>\n\u003C\u002Fdiv>\n\u003Cdiv class=\"fmstr-cmp-ffh-code__preview-btn\">Send feedback\u003C\u002Fdiv>\n\u003C\u002Fdiv>\n\u003Cp class=\"fmstr-cmp-ffh-code__preview-caption\">Rendered output. Keyboard-accessible focus ring on the active field, inline error slot ready, mobile-friendly layout.\u003C\u002Fp>\n\u003C\u002Fdiv>\n\n\u003Cdiv class=\"fmstr-cmp-ffh-code__code-pane\">\n\u003Cdiv class=\"fmstr-cmp-ffh-code__code-header\">\n\u003Cspan class=\"fmstr-cmp-ffh-code__code-filename\">feedback.html\u003C\u002Fspan>\n\u003Cbutton type=\"button\" class=\"fmstr-cmp-ffh-code__code-copy\" aria-label=\"Copy code\">Copy\u003C\u002Fbutton>\n\u003C\u002Fdiv>\n\u003Cpre class=\"fmstr-cmp-ffh-code__code-body\">\u003Ccode>\u003Cspan class=\"fmstr-cmp-ffh-code__cmt\">&lt;!DOCTYPE html&gt;\u003C\u002Fspan>\n\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&lt;html\u003C\u002Fspan> \u003Cspan class=\"fmstr-cmp-ffh-code__attr\">lang\u003C\u002Fspan>=\u003Cspan class=\"fmstr-cmp-ffh-code__str\">\"en\"\u003C\u002Fspan>\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&gt;\u003C\u002Fspan>\n\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&lt;head&gt;\u003C\u002Fspan>\n\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&lt;meta\u003C\u002Fspan> \u003Cspan class=\"fmstr-cmp-ffh-code__attr\">charset\u003C\u002Fspan>=\u003Cspan class=\"fmstr-cmp-ffh-code__str\">\"UTF-8\"\u003C\u002Fspan>\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&gt;\u003C\u002Fspan>\n\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&lt;meta\u003C\u002Fspan> \u003Cspan class=\"fmstr-cmp-ffh-code__attr\">name\u003C\u002Fspan>=\u003Cspan class=\"fmstr-cmp-ffh-code__str\">\"viewport\"\u003C\u002Fspan> \u003Cspan class=\"fmstr-cmp-ffh-code__attr\">content\u003C\u002Fspan>=\u003Cspan class=\"fmstr-cmp-ffh-code__str\">\"width=device-width, initial-scale=1.0\"\u003C\u002Fspan>\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&gt;\u003C\u002Fspan>\n\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&lt;title&gt;\u003C\u002Fspan>Feedback Form\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&lt;\u002Ftitle&gt;\u003C\u002Fspan>\n\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&lt;style&gt;\u003C\u002Fspan>\nbody { font-family: system-ui, sans-serif; background: #f7f7f9; padding: 40px 16px; }\nform { max-width: 480px; margin: 0 auto; background: #fff; padding: 24px; border-radius: 12px; }\n.field { margin-bottom: 16px; }\nlabel { display: block; font-weight: 600; margin-bottom: 6px; }\ninput, select, textarea { width: 100%; padding: 10px 12px; border: 1px solid #d0d0d6; border-radius: 8px; box-sizing: border-box; }\ninput:focus, select:focus, textarea:focus { outline: 2px solid #5b6cff; border-color: #5b6cff; }\n[aria-invalid=\"true\"] { border-color: #d33; }\n.error { display: block; color: #d33; font-size: 0.8rem; margin-top: 4px; }\nbutton { width: 100%; padding: 12px; background: #5b6cff; color: #fff; font-weight: 600; border: none; border-radius: 8px; cursor: pointer; }\n\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&lt;\u002Fstyle&gt;\u003C\u002Fspan>\n\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&lt;\u002Fhead&gt;\u003C\u002Fspan>\n\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&lt;body&gt;\u003C\u002Fspan>\n\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&lt;h1&gt;\u003C\u002Fspan>Tell us what you think\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&lt;\u002Fh1&gt;\u003C\u002Fspan>\n\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&lt;form\u003C\u002Fspan> \u003Cspan class=\"fmstr-cmp-ffh-code__attr\">id\u003C\u002Fspan>=\u003Cspan class=\"fmstr-cmp-ffh-code__str\">\"feedback-form\"\u003C\u002Fspan> \u003Cspan class=\"fmstr-cmp-ffh-code__attr\">action\u003C\u002Fspan>=\u003Cspan class=\"fmstr-cmp-ffh-code__str\">\"https:\u002F\u002Fapp.formester.com\u002Fapi\u002Fv1\u002Fforms\u002FYOUR_FORM_ID\u002Fsubmissions\"\u003C\u002Fspan> \u003Cspan class=\"fmstr-cmp-ffh-code__attr\">method\u003C\u002Fspan>=\u003Cspan class=\"fmstr-cmp-ffh-code__str\">\"post\"\u003C\u002Fspan> \u003Cspan class=\"fmstr-cmp-ffh-code__attr\">novalidate\u003C\u002Fspan>\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&gt;\u003C\u002Fspan>\n\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&lt;div\u003C\u002Fspan> \u003Cspan class=\"fmstr-cmp-ffh-code__attr\">class\u003C\u002Fspan>=\u003Cspan class=\"fmstr-cmp-ffh-code__str\">\"field\"\u003C\u002Fspan>\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&gt;\u003C\u002Fspan>\n\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&lt;label\u003C\u002Fspan> \u003Cspan class=\"fmstr-cmp-ffh-code__attr\">for\u003C\u002Fspan>=\u003Cspan class=\"fmstr-cmp-ffh-code__str\">\"name\"\u003C\u002Fspan>\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&gt;\u003C\u002Fspan>Name\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&lt;\u002Flabel&gt;\u003C\u002Fspan>\n\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&lt;input\u003C\u002Fspan> \u003Cspan class=\"fmstr-cmp-ffh-code__attr\">type\u003C\u002Fspan>=\u003Cspan class=\"fmstr-cmp-ffh-code__str\">\"text\"\u003C\u002Fspan> \u003Cspan class=\"fmstr-cmp-ffh-code__attr\">id\u003C\u002Fspan>=\u003Cspan class=\"fmstr-cmp-ffh-code__str\">\"name\"\u003C\u002Fspan> \u003Cspan class=\"fmstr-cmp-ffh-code__attr\">name\u003C\u002Fspan>=\u003Cspan class=\"fmstr-cmp-ffh-code__str\">\"name\"\u003C\u002Fspan> \u003Cspan class=\"fmstr-cmp-ffh-code__attr\">autocomplete\u003C\u002Fspan>=\u003Cspan class=\"fmstr-cmp-ffh-code__str\">\"name\"\u003C\u002Fspan> \u003Cspan class=\"fmstr-cmp-ffh-code__attr\">required\u003C\u002Fspan>\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&gt;\u003C\u002Fspan>\n\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&lt;\u002Fdiv&gt;\u003C\u002Fspan>\n\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&lt;div\u003C\u002Fspan> \u003Cspan class=\"fmstr-cmp-ffh-code__attr\">class\u003C\u002Fspan>=\u003Cspan class=\"fmstr-cmp-ffh-code__str\">\"field\"\u003C\u002Fspan>\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&gt;\u003C\u002Fspan>\n\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&lt;label\u003C\u002Fspan> \u003Cspan class=\"fmstr-cmp-ffh-code__attr\">for\u003C\u002Fspan>=\u003Cspan class=\"fmstr-cmp-ffh-code__str\">\"email\"\u003C\u002Fspan>\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&gt;\u003C\u002Fspan>Email\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&lt;\u002Flabel&gt;\u003C\u002Fspan>\n\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&lt;input\u003C\u002Fspan> \u003Cspan class=\"fmstr-cmp-ffh-code__attr\">type\u003C\u002Fspan>=\u003Cspan class=\"fmstr-cmp-ffh-code__str\">\"email\"\u003C\u002Fspan> \u003Cspan class=\"fmstr-cmp-ffh-code__attr\">id\u003C\u002Fspan>=\u003Cspan class=\"fmstr-cmp-ffh-code__str\">\"email\"\u003C\u002Fspan> \u003Cspan class=\"fmstr-cmp-ffh-code__attr\">name\u003C\u002Fspan>=\u003Cspan class=\"fmstr-cmp-ffh-code__str\">\"email\"\u003C\u002Fspan> \u003Cspan class=\"fmstr-cmp-ffh-code__attr\">autocomplete\u003C\u002Fspan>=\u003Cspan class=\"fmstr-cmp-ffh-code__str\">\"email\"\u003C\u002Fspan> \u003Cspan class=\"fmstr-cmp-ffh-code__attr\">required\u003C\u002Fspan>\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&gt;\u003C\u002Fspan>\n\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&lt;\u002Fdiv&gt;\u003C\u002Fspan>\n\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&lt;div\u003C\u002Fspan> \u003Cspan class=\"fmstr-cmp-ffh-code__attr\">class\u003C\u002Fspan>=\u003Cspan class=\"fmstr-cmp-ffh-code__str\">\"field\"\u003C\u002Fspan>\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&gt;\u003C\u002Fspan>\n\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&lt;label\u003C\u002Fspan> \u003Cspan class=\"fmstr-cmp-ffh-code__attr\">for\u003C\u002Fspan>=\u003Cspan class=\"fmstr-cmp-ffh-code__str\">\"rating\"\u003C\u002Fspan>\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&gt;\u003C\u002Fspan>How was your experience?\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&lt;\u002Flabel&gt;\u003C\u002Fspan>\n\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&lt;select\u003C\u002Fspan> \u003Cspan class=\"fmstr-cmp-ffh-code__attr\">id\u003C\u002Fspan>=\u003Cspan class=\"fmstr-cmp-ffh-code__str\">\"rating\"\u003C\u002Fspan> \u003Cspan class=\"fmstr-cmp-ffh-code__attr\">name\u003C\u002Fspan>=\u003Cspan class=\"fmstr-cmp-ffh-code__str\">\"rating\"\u003C\u002Fspan> \u003Cspan class=\"fmstr-cmp-ffh-code__attr\">required\u003C\u002Fspan>\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&gt;\u003C\u002Fspan>\n\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&lt;option\u003C\u002Fspan> \u003Cspan class=\"fmstr-cmp-ffh-code__attr\">value\u003C\u002Fspan>=\u003Cspan class=\"fmstr-cmp-ffh-code__str\">\"\"\u003C\u002Fspan>\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&gt;\u003C\u002Fspan>Pick one\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&lt;\u002Foption&gt;\u003C\u002Fspan>\n\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&lt;option\u003C\u002Fspan> \u003Cspan class=\"fmstr-cmp-ffh-code__attr\">value\u003C\u002Fspan>=\u003Cspan class=\"fmstr-cmp-ffh-code__str\">\"5\"\u003C\u002Fspan>\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&gt;\u003C\u002Fspan>Loved it\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&lt;\u002Foption&gt;\u003C\u002Fspan>\n\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&lt;option\u003C\u002Fspan> \u003Cspan class=\"fmstr-cmp-ffh-code__attr\">value\u003C\u002Fspan>=\u003Cspan class=\"fmstr-cmp-ffh-code__str\">\"3\"\u003C\u002Fspan>\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&gt;\u003C\u002Fspan>Okay\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&lt;\u002Foption&gt;\u003C\u002Fspan>\n\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&lt;option\u003C\u002Fspan> \u003Cspan class=\"fmstr-cmp-ffh-code__attr\">value\u003C\u002Fspan>=\u003Cspan class=\"fmstr-cmp-ffh-code__str\">\"1\"\u003C\u002Fspan>\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&gt;\u003C\u002Fspan>Bad\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&lt;\u002Foption&gt;\u003C\u002Fspan>\n\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&lt;\u002Fselect&gt;\u003C\u002Fspan>\n\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&lt;\u002Fdiv&gt;\u003C\u002Fspan>\n\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&lt;div\u003C\u002Fspan> \u003Cspan class=\"fmstr-cmp-ffh-code__attr\">class\u003C\u002Fspan>=\u003Cspan class=\"fmstr-cmp-ffh-code__str\">\"field\"\u003C\u002Fspan>\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&gt;\u003C\u002Fspan>\n\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&lt;label\u003C\u002Fspan> \u003Cspan class=\"fmstr-cmp-ffh-code__attr\">for\u003C\u002Fspan>=\u003Cspan class=\"fmstr-cmp-ffh-code__str\">\"message\"\u003C\u002Fspan>\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&gt;\u003C\u002Fspan>Your feedback\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&lt;\u002Flabel&gt;\u003C\u002Fspan>\n\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&lt;textarea\u003C\u002Fspan> \u003Cspan class=\"fmstr-cmp-ffh-code__attr\">id\u003C\u002Fspan>=\u003Cspan class=\"fmstr-cmp-ffh-code__str\">\"message\"\u003C\u002Fspan> \u003Cspan class=\"fmstr-cmp-ffh-code__attr\">name\u003C\u002Fspan>=\u003Cspan class=\"fmstr-cmp-ffh-code__str\">\"message\"\u003C\u002Fspan> \u003Cspan class=\"fmstr-cmp-ffh-code__attr\">rows\u003C\u002Fspan>=\u003Cspan class=\"fmstr-cmp-ffh-code__str\">\"5\"\u003C\u002Fspan> \u003Cspan class=\"fmstr-cmp-ffh-code__attr\">required\u003C\u002Fspan>\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&gt;&lt;\u002Ftextarea&gt;\u003C\u002Fspan>\n\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&lt;\u002Fdiv&gt;\u003C\u002Fspan>\n\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&lt;button\u003C\u002Fspan> \u003Cspan class=\"fmstr-cmp-ffh-code__attr\">type\u003C\u002Fspan>=\u003Cspan class=\"fmstr-cmp-ffh-code__str\">\"submit\"\u003C\u002Fspan>\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&gt;\u003C\u002Fspan>Send feedback\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&lt;\u002Fbutton&gt;\u003C\u002Fspan>\n\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&lt;\u002Fform&gt;\u003C\u002Fspan>\n\n\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&lt;script&gt;\u003C\u002Fspan>\n\u003Cspan class=\"fmstr-cmp-ffh-code__cmt\">\u002F\u002F Accessible inline validation: aria-invalid, aria-describedby, focus management\u003C\u002Fspan>\nconst form = document.getElementById(\u003Cspan class=\"fmstr-cmp-ffh-code__str\">'feedback-form'\u003C\u002Fspan>);\nform.addEventListener(\u003Cspan class=\"fmstr-cmp-ffh-code__str\">'submit'\u003C\u002Fspan>, (e) =&gt; {\nlet firstInvalid = null;\n[...form.querySelectorAll(\u003Cspan class=\"fmstr-cmp-ffh-code__str\">'input, select, textarea'\u003C\u002Fspan>)].forEach((input) =&gt; {\nconst valid = input.value.trim() &amp;&amp; (input.type !== \u003Cspan class=\"fmstr-cmp-ffh-code__str\">'email'\u003C\u002Fspan> || \u002F^\\S+@\\S+\\.\\S+$\u002F.test(input.value));\ninput.setAttribute(\u003Cspan class=\"fmstr-cmp-ffh-code__str\">'aria-invalid'\u003C\u002Fspan>, valid ? \u003Cspan class=\"fmstr-cmp-ffh-code__str\">'false'\u003C\u002Fspan> : \u003Cspan class=\"fmstr-cmp-ffh-code__str\">'true'\u003C\u002Fspan>);\nif (!valid &amp;&amp; !firstInvalid) firstInvalid = input;\n});\nif (firstInvalid) { e.preventDefault(); firstInvalid.focus(); }\n});\n\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&lt;\u002Fscript&gt;\u003C\u002Fspan>\n\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&lt;\u002Fbody&gt;\u003C\u002Fspan>\n\u003Cspan class=\"fmstr-cmp-ffh-code__tag\">&lt;\u002Fhtml&gt;\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C\u002Fdiv>\n\u003C\u002Fdiv>\n\n\u003Cp class=\"fmstr-cmp-ffh-code__foot\">The \u003Ccode>action\u003C\u002Fcode> URL above points to \u003Ca href=\"https:\u002F\u002Fformester.com\u002Ffeatures\u002Fhtml-form-backend\u002F\">Formester&rsquo;s HTML form backend\u003C\u002Fa>. Replace \u003Ccode>YOUR_FORM_ID\u003C\u002Fcode> with your form&rsquo;s ID, or point it at your own server. Everything else stays the same.\u003C\u002Fp>\n\u003C\u002Fdiv>\n\u003C\u002Fsection>\n\n\u003Csection class=\"fmstr-cmp-ffh-body\" aria-label=\"Common mistakes and variants\">\n\u003Cdiv class=\"fmstr-cmp-ffh-body__container\">\n\n\u003Ch2 class=\"fmstr-cmp-ffh-body__h2\">Common mistakes that break feedback forms\u003C\u002Fh2>\n\u003Cul>\n\u003Cli>\u003Cstrong>\u003Ccode>mailto:\u003C\u002Fcode> as the action.\u003C\u002Fstrong> Looks like the easy answer. Drops half your submissions because the user has to manually send the draft. Use a real backend.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Missing \u003Ccode>name\u003C\u002Fcode> attributes.\u003C\u002Fstrong> The form POSTs successfully but the server gets empty fields. \u003Ccode>id\u003C\u002Fcode> is for CSS and labels; \u003Ccode>name\u003C\u002Fcode> is what the server reads.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Removed focus outlines.\u003C\u002Fstrong> \u003Ccode>outline: none\u003C\u002Fcode> is the most copy-pasted CSS mistake on the web. It breaks keyboard navigation. Replace the outline; don't delete it.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Client-side validation only.\u003C\u002Fstrong> A user with DevTools open can submit anything. Validate on the server too.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>No spam protection.\u003C\u002Fstrong> Public forms attract bots within hours. Add a honeypot field (a hidden input that bots fill and humans don't) or a CAPTCHA. \u003Ca href=\"https:\u002F\u002Fformester.com\u002Ffeatures\u002Fspam-protection\u002F\">Formester's backend\u003C\u002Fa> does this automatically.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>No confirmation page or message.\u003C\u002Fstrong> The user submits, the page reloads, nothing visibly changes. They submit again. Add a \u003Ccode>&lt;p role=\"status\"&gt;Thanks, we got it&lt;\u002Fp&gt;\u003C\u002Fcode> or redirect to a thank-you page.\u003C\u002Fli>\n\u003C\u002Ful>\n\n\u003Ch2 class=\"fmstr-cmp-ffh-body__h2\">Variants of the feedback form\u003C\u002Fh2>\n\u003Cp>The base form covers most cases. Three common variants:\u003C\u002Fp>\n\u003Cdiv class=\"fmstr-cmp-ffh-body__variants\">\n\u003Cdiv class=\"fmstr-cmp-ffh-body__variant\">\n\u003Ch4>Customer feedback (with rating)\u003C\u002Fh4>\n\u003Cp>Add a 1-5 star scale instead of the dropdown. The \u003Ccode>&lt;input type=\"range\"&gt;\u003C\u002Fcode> works, but a row of radio buttons styled as stars is clearer for screen readers. The \u003Ca href=\"https:\u002F\u002Fformester.com\u002Ftemplates\u002Fcustomer-feedback-form-31840\u002F\">customer feedback form template\u003C\u002Fa> ships this layout pre-built.\u003C\u002Fp>\n\u003C\u002Fdiv>\n\u003Cdiv class=\"fmstr-cmp-ffh-body__variant\">\n\u003Ch4>Product feedback (with feature picker)\u003C\u002Fh4>\n\u003Cp>Add a checkbox group: \"Which features did you use?\" with options like Onboarding, Search, Reporting. Use \u003Ccode>&lt;fieldset&gt;&lt;legend&gt;\u003C\u002Fcode> around the group so screen readers announce it as one question. The \u003Ca href=\"https:\u002F\u002Fformester.com\u002Ftemplates\u002Fcategories\u002Ffeedback-forms\u002F\">feedback form templates library\u003C\u002Fa> has a fuller version.\u003C\u002Fp>\n\u003C\u002Fdiv>\n\u003Cdiv class=\"fmstr-cmp-ffh-body__variant\">\n\u003Ch4>Employee feedback (anonymous)\u003C\u002Fh4>\n\u003Cp>Drop the name and email fields entirely. Add a \"Department\" dropdown and a longer text area. If you collect this through Formester, turn off IP tracking in the form settings to keep submissions genuinely anonymous. The \u003Ca href=\"https:\u002F\u002Fformester.com\u002Ftemplates\u002Fcategories\u002Ffeedback-forms\u002F\">employee feedback templates\u003C\u002Fa> are preconfigured for this.\u003C\u002Fp>\n\u003C\u002Fdiv>\n\u003C\u002Fdiv>\n\n\u003C\u002Fdiv>\n\u003C\u002Fsection>\n\n\u003Cstyle>\n\u002F* host-link-override *\u002F\n.fmstr-cmp-ffh-a11y a { text-decoration: none !important; }\n.fmstr-cmp-ffh-a11y {\n--fmstr-cmp-ffh-a11y-bg-card: #ffffff;\n--fmstr-cmp-ffh-a11y-bg-code: #0f172a;\n--fmstr-cmp-ffh-a11y-fg-1: #101828;\n--fmstr-cmp-ffh-a11y-fg-2: #475467;\n--fmstr-cmp-ffh-a11y-fg-3: #697586;\n--fmstr-cmp-ffh-a11y-violet-500: #7f56d9;\n--fmstr-cmp-ffh-a11y-violet-600: #6941c6;\n--fmstr-cmp-ffh-a11y-tint: #f7f3ff;\n--fmstr-cmp-ffh-a11y-edge: #e4d7ff;\n--fmstr-cmp-ffh-a11y-border: #eaecf0;\n--fmstr-cmp-ffh-a11y-red-bg: #fef2f2;\n--fmstr-cmp-ffh-a11y-red-edge: #fecaca;\n--fmstr-cmp-ffh-a11y-red: #b91c1c;\n--fmstr-cmp-ffh-a11y-green-bg: #f0fdf4;\n--fmstr-cmp-ffh-a11y-green-edge: #bbf7d0;\n--fmstr-cmp-ffh-a11y-green: #15803d;\n--fmstr-cmp-ffh-a11y-shadow: 0 4px 20px rgba(16,24,40,.06), 0 2px 6px rgba(16,24,40,.04);\n\nbackground: transparent; padding: 56px 24px;\nfont-family: inherit; color: var(--fmstr-cmp-ffh-a11y-fg-1);\n}\n.fmstr-cmp-ffh-a11y *, .fmstr-cmp-ffh-a11y *::before, .fmstr-cmp-ffh-a11y *::after { box-sizing: border-box; }\n.fmstr-cmp-ffh-a11y__container { max-width: 820px; margin: 0 auto; }\n.fmstr-cmp-ffh-a11y__head { margin: 0 0 28px; }\n.fmstr-cmp-ffh-a11y__eyebrow {\ndisplay: inline-block; padding: 5px 12px; border-radius: 9999px;\nbackground: var(--fmstr-cmp-ffh-a11y-tint); color: var(--fmstr-cmp-ffh-a11y-violet-600);\nfont-size: 12px; font-weight: 600; letter-spacing: .04em;\ntext-transform: uppercase; border: 1px solid var(--fmstr-cmp-ffh-a11y-edge); margin: 0 0 14px;\n}\n.fmstr-cmp-ffh-a11y__h2 { font-size: clamp(26px, 3vw, 36px); font-weight: 700; line-height: 1.15; letter-spacing: -.02em; margin: 0; }\n.fmstr-cmp-ffh-a11y__intro { color: var(--fmstr-cmp-ffh-a11y-fg-3); font-size: 17px; line-height: 1.6; margin: 14px 0 0; }\n\n.fmstr-cmp-ffh-a11y__list { display: flex; flex-direction: column; gap: 16px; }\n.fmstr-cmp-ffh-a11y__item {\nbackground: var(--fmstr-cmp-ffh-a11y-bg-card);\nborder: 1px solid var(--fmstr-cmp-ffh-a11y-border);\nborder-radius: 16px; padding: 22px 24px;\ndisplay: grid; grid-template-columns: 44px 1fr 1fr; gap: 20px; align-items: start;\nbox-shadow: var(--fmstr-cmp-ffh-a11y-shadow);\n}\n.fmstr-cmp-ffh-a11y__num {\nwidth: 36px; height: 36px; border-radius: 10px;\nbackground: var(--fmstr-cmp-ffh-a11y-tint);\ncolor: var(--fmstr-cmp-ffh-a11y-violet-600);\ndisplay: grid; place-items: center;\nfont-weight: 700; font-size: 15px;\nborder: 1px solid var(--fmstr-cmp-ffh-a11y-edge);\n}\n\n.fmstr-cmp-ffh-a11y__copy h3 {\nfont-size: 17px; font-weight: 600; letter-spacing: -.01em;\ncolor: var(--fmstr-cmp-ffh-a11y-fg-1); margin: 0 0 6px;\n}\n.fmstr-cmp-ffh-a11y__copy p { color: var(--fmstr-cmp-ffh-a11y-fg-2); font-size: 14.5px; line-height: 1.6; margin: 0; }\n.fmstr-cmp-ffh-a11y__copy strong { color: var(--fmstr-cmp-ffh-a11y-fg-1); font-weight: 600; }\n\n.fmstr-cmp-ffh-a11y__pair { display: flex; flex-direction: column; gap: 10px; }\n.fmstr-cmp-ffh-a11y__codebox {\nbackground: var(--fmstr-cmp-ffh-a11y-bg-code);\nborder-radius: 8px; padding: 10px 12px;\nfont-family: ui-monospace, Menlo, Monaco, monospace;\nfont-size: 11.5px; line-height: 1.55;\ncolor: #e2e8f0; overflow-x: auto; margin: 0;\nwhite-space: pre; position: relative; padding-left: 50px;\n}\n.fmstr-cmp-ffh-a11y__codebox code { font-family: inherit; }\n.fmstr-cmp-ffh-a11y__codebox::before {\ncontent: \"\"; position: absolute; left: 10px; top: 11px;\nwidth: 14px; height: 14px; border-radius: 50%;\nbackground-repeat: no-repeat; background-position: center;\n}\n.fmstr-cmp-ffh-a11y__codebox--bad::before { background-color: var(--fmstr-cmp-ffh-a11y-red-bg); background-image: url(\"data:image\u002Fsvg+xml,%3Csvg xmlns='http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg' width='8' height='8' viewBox='0 0 8 8' fill='none' stroke='%23b91c1c' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='M1.5 1.5 L6.5 6.5 M6.5 1.5 L1.5 6.5'\u002F%3E%3C\u002Fsvg%3E\"); }\n.fmstr-cmp-ffh-a11y__codebox--good::before { background-color: var(--fmstr-cmp-ffh-a11y-green-bg); background-image: url(\"data:image\u002Fsvg+xml,%3Csvg xmlns='http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg' width='9' height='9' viewBox='0 0 9 9' fill='none' stroke='%2315803d' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M1.5 4.5 L3.5 6.5 L7 3'\u002F%3E%3C\u002Fsvg%3E\"); }\n.fmstr-cmp-ffh-a11y__codebox-label {\nposition: absolute; top: 11px; left: 28px;\nfont-size: 9px; font-weight: 700; letter-spacing: .08em;\ntext-transform: uppercase;\n}\n.fmstr-cmp-ffh-a11y__codebox--bad .fmstr-cmp-ffh-a11y__codebox-label { color: var(--fmstr-cmp-ffh-a11y-red); }\n.fmstr-cmp-ffh-a11y__codebox--good .fmstr-cmp-ffh-a11y__codebox-label { color: var(--fmstr-cmp-ffh-a11y-green); }\n\n.fmstr-cmp-ffh-a11y__codebox .t { color: #f472b6; }\n.fmstr-cmp-ffh-a11y__codebox .a { color: #a5b4fc; }\n.fmstr-cmp-ffh-a11y__codebox .s { color: #86efac; }\n\n.fmstr-cmp-ffh-a11y__foot {\nmargin: 28px auto 0; max-width: 760px; text-align: center;\ncolor: var(--fmstr-cmp-ffh-a11y-fg-3); font-size: 14.5px; line-height: 1.6;\n}\n.fmstr-cmp-ffh-a11y__foot a { color: var(--fmstr-cmp-ffh-a11y-violet-600) !important; font-weight: 600; }\n.fmstr-cmp-ffh-a11y__foot a:hover { text-decoration: underline !important; }\n\n@media (max-width: 880px) {\n.fmstr-cmp-ffh-a11y__item { grid-template-columns: 36px 1fr; gap: 16px; }\n.fmstr-cmp-ffh-a11y__pair { grid-column: 1 \u002F -1; }\n}\n@media (max-width: 760px) {\n.fmstr-cmp-ffh-a11y { padding: 40px 16px; }\n.fmstr-cmp-ffh-a11y__item { padding: 18px; border-radius: 14px; }\n.fmstr-cmp-ffh-a11y__intro { font-size: 15.5px; }\n.fmstr-cmp-ffh-a11y__codebox { font-size: 11px; }\n}\n\u003C\u002Fstyle>\n\n\u003Csection class=\"fmstr-cmp-ffh-a11y\" aria-labelledby=\"fmstr-cmp-ffh-a11y-h2\">\n\u003Cdiv class=\"fmstr-cmp-ffh-a11y__container\">\n\u003Cdiv class=\"fmstr-cmp-ffh-a11y__head\">\n\u003Cspan class=\"fmstr-cmp-ffh-a11y__eyebrow\">Five flags worth catching\u003C\u002Fspan>\n\u003Ch2 class=\"fmstr-cmp-ffh-a11y__h2\" id=\"fmstr-cmp-ffh-a11y-h2\">Accessibility checklist for an HTML feedback form\u003C\u002Fh2>\n\u003Cp class=\"fmstr-cmp-ffh-a11y__intro\">Every item below is something keyboard and screen-reader users actually hit. Skip these and a measurable chunk of your audience can&rsquo;t complete the form.\u003C\u002Fp>\n\u003C\u002Fdiv>\n\n\u003Cdiv class=\"fmstr-cmp-ffh-a11y__list\">\n\n\u003Carticle class=\"fmstr-cmp-ffh-a11y__item\">\n\u003Cdiv class=\"fmstr-cmp-ffh-a11y__num\">1\u003C\u002Fdiv>\n\u003Cdiv class=\"fmstr-cmp-ffh-a11y__copy\">\n\u003Ch3>Pair every label with its input\u003C\u002Fh3>\n\u003Cp>The label&rsquo;s \u003Ccode>for\u003C\u002Fcode> must match the input&rsquo;s \u003Ccode>id\u003C\u002Fcode>. Click the label, focus the input. Screen readers announce the label out loud. Skip this and the form fails WCAG 2.1 and loses keyboard users.\u003C\u002Fp>\n\u003C\u002Fdiv>\n\u003Cdiv class=\"fmstr-cmp-ffh-a11y__pair\">\n\u003Cpre class=\"fmstr-cmp-ffh-a11y__codebox fmstr-cmp-ffh-a11y__codebox--bad\">\u003Cspan class=\"fmstr-cmp-ffh-a11y__codebox-label\">No\u003C\u002Fspan>\u003Ccode>\u003Cspan class=\"t\">&lt;label&gt;\u003C\u002Fspan>Email\u003Cspan class=\"t\">&lt;\u002Flabel&gt;\u003C\u002Fspan>\n\u003Cspan class=\"t\">&lt;input\u003C\u002Fspan> \u003Cspan class=\"a\">type\u003C\u002Fspan>=\u003Cspan class=\"s\">\"email\"\u003C\u002Fspan>\u003Cspan class=\"t\">&gt;\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cpre class=\"fmstr-cmp-ffh-a11y__codebox fmstr-cmp-ffh-a11y__codebox--good\">\u003Cspan class=\"fmstr-cmp-ffh-a11y__codebox-label\">Yes\u003C\u002Fspan>\u003Ccode>\u003Cspan class=\"t\">&lt;label\u003C\u002Fspan> \u003Cspan class=\"a\">for\u003C\u002Fspan>=\u003Cspan class=\"s\">\"email\"\u003C\u002Fspan>\u003Cspan class=\"t\">&gt;\u003C\u002Fspan>Email\u003Cspan class=\"t\">&lt;\u002Flabel&gt;\u003C\u002Fspan>\n\u003Cspan class=\"t\">&lt;input\u003C\u002Fspan> \u003Cspan class=\"a\">id\u003C\u002Fspan>=\u003Cspan class=\"s\">\"email\"\u003C\u002Fspan> \u003Cspan class=\"a\">type\u003C\u002Fspan>=\u003Cspan class=\"s\">\"email\"\u003C\u002Fspan>\u003Cspan class=\"t\">&gt;\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C\u002Fdiv>\n\u003C\u002Farticle>\n\n\u003Carticle class=\"fmstr-cmp-ffh-a11y__item\">\n\u003Cdiv class=\"fmstr-cmp-ffh-a11y__num\">2\u003C\u002Fdiv>\n\u003Cdiv class=\"fmstr-cmp-ffh-a11y__copy\">\n\u003Ch3>Connect errors with \u003Ccode>aria-describedby\u003C\u002Fcode>\u003C\u002Fh3>\n\u003Cp>An invalid field needs \u003Ccode>aria-invalid=\"true\"\u003C\u002Fcode> plus an \u003Ccode>aria-describedby\u003C\u002Fcode> that points at the visible error message. Screen readers then announce the error along with the field name on focus.\u003C\u002Fp>\n\u003C\u002Fdiv>\n\u003Cdiv class=\"fmstr-cmp-ffh-a11y__pair\">\n\u003Cpre class=\"fmstr-cmp-ffh-a11y__codebox fmstr-cmp-ffh-a11y__codebox--bad\">\u003Cspan class=\"fmstr-cmp-ffh-a11y__codebox-label\">No\u003C\u002Fspan>\u003Ccode>\u003Cspan class=\"t\">&lt;input\u003C\u002Fspan> \u003Cspan class=\"a\">id\u003C\u002Fspan>=\u003Cspan class=\"s\">\"email\"\u003C\u002Fspan>\u003Cspan class=\"t\">&gt;\u003C\u002Fspan>\n\u003Cspan class=\"t\">&lt;span&gt;\u003C\u002Fspan>Invalid email\u003Cspan class=\"t\">&lt;\u002Fspan&gt;\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cpre class=\"fmstr-cmp-ffh-a11y__codebox fmstr-cmp-ffh-a11y__codebox--good\">\u003Cspan class=\"fmstr-cmp-ffh-a11y__codebox-label\">Yes\u003C\u002Fspan>\u003Ccode>\u003Cspan class=\"t\">&lt;input\u003C\u002Fspan> \u003Cspan class=\"a\">id\u003C\u002Fspan>=\u003Cspan class=\"s\">\"email\"\u003C\u002Fspan>\n\u003Cspan class=\"a\">aria-invalid\u003C\u002Fspan>=\u003Cspan class=\"s\">\"true\"\u003C\u002Fspan>\n\u003Cspan class=\"a\">aria-describedby\u003C\u002Fspan>=\u003Cspan class=\"s\">\"email-error\"\u003C\u002Fspan>\u003Cspan class=\"t\">&gt;\u003C\u002Fspan>\n\u003Cspan class=\"t\">&lt;span\u003C\u002Fspan> \u003Cspan class=\"a\">id\u003C\u002Fspan>=\u003Cspan class=\"s\">\"email-error\"\u003C\u002Fspan>\u003Cspan class=\"t\">&gt;\u003C\u002Fspan>Invalid email\u003Cspan class=\"t\">&lt;\u002Fspan&gt;\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C\u002Fdiv>\n\u003C\u002Farticle>\n\n\u003Carticle class=\"fmstr-cmp-ffh-a11y__item\">\n\u003Cdiv class=\"fmstr-cmp-ffh-a11y__num\">3\u003C\u002Fdiv>\n\u003Cdiv class=\"fmstr-cmp-ffh-a11y__copy\">\n\u003Ch3>Use \u003Ccode>autocomplete\u003C\u002Fcode> tokens\u003C\u002Fh3>\n\u003Cp>One line per field. Browsers prefill from saved info, password managers behave, and assistive tech recognizes the field&rsquo;s purpose. Measurable lift in completion rate on mobile.\u003C\u002Fp>\n\u003C\u002Fdiv>\n\u003Cdiv class=\"fmstr-cmp-ffh-a11y__pair\">\n\u003Cpre class=\"fmstr-cmp-ffh-a11y__codebox fmstr-cmp-ffh-a11y__codebox--bad\">\u003Cspan class=\"fmstr-cmp-ffh-a11y__codebox-label\">No\u003C\u002Fspan>\u003Ccode>\u003Cspan class=\"t\">&lt;input\u003C\u002Fspan> \u003Cspan class=\"a\">type\u003C\u002Fspan>=\u003Cspan class=\"s\">\"text\"\u003C\u002Fspan> \u003Cspan class=\"a\">name\u003C\u002Fspan>=\u003Cspan class=\"s\">\"name\"\u003C\u002Fspan>\u003Cspan class=\"t\">&gt;\u003C\u002Fspan>\n\u003Cspan class=\"t\">&lt;input\u003C\u002Fspan> \u003Cspan class=\"a\">type\u003C\u002Fspan>=\u003Cspan class=\"s\">\"email\"\u003C\u002Fspan> \u003Cspan class=\"a\">name\u003C\u002Fspan>=\u003Cspan class=\"s\">\"email\"\u003C\u002Fspan>\u003Cspan class=\"t\">&gt;\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cpre class=\"fmstr-cmp-ffh-a11y__codebox fmstr-cmp-ffh-a11y__codebox--good\">\u003Cspan class=\"fmstr-cmp-ffh-a11y__codebox-label\">Yes\u003C\u002Fspan>\u003Ccode>\u003Cspan class=\"t\">&lt;input\u003C\u002Fspan> \u003Cspan class=\"a\">type\u003C\u002Fspan>=\u003Cspan class=\"s\">\"text\"\u003C\u002Fspan> \u003Cspan class=\"a\">name\u003C\u002Fspan>=\u003Cspan class=\"s\">\"name\"\u003C\u002Fspan>\n\u003Cspan class=\"a\">autocomplete\u003C\u002Fspan>=\u003Cspan class=\"s\">\"name\"\u003C\u002Fspan>\u003Cspan class=\"t\">&gt;\u003C\u002Fspan>\n\u003Cspan class=\"t\">&lt;input\u003C\u002Fspan> \u003Cspan class=\"a\">type\u003C\u002Fspan>=\u003Cspan class=\"s\">\"email\"\u003C\u002Fspan> \u003Cspan class=\"a\">name\u003C\u002Fspan>=\u003Cspan class=\"s\">\"email\"\u003C\u002Fspan>\n\u003Cspan class=\"a\">autocomplete\u003C\u002Fspan>=\u003Cspan class=\"s\">\"email\"\u003C\u002Fspan>\u003Cspan class=\"t\">&gt;\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C\u002Fdiv>\n\u003C\u002Farticle>\n\n\u003Carticle class=\"fmstr-cmp-ffh-a11y__item\">\n\u003Cdiv class=\"fmstr-cmp-ffh-a11y__num\">4\u003C\u002Fdiv>\n\u003Cdiv class=\"fmstr-cmp-ffh-a11y__copy\">\n\u003Ch3>Keep focus outlines visible\u003C\u002Fh3>\n\u003Cp>\u003Ccode>outline: none\u003C\u002Fcode> is the single most-copied CSS mistake on the web. It breaks keyboard navigation. Replace the default outline, never delete it. The visible ring is how a sighted keyboard user knows where they are.\u003C\u002Fp>\n\u003C\u002Fdiv>\n\u003Cdiv class=\"fmstr-cmp-ffh-a11y__pair\">\n\u003Cpre class=\"fmstr-cmp-ffh-a11y__codebox fmstr-cmp-ffh-a11y__codebox--bad\">\u003Cspan class=\"fmstr-cmp-ffh-a11y__codebox-label\">No\u003C\u002Fspan>\u003Ccode>input:focus { outline: none; }\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cpre class=\"fmstr-cmp-ffh-a11y__codebox fmstr-cmp-ffh-a11y__codebox--good\">\u003Cspan class=\"fmstr-cmp-ffh-a11y__codebox-label\">Yes\u003C\u002Fspan>\u003Ccode>input:focus {\noutline: 2px solid #5b6cff;\noutline-offset: 1px;\n}\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C\u002Fdiv>\n\u003C\u002Farticle>\n\n\u003Carticle class=\"fmstr-cmp-ffh-a11y__item\">\n\u003Cdiv class=\"fmstr-cmp-ffh-a11y__num\">5\u003C\u002Fdiv>\n\u003Cdiv class=\"fmstr-cmp-ffh-a11y__copy\">\n\u003Ch3>Mark required fields semantically\u003C\u002Fh3>\n\u003Cp>The native \u003Ccode>required\u003C\u002Fcode> attribute does two jobs at once: it tells the browser to block submission and tells screen readers the field is required. Don&rsquo;t fake it with just a red asterisk in the label.\u003C\u002Fp>\n\u003C\u002Fdiv>\n\u003Cdiv class=\"fmstr-cmp-ffh-a11y__pair\">\n\u003Cpre class=\"fmstr-cmp-ffh-a11y__codebox fmstr-cmp-ffh-a11y__codebox--bad\">\u003Cspan class=\"fmstr-cmp-ffh-a11y__codebox-label\">No\u003C\u002Fspan>\u003Ccode>\u003Cspan class=\"t\">&lt;label&gt;\u003C\u002Fspan>Email \u003Cspan class=\"t\">&lt;span&gt;\u003C\u002Fspan>*\u003Cspan class=\"t\">&lt;\u002Fspan&gt;&lt;\u002Flabel&gt;\u003C\u002Fspan>\n\u003Cspan class=\"t\">&lt;input\u003C\u002Fspan> \u003Cspan class=\"a\">type\u003C\u002Fspan>=\u003Cspan class=\"s\">\"email\"\u003C\u002Fspan>\u003Cspan class=\"t\">&gt;\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cpre class=\"fmstr-cmp-ffh-a11y__codebox fmstr-cmp-ffh-a11y__codebox--good\">\u003Cspan class=\"fmstr-cmp-ffh-a11y__codebox-label\">Yes\u003C\u002Fspan>\u003Ccode>\u003Cspan class=\"t\">&lt;label\u003C\u002Fspan> \u003Cspan class=\"a\">for\u003C\u002Fspan>=\u003Cspan class=\"s\">\"email\"\u003C\u002Fspan>\u003Cspan class=\"t\">&gt;\u003C\u002Fspan>Email (required)\u003Cspan class=\"t\">&lt;\u002Flabel&gt;\u003C\u002Fspan>\n\u003Cspan class=\"t\">&lt;input\u003C\u002Fspan> \u003Cspan class=\"a\">id\u003C\u002Fspan>=\u003Cspan class=\"s\">\"email\"\u003C\u002Fspan> \u003Cspan class=\"a\">type\u003C\u002Fspan>=\u003Cspan class=\"s\">\"email\"\u003C\u002Fspan> \u003Cspan class=\"a\">required\u003C\u002Fspan>\u003Cspan class=\"t\">&gt;\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C\u002Fdiv>\n\u003C\u002Farticle>\n\n\u003C\u002Fdiv>\n\n\u003Cp class=\"fmstr-cmp-ffh-a11y__foot\">For edge cases (fieldsets, error summaries, custom controls), the \u003Ca href=\"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FHTML\u002FReference\u002FElements\u002Fform\">MDN \u003Ccode>&lt;form&gt;\u003C\u002Fcode> reference\u003C\u002Fa> is the canonical source.\u003C\u002Fp>\n\u003C\u002Fdiv>\n\u003C\u002Fsection>\n\n\u003Cstyle>\n\u002F* host-link-override *\u002F\n.fmstr-cmp-ffh-faq a { text-decoration: none !important; }\n.fmstr-cmp-ffh-faq {\n--c-bg: #fafafb; --c-card: #ffffff;\n--c-fg-1: #101828; --c-fg-2: #475467;\n--c-violet-600: #6941c6; --c-tint: #f7f3ff; --c-edge: #e4d7ff;\n--c-border: #eaecf0; --c-chip-bg: #f4f4f7;\n--c-shadow: 0 1px 3px rgba(16,24,40,.05);\n\nbackground: transparent; padding: 56px 24px;\nfont-family: inherit;\ncolor: var(--c-fg-1);\n}\n.fmstr-cmp-ffh-faq *, .fmstr-cmp-ffh-faq *::before, .fmstr-cmp-ffh-faq *::after { box-sizing: border-box; }\n.fmstr-cmp-ffh-faq__container { max-width: 820px; margin: 0 auto; }\n.fmstr-cmp-ffh-faq__h2 { font-size: clamp(26px, 3vw, 36px); font-weight: 700; line-height: 1.15; letter-spacing: -.02em; margin: 0; color: var(--c-fg-1); }\n.fmstr-cmp-ffh-faq__intro { color: #697586; font-size: 17px; line-height: 1.6; margin: 14px 0 28px; max-width: 760px; }\n.fmstr-cmp-ffh-faq__list { display: flex; flex-direction: column; gap: 12px; }\n.fmstr-cmp-ffh-faq__item {\nbackground: var(--c-card); border: 1px solid var(--c-border);\nborder-radius: 14px; box-shadow: var(--c-shadow); overflow: hidden;\n}\n.fmstr-cmp-ffh-faq__item > summary {\npadding: 18px 22px; cursor: pointer; font-weight: 600; font-size: 16.5px;\ncolor: var(--c-fg-1); display: flex; align-items: center; gap: 14px;\nlist-style: none;\n}\n.fmstr-cmp-ffh-faq__item > summary::-webkit-details-marker { display: none; }\n.fmstr-cmp-ffh-faq__item > summary::before {\ncontent: \"\"; width: 28px; height: 28px; border-radius: 8px; flex-shrink: 0;\nbackground-color: var(--c-chip-bg);\nbackground-image: url(\"data:image\u002Fsvg+xml,%3Csvg xmlns='http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg' width='14' height='14' viewBox='0 0 14 14' fill='none' stroke='%2375747f' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 5l4 4 4-4'\u002F%3E%3C\u002Fsvg%3E\");\nbackground-repeat: no-repeat; background-position: center;\ntransition: transform .15s ease, background-color .15s ease;\n}\n.fmstr-cmp-ffh-faq__item[open] > summary::before { transform: rotate(180deg); background-color: var(--c-tint); }\n.fmstr-cmp-ffh-faq__item[open] > summary { color: var(--c-violet-600); }\n.fmstr-cmp-ffh-faq__answer { padding: 0 22px 22px 64px; color: var(--c-fg-2); font-size: 15.5px; line-height: 1.7; }\n.fmstr-cmp-ffh-faq__answer a { color: var(--c-violet-600) !important; text-decoration: none !important; }\n.fmstr-cmp-ffh-faq__answer a:hover { text-decoration: underline !important; }\n.fmstr-cmp-ffh-faq__answer code {\nbackground: var(--c-chip-bg); padding: 1px 6px; border-radius: 4px;\nfont-family: ui-monospace, Menlo, Monaco, monospace; font-size: 13.5px;\ncolor: var(--c-violet-600);\n}\n\n@media (max-width: 760px) {\n.fmstr-cmp-ffh-faq { padding: 40px 16px; }\n.fmstr-cmp-ffh-faq__intro { font-size: 15.5px; }\n.fmstr-cmp-ffh-faq__item > summary { padding: 16px 16px; font-size: 15.5px; gap: 12px; }\n.fmstr-cmp-ffh-faq__item > summary::before { width: 26px; height: 26px; }\n.fmstr-cmp-ffh-faq__answer { padding: 0 16px 18px 16px; font-size: 15px; line-height: 1.65; }\n}\n\u003C\u002Fstyle>\n\n\u003Csection class=\"fmstr-cmp-ffh-faq\" aria-labelledby=\"fmstr-cmp-ffh-faq-h2\">\n\u003Cdiv class=\"fmstr-cmp-ffh-faq__container\">\n\u003Ch2 class=\"fmstr-cmp-ffh-faq__h2\" id=\"fmstr-cmp-ffh-faq-h2\">HTML feedback form FAQ\u003C\u002Fh2>\n\u003Cp class=\"fmstr-cmp-ffh-faq__intro\">Answers that mirror the FAQPage JSON-LD on the live page.\u003C\u002Fp>\n\u003Cdiv class=\"fmstr-cmp-ffh-faq__list\">\n\n\u003Cdetails class=\"fmstr-cmp-ffh-faq__item\">\n\u003Csummary>How do you add a feedback form in HTML?\u003C\u002Fsummary>\n\u003Cdiv class=\"fmstr-cmp-ffh-faq__answer\">Use a \u003Ccode>&lt;form&gt;\u003C\u002Fcode> element with \u003Ccode>action\u003C\u002Fcode> set to your submission endpoint and \u003Ccode>method=\"post\"\u003C\u002Fcode>. Inside the form, add labeled \u003Ccode>&lt;input&gt;\u003C\u002Fcode> and \u003Ccode>&lt;textarea&gt;\u003C\u002Fcode> elements with \u003Ccode>name\u003C\u002Fcode> attributes. Style with CSS, validate with JavaScript, and point the \u003Ccode>action\u003C\u002Fcode> at a backend (your server, or a service like \u003Ca href=\"https:\u002F\u002Fformester.com\u002Ffeatures\u002Fhtml-form-backend\u002F\">Formester&rsquo;s HTML form backend\u003C\u002Fa>). The complete copy-paste example above is the shortest working version.\u003C\u002Fdiv>\n\u003C\u002Fdetails>\n\n\u003Cdetails class=\"fmstr-cmp-ffh-faq__item\">\n\u003Csummary>How do I create a feedback form?\u003C\u002Fsummary>\n\u003Cdiv class=\"fmstr-cmp-ffh-faq__answer\">Decide what to ask (name, email, rating, open-ended feedback are the standard four). Write the HTML using a \u003Ccode>&lt;form&gt;\u003C\u002Fcode> with one labeled input per question. Style it with CSS so it matches your site. Hook the \u003Ccode>action\u003C\u002Fcode> to a backend that stores submissions. The full process is the six steps above, or skip ahead to \u003Ca href=\"https:\u002F\u002Fformester.com\u002Ffeatures\u002Fdrag-and-drop-form-builder\u002F\">Formester&rsquo;s drag-and-drop builder\u003C\u002Fa> if you&rsquo;d rather not write code.\u003C\u002Fdiv>\n\u003C\u002Fdetails>\n\n\u003Cdetails class=\"fmstr-cmp-ffh-faq__item\">\n\u003Csummary>How do I create an inquiry form in HTML?\u003C\u002Fsummary>\n\u003Cdiv class=\"fmstr-cmp-ffh-faq__answer\">Same pattern as a feedback form, with different field labels. Swap \"How was your experience?\" for \"What are you interested in?\" and \"Your feedback\" for \"Your message.\" Keep the name, email, and submit-button structure identical. For a longer inquiry form with subject lines and contact preferences, the \u003Ca href=\"https:\u002F\u002Fformester.com\u002Fblog\u002Fcontact-form-design-tips-best-practices-and-examples\u002F\">contact form design best practices guide\u003C\u002Fa> covers the patterns.\u003C\u002Fdiv>\n\u003C\u002Fdetails>\n\n\u003Cdetails class=\"fmstr-cmp-ffh-faq__item\">\n\u003Csummary>How do you add a comment to a form in HTML?\u003C\u002Fsummary>\n\u003Cdiv class=\"fmstr-cmp-ffh-faq__answer\">Two meanings. (1) An HTML comment for developers: \u003Ccode>&lt;!-- this is the feedback section --&gt;\u003C\u002Fcode> between elements. (2) A user-facing comment field: a \u003Ccode>&lt;textarea&gt;\u003C\u002Fcode> with a label like \"Your comments.\" If you want comments to be optional, leave off the \u003Ccode>required\u003C\u002Fcode> attribute. Use \u003Ccode>rows\u003C\u002Fcode> and \u003Ccode>cols\u003C\u002Fcode> (or CSS height) to size the box.\u003C\u002Fdiv>\n\u003C\u002Fdetails>\n\n\u003Cdetails class=\"fmstr-cmp-ffh-faq__item\">\n\u003Csummary>How do I add CSS to a feedback form?\u003C\u002Fsummary>\n\u003Cdiv class=\"fmstr-cmp-ffh-faq__answer\">Two options. Inline \u003Ccode>&lt;style&gt;\u003C\u002Fcode> tags inside \u003Ccode>&lt;head&gt;\u003C\u002Fcode> work fine for one-off pages. For any real site, link an external stylesheet with \u003Ccode>&lt;link rel=\"stylesheet\" href=\"styles.css\"&gt;\u003C\u002Fcode>. Style the \u003Ccode>form\u003C\u002Fcode>, \u003Ccode>label\u003C\u002Fcode>, \u003Ccode>input\u003C\u002Fcode>, \u003Ccode>textarea\u003C\u002Fcode>, and \u003Ccode>button\u003C\u002Fcode> selectors directly. Step 3 above ships a complete starter stylesheet you can paste, including focus rings and inline error styles.\u003C\u002Fdiv>\n\u003C\u002Fdetails>\n\n\u003Cdetails class=\"fmstr-cmp-ffh-faq__item\">\n\u003Csummary>How do I add JavaScript validation without breaking accessibility?\u003C\u002Fsummary>\n\u003Cdiv class=\"fmstr-cmp-ffh-faq__answer\">Use \u003Ccode>aria-invalid=\"true\"\u003C\u002Fcode> on invalid fields, \u003Ccode>aria-describedby\u003C\u002Fcode> to point at the inline error message, and move focus to the first invalid field on submit failure. Avoid \u003Ccode>alert()\u003C\u002Fcode> boxes, they break screen-reader flow. The Step 4 JavaScript and the complete example above are accessibility-tested versions you can paste directly. Always re-validate on the server too, since a user with DevTools open can bypass client-side checks.\u003C\u002Fdiv>\n\u003C\u002Fdetails>\n\n\u003C\u002Fdiv>\n\u003C\u002Fdiv>\n\u003C\u002Fsection>\n\n\u003Cstyle>\n\u002F* host-link-override *\u002F\n.fmstr-cmp-ffh-vid a { text-decoration: none !important; }\n.fmstr-cmp-ffh-vid {\n--c-bg-card: #ffffff;\n--c-fg-1: #101828; --c-fg-2: #475467; --c-fg-3: #697586;\n--c-violet-500: #7f56d9; --c-violet-600: #6941c6;\n--c-tint: #f7f3ff; --c-edge: #e4d7ff; --c-border: #eaecf0;\n--c-shadow: 0 4px 20px rgba(16,24,40,.06), 0 2px 6px rgba(16,24,40,.04);\n\nbackground: transparent; padding: 56px 24px;\nfont-family: inherit;\ncolor: var(--c-fg-1);\n}\n.fmstr-cmp-ffh-vid *, .fmstr-cmp-ffh-vid *::before, .fmstr-cmp-ffh-vid *::after { box-sizing: border-box; }\n.fmstr-cmp-ffh-vid__container { max-width: 820px; margin: 0 auto; }\n.fmstr-cmp-ffh-vid__head { margin: 0 0 24px; }\n.fmstr-cmp-ffh-vid__eyebrow {\ndisplay: inline-block; padding: 5px 12px; border-radius: 9999px;\nbackground: var(--c-tint); color: var(--c-violet-600);\nfont-size: 12px; font-weight: 600; letter-spacing: .04em;\ntext-transform: uppercase; border: 1px solid var(--c-edge); margin: 0 0 14px;\n}\n.fmstr-cmp-ffh-vid__h2 { font-size: clamp(24px, 2.8vw, 32px); font-weight: 700; line-height: 1.15; letter-spacing: -.02em; margin: 0; color: var(--c-fg-1); }\n.fmstr-cmp-ffh-vid__sub { color: var(--c-fg-3); font-size: 16px; line-height: 1.6; margin: 12px 0 0; }\n.fmstr-cmp-ffh-vid__frame {\nposition: relative; aspect-ratio: 16 \u002F 9; border-radius: 20px; overflow: hidden;\nbackground: var(--c-tint); border: 1px solid var(--c-border); box-shadow: var(--c-shadow);\n}\n.fmstr-cmp-ffh-vid__frame iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }\n.fmstr-cmp-ffh-vid__caption { color: var(--c-fg-3); font-size: 14px; line-height: 1.6; text-align: center; margin: 16px 0 0; }\n.fmstr-cmp-ffh-vid__caption a { color: var(--c-violet-600) !important; text-decoration: none !important; }\n.fmstr-cmp-ffh-vid__caption a:hover { text-decoration: underline !important; }\n.fmstr-cmp-ffh-vid__caption code {\nbackground: var(--c-tint); padding: 1px 6px; border-radius: 4px;\nfont-family: ui-monospace, Menlo, Monaco, monospace; font-size: 13px;\ncolor: var(--c-violet-600);\n}\n\n@media (max-width: 760px) {\n.fmstr-cmp-ffh-vid { padding: 40px 16px; }\n.fmstr-cmp-ffh-vid__sub { font-size: 15px; }\n.fmstr-cmp-ffh-vid__frame { border-radius: 16px; }\n.fmstr-cmp-ffh-vid__caption { font-size: 13.5px; }\n}\n\u003C\u002Fstyle>\n\n\u003Csection class=\"fmstr-cmp-ffh-vid\" aria-labelledby=\"fmstr-cmp-ffh-vid-h2\">\n\u003Cdiv class=\"fmstr-cmp-ffh-vid__container\">\n\u003Cdiv class=\"fmstr-cmp-ffh-vid__head\">\n\u003Cspan class=\"fmstr-cmp-ffh-vid__eyebrow\">Three-minute walkthrough\u003C\u002Fspan>\n\u003Ch2 class=\"fmstr-cmp-ffh-vid__h2\" id=\"fmstr-cmp-ffh-vid-h2\">Watch the full HTML feedback form built from scratch\u003C\u002Fh2>\n\u003Cp class=\"fmstr-cmp-ffh-vid__sub\">Structure, CSS, accessible validation, backend swap. All six steps in one short video.\u003C\u002Fp>\n\u003C\u002Fdiv>\n\u003Cdiv class=\"fmstr-cmp-ffh-vid__frame\">\n\u003Ciframe src=\"https:\u002F\u002Fwww.youtube.com\u002Fembed\u002F8FC3c5Cv5ew\" title=\"How to make a feedback form in HTML\" loading=\"lazy\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen>\u003C\u002Fiframe>\n\u003C\u002Fdiv>\n\u003Cp class=\"fmstr-cmp-ffh-vid__caption\">Prefer reading? The full tutorial is below with copy-paste blocks. To skip the backend setup entirely, point the form&rsquo;s \u003Ccode>action\u003C\u002Fcode> at \u003Ca href=\"https:\u002F\u002Fformester.com\u002Ffeatures\u002Fhtml-form-backend\u002F\">Formester&rsquo;s HTML form backend\u003C\u002Fa>.\u003C\u002Fp>\n\u003C\u002Fdiv>\n\u003C\u002Fsection>\n\n\u003Cstyle>\n\u002F* host-link-override *\u002F\n.fmstr-cmp-ffh-rel a { text-decoration: none !important; }\n.fmstr-cmp-ffh-rel {\n--c-bg: #f4f4f7; --c-card: #ffffff;\n--c-fg-1: #101828; --c-fg-2: #475467; --c-fg-3: #697586;\n--c-violet-500: #7f56d9; --c-violet-600: #6941c6;\n--c-tint: #f7f3ff; --c-edge: #e4d7ff; --c-border: #eaecf0;\n--c-shadow: 0 4px 20px rgba(16,24,40,.06);\n\nbackground: transparent; padding: 56px 24px;\nfont-family: inherit;\ncolor: var(--c-fg-1);\n}\n.fmstr-cmp-ffh-rel *, .fmstr-cmp-ffh-rel *::before, .fmstr-cmp-ffh-rel *::after { box-sizing: border-box; }\n.fmstr-cmp-ffh-rel__container { max-width: 820px; margin: 0 auto; }\n.fmstr-cmp-ffh-rel__head { margin: 0 0 28px; }\n.fmstr-cmp-ffh-rel__h2 { font-size: clamp(26px, 3vw, 36px); font-weight: 700; line-height: 1.15; letter-spacing: -.02em; margin: 0; }\n.fmstr-cmp-ffh-rel__intro { color: var(--c-fg-3); font-size: 17px; line-height: 1.6; margin: 14px 0 0; }\n.fmstr-cmp-ffh-rel__grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }\n.fmstr-cmp-ffh-rel__card {\nbackground: var(--c-card); border: 1px solid var(--c-border);\nborder-radius: 14px; padding: 18px 20px; display: flex; align-items: center; gap: 14px;\ntext-decoration: none !important; color: inherit !important; transition: all .15s ease;\n}\n.fmstr-cmp-ffh-rel__card:hover { border-color: var(--c-edge); box-shadow: var(--c-shadow); transform: translateY(-1px); }\n.fmstr-cmp-ffh-rel__icon { width: 40px; height: 40px; border-radius: 10px; background: var(--c-tint); display: grid; place-items: center; flex-shrink: 0; font-size: 18px; border: 1px solid var(--c-edge); }\n.fmstr-cmp-ffh-rel__text { flex-grow: 1; }\n.fmstr-cmp-ffh-rel__text h4 { font-size: 14.5px; font-weight: 600; color: var(--c-fg-1); margin: 0; }\n.fmstr-cmp-ffh-rel__text small { font-size: 12.5px; color: var(--c-fg-3); display: block; margin-top: 2px; }\n.fmstr-cmp-ffh-rel__arrow { color: var(--c-violet-500); font-size: 18px; }\n\n@media (max-width: 880px) { .fmstr-cmp-ffh-rel__grid { grid-template-columns: 1fr 1fr; gap: 12px; } }\n@media (max-width: 760px) {\n.fmstr-cmp-ffh-rel { padding: 40px 16px; }\n.fmstr-cmp-ffh-rel__intro { font-size: 15.5px; }\n.fmstr-cmp-ffh-rel__card { padding: 16px; gap: 12px; }\n}\n@media (max-width: 540px) { .fmstr-cmp-ffh-rel__grid { grid-template-columns: 1fr; gap: 12px; } }\n\u003C\u002Fstyle>\n\n\u003Csection class=\"fmstr-cmp-ffh-rel\" aria-labelledby=\"fmstr-cmp-ffh-rel-h2\">\n\u003Cdiv class=\"fmstr-cmp-ffh-rel__container\">\n\u003Cdiv class=\"fmstr-cmp-ffh-rel__head\">\n\u003Ch2 class=\"fmstr-cmp-ffh-rel__h2\" id=\"fmstr-cmp-ffh-rel-h2\">More from Formester on HTML forms and feedback\u003C\u002Fh2>\n\u003Cp class=\"fmstr-cmp-ffh-rel__intro\">Pair this tutorial with the backend features, ready-made templates, and adjacent how-tos.\u003C\u002Fp>\n\u003C\u002Fdiv>\n\u003Cdiv class=\"fmstr-cmp-ffh-rel__grid\">\n\n\u003Ca class=\"fmstr-cmp-ffh-rel__card\" href=\"https:\u002F\u002Fformester.com\u002Ffeatures\u002Fhtml-form-backend\u002F\">\n\u003Cdiv class=\"fmstr-cmp-ffh-rel__icon\" aria-hidden=\"true\">&#128229;\u003C\u002Fdiv>\n\u003Cdiv class=\"fmstr-cmp-ffh-rel__text\">\u003Ch4>HTML Form Backend\u003C\u002Fh4>\u003Csmall>One \u003Ccode>action\u003C\u002Fcode> swap, no server\u003C\u002Fsmall>\u003C\u002Fdiv>\n\u003Cspan class=\"fmstr-cmp-ffh-rel__arrow\" aria-hidden=\"true\">&rarr;\u003C\u002Fspan>\n\u003C\u002Fa>\n\n\u003Ca class=\"fmstr-cmp-ffh-rel__card\" href=\"https:\u002F\u002Fformester.com\u002Ffeatures\u002Fembed-forms\u002F\">\n\u003Cdiv class=\"fmstr-cmp-ffh-rel__icon\" aria-hidden=\"true\">&#128279;\u003C\u002Fdiv>\n\u003Cdiv class=\"fmstr-cmp-ffh-rel__text\">\u003Ch4>Embed Forms\u003C\u002Fh4>\u003Csmall>Drop a form into any HTML page\u003C\u002Fsmall>\u003C\u002Fdiv>\n\u003Cspan class=\"fmstr-cmp-ffh-rel__arrow\" aria-hidden=\"true\">&rarr;\u003C\u002Fspan>\n\u003C\u002Fa>\n\n\u003Ca class=\"fmstr-cmp-ffh-rel__card\" href=\"https:\u002F\u002Fformester.com\u002Ffeatures\u002Fspam-protection\u002F\">\n\u003Cdiv class=\"fmstr-cmp-ffh-rel__icon\" aria-hidden=\"true\">&#128737;\u003C\u002Fdiv>\n\u003Cdiv class=\"fmstr-cmp-ffh-rel__text\">\u003Ch4>Spam Protection\u003C\u002Fh4>\u003Csmall>Honeypot + reCAPTCHA built in\u003C\u002Fsmall>\u003C\u002Fdiv>\n\u003Cspan class=\"fmstr-cmp-ffh-rel__arrow\" aria-hidden=\"true\">&rarr;\u003C\u002Fspan>\n\u003C\u002Fa>\n\n\u003Ca class=\"fmstr-cmp-ffh-rel__card\" href=\"https:\u002F\u002Fformester.com\u002Ftemplates\u002Fcustomer-feedback-form-31840\u002F\">\n\u003Cdiv class=\"fmstr-cmp-ffh-rel__icon\" aria-hidden=\"true\">&#11088;\u003C\u002Fdiv>\n\u003Cdiv class=\"fmstr-cmp-ffh-rel__text\">\u003Ch4>Customer Feedback Form\u003C\u002Fh4>\u003Csmall>Pre-built template\u003C\u002Fsmall>\u003C\u002Fdiv>\n\u003Cspan class=\"fmstr-cmp-ffh-rel__arrow\" aria-hidden=\"true\">&rarr;\u003C\u002Fspan>\n\u003C\u002Fa>\n\n\u003Ca class=\"fmstr-cmp-ffh-rel__card\" href=\"https:\u002F\u002Fformester.com\u002Ftemplates\u002Fcategories\u002Ffeedback-forms\u002F\">\n\u003Cdiv class=\"fmstr-cmp-ffh-rel__icon\" aria-hidden=\"true\">&#128196;\u003C\u002Fdiv>\n\u003Cdiv class=\"fmstr-cmp-ffh-rel__text\">\u003Ch4>All Feedback Templates\u003C\u002Fh4>\u003Csmall>Customer, product, employee\u003C\u002Fsmall>\u003C\u002Fdiv>\n\u003Cspan class=\"fmstr-cmp-ffh-rel__arrow\" aria-hidden=\"true\">&rarr;\u003C\u002Fspan>\n\u003C\u002Fa>\n\n\u003Ca class=\"fmstr-cmp-ffh-rel__card\" href=\"https:\u002F\u002Fformester.com\u002Fai-form-generator\u002F\">\n\u003Cdiv class=\"fmstr-cmp-ffh-rel__icon\" aria-hidden=\"true\">&#10024;\u003C\u002Fdiv>\n\u003Cdiv class=\"fmstr-cmp-ffh-rel__text\">\u003Ch4>AI Form Generator\u003C\u002Fh4>\u003Csmall>The no-code alternative\u003C\u002Fsmall>\u003C\u002Fdiv>\n\u003Cspan class=\"fmstr-cmp-ffh-rel__arrow\" aria-hidden=\"true\">&rarr;\u003C\u002Fspan>\n\u003C\u002Fa>\n\n\u003Ca class=\"fmstr-cmp-ffh-rel__card\" href=\"https:\u002F\u002Fformester.com\u002Fblog\u002Fhow-to-send-contact-form-data-to-google-sheets-free\u002F\">\n\u003Cdiv class=\"fmstr-cmp-ffh-rel__icon\" aria-hidden=\"true\">&#128203;\u003C\u002Fdiv>\n\u003Cdiv class=\"fmstr-cmp-ffh-rel__text\">\u003Ch4>Send form data to Google Sheets\u003C\u002Fh4>\u003Csmall>Free, step-by-step\u003C\u002Fsmall>\u003C\u002Fdiv>\n\u003Cspan class=\"fmstr-cmp-ffh-rel__arrow\" aria-hidden=\"true\">&rarr;\u003C\u002Fspan>\n\u003C\u002Fa>\n\n\u003Ca class=\"fmstr-cmp-ffh-rel__card\" href=\"https:\u002F\u002Fformester.com\u002Fblog\u002Fcontact-form-design-tips-best-practices-and-examples\u002F\">\n\u003Cdiv class=\"fmstr-cmp-ffh-rel__icon\" aria-hidden=\"true\">&#127912;\u003C\u002Fdiv>\n\u003Cdiv class=\"fmstr-cmp-ffh-rel__text\">\u003Ch4>Contact form design tips\u003C\u002Fh4>\u003Csmall>Best practices and examples\u003C\u002Fsmall>\u003C\u002Fdiv>\n\u003Cspan class=\"fmstr-cmp-ffh-rel__arrow\" aria-hidden=\"true\">&rarr;\u003C\u002Fspan>\n\u003C\u002Fa>\n\n\u003Ca class=\"fmstr-cmp-ffh-rel__card\" href=\"https:\u002F\u002Fformester.com\u002Fblog\u002Fhow-to-build-spam-free-contact-forms-for-your-website\u002F\">\n\u003Cdiv class=\"fmstr-cmp-ffh-rel__icon\" aria-hidden=\"true\">&#129302;\u003C\u002Fdiv>\n\u003Cdiv class=\"fmstr-cmp-ffh-rel__text\">\u003Ch4>Build spam-free contact forms\u003C\u002Fh4>\u003Csmall>Stop bots before they hit your inbox\u003C\u002Fsmall>\u003C\u002Fdiv>\n\u003Cspan class=\"fmstr-cmp-ffh-rel__arrow\" aria-hidden=\"true\">&rarr;\u003C\u002Fspan>\n\u003C\u002Fa>\n\n\u003C\u002Fdiv>\n\u003C\u002Fdiv>\n\u003C\u002Fsection>\n","blog\u002Fblog\u002Fhow-to-make-feedback-form-in-html.md",{"text":300},"16 min read",{"title":302,"author":32,"authorImage":8,"authorProfile":201,"coverImg":303,"coverImgAlt":304,"createdAt":305,"description":306,"featured":14,"jsonld":307,"keywords":308,"metaDescription":309,"metaImage":310,"metaTitle":311,"publishedAt":312,"slug":313,"updatedAt":314,"__hash__":315,"body":316,"id":317,"coverImgWidth":25,"coverImgHeight":26,"readingStats":318},"5 Best Budget Friendly Online Form Builders | No Code Form Builders","https:\u002F\u002Fformester-strapi.s3.ap-south-1.amazonaws.com\u002Fan_illustration_of_best_online_form_builders_89d3387856.png","an illustration of best online form builders","2025-01-16T04:22:50.249Z","Let's explore the 5 best online form builders that offer better features and a superior experience compared to Google Forms, all while being budget-friendly!",[],"best online form builders,\ngoogle forms alternatives,","Let's explore the 5 best budget friendly online form builders that offer better features and a superior experience compared to Google Forms.",[],"5 Best Budget Friendly Online Form Builders | No Code","2025-01-16T04:46:17.034Z","best-budget-friendly-online-form-builders","2025-08-20T01:23:59.197Z","KOLyHXCr2YWeLgP-KJdZOb3ANG4AVokViOcg_yRU5N0","\u003Ciframe width=\"813\" height=\"315\" src=\"https:\u002F\u002Fwww.youtube.com\u002Fembed\u002FYSW7MR3iiIk?si=A17cOkJr5ZhLMIVL\" title=\"YouTube video player\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen>\u003C\u002Fiframe>\n\nBuilding forms shouldn't feel like a chore. With so many amazing no-code form builders available, it's easier than ever to create surveys, quizzes, and forms tailored to your needs. **But which tool is the best fit for you?**\n\nIn this post, we’ll explore 5 best online form builders, Formester, Fillout, Tally. so, forms.app, and Cognito Forms. Plus, find the **[form builder comparison tool](\u002Fcomparison-tool\u002F)** to help you compare **30+ online form builders** side by side. Let’s dive in and find your perfect match!\n\n## Top Budget Friendly Online Form Builders\nBelow is the list of amazing formbuilder ranked based on ease of use, affordability and features they offer:\n\n### 1. [Formester](\u002F):\n\n![a mockup of formester](https:\u002F\u002Fformester-strapi.s3.ap-south-1.amazonaws.com\u002Fa_mockup_of_formester_d90793213b.png)\nFormester is by far the best no-code online form builder because it offers the easiest user interface, tons of premium features and unlimited forms.\n\nWith Formester, you can build any kind of form, survey, or quiz—from basic forms like contact forms to advanced research surveys and scoring quizzes.\n\nIt can easily integrate with any kind of third party app to automate your workflows.\nFeatures:\n\n#### AI Form Generator:\nFormester offers an easy-to-use **[AI form generator](\u002Fai-form-generator\u002F)** that helps you create any kind of form or survey in minutes using a simple prompt.\n\nSimply enter a prompt like “Generate a job application form,” click generate, and it will create the complete form for you.\n\n#### Payment Integration:\nWith Formester, you can easily **[collect payments](\u002Ffeatures\u002Fonline-payments\u002F)** from your users through Stripe and PayPal—perfect for online orders and applications.\n\n#### AI Auto Translation:\nIf you’re tired of manually creating forms or surveys in different languages, the **[AI auto translator](\u002Fai-powered-multilingual-forms\u002F)** will be a game-changer.\n\nWith just one click, you can translate an entire form or survey into all major languages. You can even let users choose the language they prefer to submit their form or survey.\n\n#### Form Limiter:\nFormester includes a built-in form limiter that allows you to set submission and date limits on your forms and surveys—perfect for time-sensitive campaigns or limited submissions.\n\n#### Pricing:\nFormester offers 4 plans:\n\n* A free plan.\n\n* Three premium plans starting at **12$\u002Fmo**.\n\n### 2. Fillout\n![a mockup of fillout](https:\u002F\u002Fformester-strapi.s3.ap-south-1.amazonaws.com\u002Fa_mockup_of_fillout_8e0ddf8aec.png)\nFillout is a modern, user-friendly online form builder designed to help you create stunning forms in no time.\nIts drag-and-drop editor makes building forms a breeze, and with its advanced customization options, you can design forms that perfectly fit your brand.\n\nWhether it’s collecting feedback, generating leads, or conducting surveys, Fillout has you covered. Plus, its seamless integrations with tools like Zapier, Slack, and Google Sheets make managing your data effortless.\n\n#### Pricing:\nFillout offers 4 plans:\n\n* A free plan.\n\n* Three premium plans starting at **15$\u002Fmo**.\n\n### 3. Tally.so\n![a mockup of tally](https:\u002F\u002Fformester-strapi.s3.ap-south-1.amazonaws.com\u002Fa_mockup_of_tally_ca9ed4b287.png)\n\nTally. so is the perfect online form builder for creators who value simplicity and speed.\n\nIts minimalist design ensures that you can create professional-looking forms without any distractions or complexity.\n\nWith unlimited forms and submissions in its free plan, Tally. so is one of the most generous form builders out there. Whether it’s collecting RSVPs, running polls, or gathering feedback, it does it all effortlessly.\n\n#### Pricing:\nTally. so offers 3 plans:\n\n* A free plan.\n\n* Premium plans starting at **29$\u002Fmo**.\n\n### 4. forms.app\n\n![a mockup of forms.app](https:\u002F\u002Fformester-strapi.s3.ap-south-1.amazonaws.com\u002Fa_mockup_of_forms_app_6c85d7bf73.png)\nforms.app is a powerful yet straightforward form builder that caters to all your data collection needs.\nFrom e-commerce forms with payment collection to detailed surveys, it offers a wide range of templates to get you started.\n\nIts mobile-friendly forms and built-in analytics make it easy to reach your audience and analyze results on the go. Plus, its conditional logic feature ensures smarter, dynamic forms tailored to your audience's responses.\n\n#### Pricing:\nForms.app offers 4 plans:\n\n* A free plan.\n\n* Three premium plans starting at **5$\u002Fmo**.\n\n### 5. Cognito Forms\n![a mockup of congnitoforms](https:\u002F\u002Fformester-strapi.s3.ap-south-1.amazonaws.com\u002Fa_mockup_of_congnitoforms_b6862cb3c4.png)\nCognito Forms is a versatile form builder perfect for businesses that need advanced functionality.\nIt supports features like calculated fields, conditional logic, and file uploads, making it great for complex forms like order forms or registration forms.\n\nWith Cognito Forms, you can even integrate with tools like QuickBooks or Microsoft Power Automate to streamline your workflows. It’s ideal for those who need power and flexibility in a simple, no-code solution.\n\n#### Pricing:\nCognitoforms offers 4 plans:\n\n* A free plan.\n\n* Three premium plans starting at **19$\u002Fmo**.\n\n### Form Builder Comparison Tool:\n![a mockup of formester comparison tool](https:\u002F\u002Fformester-strapi.s3.ap-south-1.amazonaws.com\u002Fa_mockup_of_formester_comparison_tool_d6960eaaef.png)\n\nThe options we’ve covered are just the tip of the iceberg when it comes to online form builders. If you’re still unsure which one fits your needs, Formester’s **[Form Builder Comparison Tool](\u002Fcomparison-tool\u002F)** is here to help.\n\nThis powerful tool lets you compare over 30 popular form builders side by side. From features like payment integration, **[conditional logic](\u002Fblog\u002Fwhat-is-conditional-logic-how-to-use-it\u002F)**, and customization options to pricing plans and user reviews, you’ll get a complete picture.\n\nWhether you're looking for advanced functionality, budget-friendly options, or niche features, this tool simplifies your decision-making process.\n\n**[Start comparing today](https:\u002F\u002Fapp.formester.com\u002Fusers\u002Fsign_up)** and choose the best form builder for your goals!\n\n","blog\u002Fblog\u002Fbest-budget-friendly-online-form-builders.md",{"text":319},"5 min read",1788439051502]