{"componentChunkName":"component---src-templates-post-jsx","path":"/blog/html-form-inspector-inspect-and-debug-your-forms-online/","result":{"data":{"mdx":{"body":"function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\n/* @jsxRuntime classic */\n\n/* @jsx mdx */\nconst _frontmatter = {\n  \"title\": \"HTML Form Inspector: inspect and debug your forms online\",\n  \"cover\": \"/blogs/forminspector/cover.png\",\n  \"date\": \"2025-07-01\",\n  \"type\": [\"announcement\"]\n};\nconst layoutProps = {\n  _frontmatter\n};\nconst MDXLayout = \"wrapper\";\nreturn function MDXContent(_ref) {\n  let {\n    components\n  } = _ref,\n      props = _objectWithoutProperties(_ref, [\"components\"]);\n\n  return mdx(MDXLayout, _extends({}, layoutProps, props, {\n    components: components,\n    mdxType: \"MDXLayout\"\n  }), mdx(\"p\", null, `HTML forms are notoriously hard to get right. They require a lot of boilerplate HTML and even small mistakes can lead to frustrating user experiences like not being able to click a label to toggle a checkbox.`), mdx(\"h2\", {\n    \"id\": \"finding-issues-in-forms\"\n  }, `Finding issues in forms`), mdx(\"p\", null, `Because forms are so verbose, it can also be hard to discover issues in them just by looking at the code. For example, how long does it take you to spot the problem in this form?`), mdx(\"div\", {\n    \"className\": \"gatsby-highlight\",\n    \"data-language\": \"html\"\n  }, mdx(\"pre\", _extends({\n    parentName: \"div\"\n  }, {\n    \"className\": \"language-html\"\n  }), mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-html\"\n  }), mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token tag\"\n  }), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token tag\"\n  }), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `<`), `form`), ` `, mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token attr-name\"\n  }), `action`), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token attr-value\"\n  }), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation attr-equals\"\n  }), `=`), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `\"`), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `\"`)), ` `, mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token attr-name\"\n  }), `method`), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token attr-value\"\n  }), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation attr-equals\"\n  }), `=`), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `\"`), `post`, mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `\"`)), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `>`)), `\n  `, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token tag\"\n  }), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token tag\"\n  }), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `<`), `label`), ` `, mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token attr-name\"\n  }), `for`), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token attr-value\"\n  }), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation attr-equals\"\n  }), `=`), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `\"`), `username`, mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `\"`)), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `>`)), `E-mail`, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token tag\"\n  }), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token tag\"\n  }), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `</`), `label`), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `>`)), `\n  `, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token tag\"\n  }), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token tag\"\n  }), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `<`), `input`), ` `, mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token attr-name\"\n  }), `type`), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token attr-value\"\n  }), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation attr-equals\"\n  }), `=`), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `\"`), `text`, mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `\"`)), ` `, mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token attr-name\"\n  }), `id`), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token attr-value\"\n  }), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation attr-equals\"\n  }), `=`), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `\"`), `username`, mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `\"`)), ` `, mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token attr-name\"\n  }), `name`), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token attr-value\"\n  }), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation attr-equals\"\n  }), `=`), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `\"`), `username`, mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `\"`)), ` `, mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token attr-name\"\n  }), `required`), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token attr-value\"\n  }), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation attr-equals\"\n  }), `=`), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `\"`), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `\"`)), ` `, mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token attr-name\"\n  }), `autocomplete`), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token attr-value\"\n  }), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation attr-equals\"\n  }), `=`), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `\"`), `username`, mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `\"`)), ` `, mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `/>`)), `\n  `, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token tag\"\n  }), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token tag\"\n  }), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `<`), `label`), ` `, mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token attr-name\"\n  }), `for`), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token attr-value\"\n  }), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation attr-equals\"\n  }), `=`), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `\"`), `password`, mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `\"`)), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `>`)), `Password`, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token tag\"\n  }), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token tag\"\n  }), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `</`), `label`), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `>`)), `\n  `, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token tag\"\n  }), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token tag\"\n  }), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `<`), `input`), ` `, mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token attr-name\"\n  }), `type`), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token attr-value\"\n  }), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation attr-equals\"\n  }), `=`), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `\"`), `password`, mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `\"`)), ` `, mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token attr-name\"\n  }), `name`), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token attr-value\"\n  }), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation attr-equals\"\n  }), `=`), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `\"`), `password`, mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `\"`)), ` `, mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token attr-name\"\n  }), `required`), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token attr-value\"\n  }), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation attr-equals\"\n  }), `=`), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `\"`), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `\"`)), ` `, mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token attr-name\"\n  }), `autocomplete`), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token attr-value\"\n  }), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation attr-equals\"\n  }), `=`), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `\"`), `current-password`, mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `\"`)), ` `, mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `/>`)), `\n  `, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token tag\"\n  }), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token tag\"\n  }), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `<`), `button`), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `>`)), `Sign in`, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token tag\"\n  }), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token tag\"\n  }), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `</`), `button`), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `>`)), `\n`, mdx(\"span\", _extends({\n    parentName: \"code\"\n  }, {\n    \"className\": \"token tag\"\n  }), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token tag\"\n  }), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `</`), `form`), mdx(\"span\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"token punctuation\"\n  }), `>`))))), mdx(\"p\", null, `If you think it's the empty `, mdx(\"code\", _extends({\n    parentName: \"p\"\n  }, {\n    \"className\": \"language-text\"\n  }), `action`), ` attribute, you're wrong: an empty action attribute will submit the form to the current page.`), mdx(\"p\", null, `If you think it's the button without a `, mdx(\"code\", _extends({\n    parentName: \"p\"\n  }, {\n    \"className\": \"language-text\"\n  }), `type=\"submit`), `, that's also fine: if there's a single button in a form, it will be treated as a submit button by default.`), mdx(\"p\", null, `In this case, our password input is missing an `, mdx(\"code\", _extends({\n    parentName: \"p\"\n  }, {\n    \"className\": \"language-text\"\n  }), `id`), ` attribute, which means that the label above it is not associated with the input. This means the input has no accessible name, and clicking the label will not focus the input.`), mdx(\"p\", null, `It's easy to overlook because as you can see, the line with the input contains the word \"password\" `, mdx(\"strong\", {\n    parentName: \"p\"\n  }, `three times`), `. How much more does a browser need to tell you that this input is a password?`), mdx(\"p\", null, `Now take a look at the following image. How long does it take you to spot the problem?`), mdx(\"img\", {\n    src: wrongformoutline,\n    alt: \"Three rectangles listing the form configuration, the fields where the input with type password has no label, and a group listing the button with a type of submit.\",\n    className: \"imgshadow\"\n  }), mdx(\"p\", null, `That's much quicker, right? You instantly see that the password input has no label, and now you can fix it.`), mdx(\"h2\", {\n    \"id\": \"introducing-the-html-form-inspector\"\n  }, `Introducing the HTML Form Inspector`), mdx(\"p\", null, `The screenshot above is how the form above is shown in our new `, mdx(\"a\", _extends({\n    parentName: \"p\"\n  }, {\n    \"href\": \"/form-inspector/\"\n  }), `HTML Form Inspector`), `, a free online tool that helps you inspect and debug your HTML forms.`), mdx(\"p\", null, `As we were building out the `, mdx(\"a\", _extends({\n    parentName: \"p\"\n  }, {\n    \"href\": \"/docs/outline-panel/#forms\"\n  }), `Forms Outline`), ` feature in Polypane and subsequently finding out that `, mdx(\"em\", {\n    parentName: \"p\"\n  }, `all our forms`), ` had issues easily picked up, we realized that this would be a great tool to have online.`), mdx(\"p\", null, `So we took the core functionality of our Forms Outline, retooled it from using the Live DOM (which we use in Polypane) to using the HTML source code, and made it `, mdx(\"a\", _extends({\n    parentName: \"p\"\n  }, {\n    \"href\": \"/form-inspector/\"\n  }), `available online for everyone to use`), `.`), mdx(\"h2\", {\n    \"id\": \"how-does-it-work\"\n  }, `How does it work?`), mdx(\"p\", null, `The HTML Form Inspector takes the HTML source code of your form and shows it in a structured way, splitting out the various parts of the form:`), mdx(\"h3\", {\n    \"id\": \"summary\"\n  }, `Summary`), mdx(\"p\", null, `The inspector starts with a summary, so can at a glance see how many fields in total, how many required fields, how many fieldsets and how many buttons there are in the form. This already helps you spot issues like a missing `, mdx(\"code\", _extends({\n    parentName: \"p\"\n  }, {\n    \"className\": \"language-text\"\n  }), `required`), ` attribute or a missing button.`), mdx(\"img\", {\n    src: inspectorsummary,\n    alt: \"4 numbers showing the total fields, required fields, fieldsets and buttons.\",\n    className: \"imgshadow\"\n  }), mdx(\"h3\", {\n    \"id\": \"form-configuration\"\n  }, `Form configuration`), mdx(\"p\", null, `The form configuration shows the `, mdx(\"code\", _extends({\n    parentName: \"p\"\n  }, {\n    \"className\": \"language-text\"\n  }), `action`), ` and `, mdx(\"code\", _extends({\n    parentName: \"p\"\n  }, {\n    \"className\": \"language-text\"\n  }), `method`), ` attributes of the form so you know where it submits to and how it submits.`), mdx(\"img\", {\n    src: inspectorconfig,\n    alt: \"Form configuration overview showing an action and method\",\n    className: \"imgshadow\"\n  }), mdx(\"h3\", {\n    \"id\": \"fields\"\n  }, `Fields`), mdx(\"p\", null, `The fields section lists all the fields in the form that aren't part of a fieldset and shows their element, type, name, label, value/checked status and whether they are required and disabled. You can click open the details of each field to see any other attributes like `, mdx(\"code\", _extends({\n    parentName: \"p\"\n  }, {\n    \"className\": \"language-text\"\n  }), `id`), `, `, mdx(\"code\", _extends({\n    parentName: \"p\"\n  }, {\n    \"className\": \"language-text\"\n  }), `autocomplete`), `, `, mdx(\"code\", _extends({\n    parentName: \"p\"\n  }, {\n    \"className\": \"language-text\"\n  }), `placeholder`), ` and more.`), mdx(\"img\", {\n    src: inspectorfields,\n    alt: \"Field overview showing a table of fields and their properties\",\n    className: \"imgshadow\"\n  }), mdx(\"h3\", {\n    \"id\": \"fieldsets\"\n  }, `Fieldsets`), mdx(\"p\", null, `Each fieldset in the form is shown in its own section, with the `, mdx(\"code\", _extends({\n    parentName: \"p\"\n  }, {\n    \"className\": \"language-text\"\n  }), `legend`), ` and all the fields that are part of that fieldset. This makes it easy to see which fields are grouped together and under what title.`), mdx(\"img\", {\n    src: inspectorfieldset,\n    alt: \"Fieldet overview showing the fieldset name and a table of fields and their properties\",\n    className: \"imgshadow\"\n  }), mdx(\"h3\", {\n    \"id\": \"buttons\"\n  }, `Buttons`), mdx(\"p\", null, `The last section lists all the buttons in the form, showing their type, name, value and whether they are disabled. This is useful to see if you have a submit button and if the label makes sense.`), mdx(\"img\", {\n    src: inspectorbuttons,\n    alt: \"Button overview showing a table of buttons and their properties\",\n    className: \"imgshadow\"\n  }), mdx(\"h2\", {\n    \"id\": \"try-it-yourself\"\n  }, `Try it yourself!`), mdx(\"p\", null, `You can find the HTML Form Inspector at `, mdx(\"a\", _extends({\n    parentName: \"p\"\n  }, {\n    \"href\": \"/form-inspector/\"\n  }), `polypane.app/form-inspector`), `, or click the image below:`), mdx(\"a\", {\n    href: \"/form-inspector/\",\n    style: {\n      \"display\": \"block\",\n      \"maxWidth\": \"initial\",\n      \"borderRadius\": \"4px\"\n    }\n  }, mdx(\"img\", {\n    style: {\n      \"display\": \"block\"\n    },\n    src: forminspector,\n    alt: \"The HTML Form Inspector\",\n    className: \"imgshadow\"\n  })), mdx(\"p\", null, `We know that making this tool freely available might not be the smartest business move, but we couldn't find anything else like it out there.`), mdx(\"p\", null, `And honestly, we've discovered so many forms with easily detectable issues that we felt compelled to share it with everyone.`), mdx(\"h2\", {\n    \"id\": \"go-even-deeper-with-polypane\"\n  }, `Go even deeper with Polypane`), mdx(\"p\", null, `In Polypane we use the live DOM to check forms which means we can pick up even more issues but also provide you with more context, and suggestions on how to improve your forms.`), mdx(\"p\", null, `For example, we can tell you if the `, mdx(\"code\", _extends({\n    parentName: \"p\"\n  }, {\n    \"className\": \"language-text\"\n  }), `autocomplete`), ` attribute has an invalid value, when the label is set by something other than a label (like ARIA, or a placeholder), if your radio groups are structured correctly, and so much more.`), mdx(\"p\", null, `When you've tested your forms with the HTML Form Inspector, you can use Polypane to go even deeper and fix any remaining issues.`), mdx(\"img\", {\n    src: formcta,\n    alt: \"Form Outline in Polypane showing missing labels\",\n    className: \"imgshadow\"\n  }), mdx(\"p\", null, `Polypane has a free 14 day trial (no credit card needed) that will let you test all your forms, along with dozens of other parts of your sites: `, mdx(\"strong\", {\n    parentName: \"p\"\n  }, mdx(\"a\", _extends({\n    parentName: \"strong\"\n  }, {\n    \"href\": \"https://dashboard.polypane.app/register\"\n  }), `Try Polypane for free`)), `!`));\n}\n;\nMDXContent.isMDXComponent = true;","timeToRead":3,"tableOfContents":{"items":[{"url":"#finding-issues-in-forms","title":"Finding issues in forms"},{"url":"#introducing-the-html-form-inspector","title":"Introducing the HTML Form Inspector"},{"url":"#how-does-it-work","title":"How does it work?","items":[{"url":"#summary","title":"Summary"},{"url":"#form-configuration","title":"Form configuration"},{"url":"#fields","title":"Fields"},{"url":"#fieldsets","title":"Fieldsets"},{"url":"#buttons","title":"Buttons"}]},{"url":"#try-it-yourself","title":"Try it yourself!"},{"url":"#go-even-deeper-with-polypane","title":"Go even deeper with Polypane"}]},"excerpt":"HTML forms are notoriously hard to get right. They require a lot of boilerplate HTML and even small mistakes can lead to frustrating user experiences like not…","frontmatter":{"title":"HTML Form Inspector: inspect and debug your forms online","cover":"/blogs/forminspector/cover.png","date":"2025-07-01","updated":null},"fields":{"slug":"/blog/html-form-inspector-inspect-and-debug-your-forms-online/","date":"2025-06-30T22:00:00.000Z","ogFileName":"html-form-inspector-inspect-and-debug-your-forms-online"}}},"pageContext":{"slug":"/blog/html-form-inspector-inspect-and-debug-your-forms-online/"}},"staticQueryHashes":["4164364741","425175329"]}