{
  "$type": "site.standard.document",
  "bskyPostRef": {
    "cid": "bafyreifgrqjrpuaydqhtmw75inmiscagqkrdsrfn2vn5y5wvcw3cebwvhy",
    "uri": "at://did:plc:zoasrjjpgvvxrrzcpaf24bsn/app.bsky.feed.post/3mmqkwdd6vj62"
  },
  "path": "/notebook/matching-form-fields-with-a-web-component/",
  "publishedAt": "2026-05-25T22:23:24.000Z",
  "site": "https://www.aaron-gustafson.com",
  "tags": [
    "form-matching-fields",
    "a demo of the web component",
    "the form-matching-fields repository"
  ],
  "textContent": "Sometimes the simplest form pattern ends up being the one you repeat _ad infinitum_ : “Type it once, then type it again.” We do it for password confirmations, email verification, and any flow where a typo can create expensive follow-up work. This week I released a small web component to handle that pattern cleanly: form-matching-fields.\n\nThe component wraps two related form fields and adds validation to ensure they match. It’s intentionally additive, which means it works with native browser validation rather than trying to replace it.\n\n## # Wrap and go\n\nThe API is intentionally simple:\n\n\n    <form-matching-fields><labelfor=“password”>Password</label><inputid=“password”type=“password”required/><labelfor=“password-again”>Password again</label><inputid=“password-again”type=“password”required/></form-matching-fields>\n\nThe component evaluates the first two eligible text-type inputs it contains and applies mismatch validation to the second one when both fields have values.\n\n## # What counts as an eligible field?\n\nTo keep behavior predictable, the component only considers descendant `input` elements of these types:\n\n  * text\n  * email\n  * password\n  * search\n  * tel\n  * url\n\n\n\nIt ignores `disabled` and `readonly` controls, which helps prevent false positives when you have conditional or locked fields in the same wrapper.\n\n## # Validation behavior that plays nicely\n\nOne of the core goals here was to avoid stepping on existing validation rules. In practice, that means:\n\n  * If the second field already has a native validation issue (like `required` or `type` mismatch), this component won’t obscure that.\n  * If the second field already has a custom validity message, this component won’t overwrite that either.\n  * It only clears mismatch errors that it set itself.\n\n\n\nThat last point is especially useful in larger forms where multiple constraints can overlap. You don’t want one helper trying to be the sole source of truth.\n\n## # Customizing the validation message\n\nBy default, the component uses this template for the validation message:\n\n> The fields “{label_1}” and “{label_2}” should match\n\nIt smartly resolves the labels (`{label_1}` and `{label_2}`) from your markup in this order:\n\n  1. associated `<label for>` text\n  2. wrapping `<label>` text\n  3. `aria-label`\n  4. `name`\n  5. `id`\n\n\n\nYou can override it with the `validation-message` attribute:\n\n\n    <form-matching-fieldsvalidation-message=“Please ensure {label_2} matches {label_1}.”><labelfor=“email”>Email</label><inputid=“email”type=“email”required/><labelfor=“verify-email”>Verify email</label><inputid=“verify-email”type=“email”required/></form-matching-fields>\n\nIn most forms, that gives you a clear error message without requiring extra setup.\n\n## # Demo\n\nI put together a demo of the web component over on GitHub:\n\n## # Grab it\n\nYou can explore the source, file issues, and suggest enhancements in the form-matching-fields repository.",
  "title": "✍🏻 Easy Data-entry Verification with a Web Component"
}