A visual custom element does not automatically behave like a native form control. A form-associated custom element can use ElementInternals to contribute a value and validity state to its owning form. The submitted value, user-visible state, disabled state, reset behavior, and restoration behavior are separate contracts. For a task that can be expressed with a native select or radio group, the native control is often the better baseline. A component layer should improve interaction without making a permit decision depend on script execution.
Form-Associated Custom Controls and Native Fallback
Working case
Reviewers choose approve, return, or defer on case 62. One application submits a standard HTML form; another wraps the choice in a custom element to show policy help. The first implementation writes only a styled label and never calls setFormValue. Reviewers see approve, but the server receives no decision. Another version sends display text instead of the stable decision code. A restart restores the label but not the value. A plain server-rendered select can carry the same name and options when the advanced control is unavailable.
Implementation boundary
function normalizeCaseDecision(value) {
const allowed = new Set(['approve', 'return', 'defer']);
return allowed.has(value) ? value : null;
}
console.log(normalizeCaseDecision('approved'));
// Output: nullStart with a normal named input and server validation. If the custom form control is warranted, set formAssociated on the autonomous element, attach internals, and call setFormValue whenever the normalized decision changes. Set validity and a focus target for errors. Handle form reset and disabled state explicitly, then test browser restoration behavior. Do not create duplicate successful controls with the same name when a fallback select remains in the form; hide or disable one submission path intentionally. The server still validates that the selected code is allowed for the current reviewer and case.
Cost and boundaries
Normalizing a three-value decision is O(1), while a custom control adds lifecycle code, accessibility testing, and browser integration work. Each validation change can trigger layout and announcement work if it replaces error nodes. Keep error text stable and update only when state changes. A custom element may add bundle bytes to every review screen, so lazy loading must preserve a usable plain form during delay or failure. Measure failed submissions and keyboard completion, not just whether the enhanced widget paints.
Failure trace
Submit the page before the component definition loads and verify the server receives a valid decision through the native path. Activate the enhanced control and submit each option; inspect the actual FormData value, not the visible label. Reset the form and confirm the value, selected appearance, and validity all agree. Disable the field and verify it no longer submits. Corrupt a decision code in the request and require server rejection. Reopen a partially completed form after navigation and verify restored state or an explicit prompt to choose again.
Verification
- FormData contains one stable decision code.
- Reset, disabled, and error states agree with the UI.
- The server rejects unauthorized decisions.
Practice drill
Build a case-decision field with approve, return, and defer. Define stable codes separate from the labels shown to reviewers. Provide a server-rendered select first. If the component takes over, check that exactly one named successful control contributes to submission. Try a missing value, reset, disabled fieldset, browser back navigation, and a keyboard-only run. Record whether every route sends the same stable code to the server.
Decision note
Form participation is an end-to-end value contract; appearance cannot stand in for submitted state.
Common Mistakes
- Assuming a shadow input submits through the outer form.
- Submitting both fallback and enhanced controls.
- Treating client validity as server authorization.
Related lessons
Web Component Contracts and Interoperability; Custom Element Upgrade and Reconnection; Shadow Slots, Events, and Focus Contracts; Shadow Style Tokens, Parts, and Shared Sheets; Forms and Data Entry Workflows; Form submission: validate on the server and return field errors.
Connected practice
Build Project: interoperable case-decision control and review Web Development: components and compatibility quiz.
