This page documents the HTML form control implementations in LibWeb: the base class infrastructure (FormAssociatedElement, FormAssociatedTextControlElement, InputEventsTarget), and the concrete element classes HTMLInputElement, HTMLSelectElement, HTMLTextAreaElement, HTMLButtonElement, and HTMLFormElement. It covers type-state dispatch, value sanitization, shadow DOM construction, picker integration with the browser UI layer, form submission, and constraint validation.
For the HTML event loop and navigation machinery, see Navigation and Browsing Contexts. For contenteditable and execCommand, see Rich Text Editing. For how layout nodes are created from form elements, see Layout System.
FormAssociatedElement (Libraries/LibWeb/HTML/FormAssociatedElement.h70-188) is a mixin base class for all form controls. It manages:
m_form to the associated HTMLFormElementsuffering_from_* virtual methodsis_submittable(), is_resettable(), is_listed(), is_button(), is_submit_button()m_custom_validity_error_message set by setCustomValidity()Concrete element classes incorporate this mixin via the FORM_ASSOCIATED_ELEMENT macro (Libraries/LibWeb/HTML/FormAssociatedElement.h27-61), which injects overrides for inserted(), removed_from(), moved_from(), and attribute_changed(). These call form_node_was_inserted/removed/moved() and form_node_attribute_changed() so the element automatically re-runs the form owner algorithm on DOM mutations.
Class inheritance for form controls:
Sources: Libraries/LibWeb/HTML/FormAssociatedElement.h Libraries/LibWeb/HTML/HTMLInputElement.h Libraries/LibWeb/HTML/HTMLTextAreaElement.h Libraries/LibWeb/HTML/HTMLSelectElement.h Libraries/LibWeb/HTML/HTMLButtonElement.h Libraries/LibWeb/DOM/EditingHostManager.h
reset_form_owner() (Libraries/LibWeb/HTML/FormAssociatedElement.cpp167-209) runs on every relevant DOM change:
m_parser_inserted flag.<form> and no form attribute is present, return early (no change needed).m_form.form content attribute, and is connected: search the tree for a <form> element whose id matches the attribute value.HTMLFormElement ancestor.set_form() which adds/removes the element from the form's m_associated_elements list.is_candidate_for_constraint_validation() (Libraries/LibWeb/HTML/FormAssociatedElement.cpp331-393) excludes elements that are:
<datalist><input> with type Hidden, ResetButton, or Button<input> or <textarea> with readonly attribute<button>satisfies_its_constraints() (Libraries/LibWeb/HTML/FormAssociatedElement.cpp396-400) returns true only if none of the following hold:
| Virtual Method | Condition |
|---|---|
suffering_from_being_missing() | required and value is empty |
suffering_from_a_type_mismatch() | Value does not match type format (URL, email) |
suffering_from_a_pattern_mismatch() | Value does not match pattern regex |
suffering_from_being_too_long() | Value length exceeds maxlength |
suffering_from_being_too_short() | Value length below minlength |
suffering_from_an_underflow() | Numeric value below min |
suffering_from_an_overflow() | Numeric value above max |
suffering_from_a_step_mismatch() | Value is not a valid step multiple |
suffering_from_bad_input() | Value is unparseable for the type |
suffering_from_a_custom_error() | setCustomValidity() set a non-empty message |
check_validity_steps() fires a cancelable invalid event when constraints fail. report_validity_steps() additionally focuses the element and calls scroll_into_view().
Sources: Libraries/LibWeb/HTML/FormAssociatedElement.h Libraries/LibWeb/HTML/FormAssociatedElement.cpp
FormAssociatedTextControlElement (Libraries/LibWeb/HTML/FormAssociatedElement.h195-281) extends both FormAssociatedElement and InputEventsTarget. It is the shared base for HTMLInputElement and HTMLTextAreaElement.
Selection state fields:
m_selection_start — UTF-16 code unit offset of selection startm_selection_end — UTF-16 code unit offset of selection endm_selection_direction — Forward, Backward, or NoneKey methods:
| Method | Purpose |
|---|---|
set_the_selection_range(start, end, direction, source) | Sets selection and dispatches selectionchange event |
select() | Selects all text in the control |
set_range_text(replacement, start, end, mode) | Replaces a range; adjusts selection per SelectionMode |
relevant_value_was_changed() | Clamps selection to new value length after a value change |
cursor_position() | Returns a DOM::Position representing the text entry cursor |
Subclasses must implement:
relevant_value() / set_relevant_value() — current displayed valuedid_edit_text_node(input_type, data) — called after user text modificationform_associated_element_to_text_node() — returns the internal DOM::Text nodetext_control_scroll_container() — the scroll container elementhandle_insert(), handle_delete(), and the cursor-movement methods from InputEventsTarget are fully implemented here and operate directly on the internal text node and selection state.
Sources: Libraries/LibWeb/HTML/FormAssociatedElement.h195-281 Libraries/LibWeb/HTML/FormAssociatedElement.cpp446-700
InputEventsTarget (Libraries/LibWeb/DOM/InputEventsTarget.h) is a pure virtual interface with two implementations:
FormAssociatedTextControlElement — for <input> and <textarea>EditingHostManager — for contenteditable elementsThe EventHandler (in LibWeb/Page/EventHandler.cpp) determines the active InputEventsTarget based on which element has focus and routes keyboard events accordingly.
Interface methods:
| Method | Semantic |
|---|---|
handle_insert(input_type, value) | User typed a character or pasted text |
handle_delete(input_type) | Backspace (deleteContentBackward) or Delete (deleteContentForward) |
handle_return_key(input_type) | Enter key pressed |
select_all() | Ctrl+A |
set_selection_anchor(node, offset) | Mouse down — begins a selection |
set_selection_focus(node, offset) | Mouse drag — extends selection |
move_cursor_to_start/end(collapse) | Home/End keys |
increment/decrement_cursor_position_offset(collapse) | Arrow keys |
increment/decrement_cursor_position_to_next/previous_word(collapse) | Ctrl+Arrow |
increment/decrement_cursor_position_to_next/previous_line(collapse) | Up/Down arrows |
EditingHostManager (Libraries/LibWeb/DOM/EditingHostManager.cpp) delegates to execCommand:
handle_insert() → document->exec_command("insertText", false, value)handle_delete() → exec_command("delete") or exec_command("forwarddelete")handle_return_key() → exec_command("insertParagraph") or exec_command("insertLineBreak")It operates on the document-level Selection object rather than maintaining its own selection state.
Sources: Libraries/LibWeb/DOM/InputEventsTarget.h Libraries/LibWeb/DOM/EditingHostManager.h Libraries/LibWeb/DOM/EditingHostManager.cpp
HTMLInputElement (Libraries/LibWeb/HTML/HTMLInputElement.h54-416) is the most complex form control, multiplexing over 22 type states via the TypeAttributeState enum generated from ENUMERATE_HTML_INPUT_TYPE_ATTRIBUTES (Libraries/LibWeb/HTML/HTMLInputElement.h30-52).
Type state to layout node mapping:
create_layout_node() (Libraries/LibWeb/HTML/HTMLInputElement.cpp123-164) dispatches on type_state(). When appearance: none is set in CSS, text input types fall back to a generic block via create_layout_node_for_display_type() instead of Layout::TextInputBox.
adjust_computed_style() (Libraries/LibWeb/HTML/HTMLInputElement.cpp166-194) post-processes computed style: it rewrites display: inline to display: inline-block for the internal shadow tree to lay out correctly, and sets a default width in ch units based on the size attribute.
Sources: Libraries/LibWeb/HTML/HTMLInputElement.cpp123-194
Each type state maps to one of four ValueAttributeMode values (Libraries/LibWeb/HTML/HTMLInputElement.h338-343):
ValueAttributeMode | Used by | Read behavior | Write behavior |
|---|---|---|---|
Value | Text, Number, Date, Range, Color, etc. | Returns m_value | Runs value_sanitization_algorithm(), stores in m_value |
Default | SubmitButton, ResetButton, Button, ImageButton | Returns value content attribute | Sets value content attribute |
DefaultOn | Checkbox, RadioButton | Returns value attribute or "on" | Sets value content attribute |
Filename | FileUpload | Returns "C:\fakepath\{name}" | Allowed only to set to empty string |
value_sanitization_algorithm() is invoked every time m_value is assigned. Its behavior varies by type:
"" if the string is not a valid floating-point number.min and max."#000000" if invalid."" if invalid.Setting value programmatically via set_value() (Libraries/LibWeb/HTML/HTMLInputElement.cpp715-772) sets m_dirty_value = true, sanitizes, and if the value changed, calls relevant_value_was_changed() and updates the internal text node and selection.
HTMLInputElement builds a closed user-agent shadow tree for types that need custom rendering. Trees are created lazily and rebuilt when the type attribute changes.
HTMLInputElement internal shadow tree elements:
update_placeholder_visibility() toggles display on m_inner_text_element and m_placeholder_element based on whether m_text_node->data() is empty.
Sources: Libraries/LibWeb/HTML/HTMLInputElement.h348-375 Libraries/LibWeb/HTML/HTMLInputElement.cpp800-900
Inputs of type file and color show native pickers via the Page interface. The picker is triggered through show_the_picker_if_applicable() (Libraries/LibWeb/HTML/HTMLInputElement.cpp378-448) which enforces transient activation and mutability before calling into Page.
Picker trigger and callback flow:
show_picker() (Libraries/LibWeb/HTML/HTMLInputElement.cpp451-478) is the IDL-exposed method; it additionally checks same-origin requirements before delegating to show_the_picker_if_applicable().
File selection results create FileAPI::File objects (with MIME type sniffed via MimeSniff::Resource::sniff()) assembled into a FileAPI::FileList stored in m_selected_files.
Sources: Libraries/LibWeb/HTML/HTMLInputElement.cpp378-668
run_input_activation_behavior() (Libraries/LibWeb/HTML/HTMLInputElement.cpp481-563) dispatches on type:
input and change events. For radio, set_checked_within_group() unchecks other RadioButton inputs sharing the same name within the same form.form->submit_form(*this, ...).form->reset_form().show_the_picker_if_applicable().m_selected_coordinate, then calls form->submit_form().legacy_pre_activation_behavior() saves checkbox/radio state before activation; legacy_cancelled_activation_behavior() restores it if the click is cancelled.
compiled_pattern_regular_expression() (Libraries/LibWeb/HTML/HTMLInputElement.cpp271-293) compiles the pattern attribute into an ECMA262 regex with v (UnicodeSets) flag, anchored as ^(?:pattern)$. Returns {} if the attribute is absent or the pattern is invalid.
Sources: Libraries/LibWeb/HTML/HTMLInputElement.cpp271-563
HTMLSelectElement (Libraries/LibWeb/HTML/HTMLSelectElement.h) manages an ordered list of options and shows a native dropdown picker.
options() (Libraries/LibWeb/HTML/HTMLSelectElement.cpp133-144) returns an HTMLOptionsCollection rooted at the element, filtered to options whose nearest_select_element() is this element. list_of_options() calls update_cached_list_of_options() (Libraries/LibWeb/HTML/HTMLSelectElement.cpp233-284), which traverses the subtree per spec, skipping descendants of nested <select>, <hr>, <datalist>, or nested <optgroup> elements. Results are cached in m_cached_list_of_options.
update_selectedness() enforces that exactly one option is selected when multiple is absent and display_size() == 1. children_changed() calls it when options are added or removed, with an optimization path in can_skip_selectedness_update_for_inserted_option() to skip unnecessary re-runs.
create_shadow_tree_if_needed() (Libraries/LibWeb/HTML/HTMLSelectElement.cpp694-757) builds:
divm_inner_text_element (div, flex: 1) — displays the selected option labelm_chevron_icon_element (div containing an inline SVG <path>) — the dropdown arrow, hidden when appearance: noneshow_the_picker_if_applicable() (Libraries/LibWeb/HTML/HTMLSelectElement.cpp532-598) populates m_select_items — a Vector<SelectItem> where each entry is a Variant of SelectItemOption, SelectItemOptionGroup, or SelectItemSeparator — then calls document().page().did_request_select_dropdown(weak_element, position, width, m_select_items).
did_select_item(Optional<u32> id) (Libraries/LibWeb/HTML/HTMLSelectElement.cpp636-664) is the callback from the browser UI. It iterates m_select_items to find the matching option by ID, sets it as selected, then calls send_select_update_notifications().
send_select_update_notifications() (Libraries/LibWeb/HTML/HTMLSelectElement.cpp491-515) queues a user-interaction task that sets m_user_validity = true, calls update_selectedcontent(), and fires input and change events.
Sources: Libraries/LibWeb/HTML/HTMLSelectElement.h Libraries/LibWeb/HTML/HTMLSelectElement.cpp
HTMLTextAreaElement (Libraries/LibWeb/HTML/HTMLTextAreaElement.h) maintains a distinction between the raw value and the API value:
| Field / Method | Description |
|---|---|
m_raw_value (UTF-16 string) | Exactly what is in the internal DOM::Text node |
m_api_value (lazy optional) | m_raw_value with newlines normalized via Infra::normalize_newlines() |
value() | Returns api_value() |
default_value() | Returns child_text_content() (text children of the element) |
set_value() (Libraries/LibWeb/HTML/HTMLTextAreaElement.cpp177-198) calls set_raw_value(), sets m_dirty_value = true, updates the DOM text node, and resets the selection to the end.
reset_algorithm() (Libraries/LibWeb/HTML/HTMLTextAreaElement.cpp109-121) resets m_user_validity and m_dirty_value to false, then restores m_raw_value from child_text_content().
children_changed() (Libraries/LibWeb/HTML/HTMLTextAreaElement.cpp397-409) updates m_raw_value from the text children only if m_dirty_value is false, preserving user-edited content.
create_shadow_tree_if_needed() (Libraries/LibWeb/HTML/HTMLTextAreaElement.cpp336-365) creates:
div
m_inner_text_element (div) → m_text_node (DOM::Text) — editable contentm_placeholder_element (div, ::placeholder pseudo-element) → m_placeholder_text_nodedid_edit_text_node() (Libraries/LibWeb/HTML/HTMLTextAreaElement.cpp422-439) does not immediately fire the input event. Instead it stores the event type/data and restarts m_input_event_timer (a 100ms Core::Timer::create_single_shot). When the timer fires, queue_firing_input_event() dispatches the deferred UIEvents::InputEvent. This coalesces rapid keystrokes into fewer events.
Sources: Libraries/LibWeb/HTML/HTMLTextAreaElement.h Libraries/LibWeb/HTML/HTMLTextAreaElement.cpp
HTMLButtonElement (Libraries/LibWeb/HTML/HTMLButtonElement.h) has four type states from ENUMERATE_HTML_BUTTON_TYPE_ATTRIBUTES:
type attribute | TypeAttributeState | is_submit_button() result |
|---|---|---|
submit | Submit | Always true |
reset | Reset | False |
button | Button | False |
absent or auto | Auto | True only if neither command nor commandfor is present |
activation_behavior() (Libraries/LibWeb/HTML/HTMLButtonElement.cpp158-296):
form->submit_form(*this, ...)Reset state → form->reset_form()Auto state (without command) → returncommandfor-associated target element.command event at it; if not cancelled, execute the built-in command:
toggle-popover, show-popover, hide-popover — popover visibilityclose, request-close, show-modal — dialog control--) — event only, no built-in behaviorSources: Libraries/LibWeb/HTML/HTMLButtonElement.h Libraries/LibWeb/HTML/HTMLButtonElement.cpp
HTMLFormElement (Libraries/LibWeb/HTML/HTMLFormElement.h) maintains m_associated_elements (a list of HTMLElement& references added/removed by FormAssociatedElement::set_form()).
submit_form(submitter, options) (Libraries/LibWeb/HTML/HTMLFormElement.cpp112) implements the HTML spec's submission algorithm:
m_constructing_entry_list must be false.m_user_validity = true on all submittable controls.novalidate_state() is false: call interactively_validate_constraints(). If it returns false, abort.m_firing_submission_events = true.SubmitEvent with the submitter element. If cancelled, abort.formdata event; collects name/value pairs from submittable elements).GET, POST, or Dialog) and encoding type.dialog method: close the ancestor <dialog>.implicitly_submit_form() (Libraries/LibWeb/HTML/HTMLFormElement.cpp74-99) is triggered by Enter in a single-line input. It clicks the default submit button if one exists; otherwise, if exactly one field blocks implicit submission, it calls submit_form() directly.
reset_form() calls reset_algorithm() on all resettable associated elements (<input>, <select>, <textarea>, <output>).
statically_validate_constraints() iterates submittable elements and calls check_validity_steps() on each, collecting unhandled invalid elements. interactively_validate_constraints() focuses the first invalid element and scrolls it into view, returning false to abort submission.
Sources: Libraries/LibWeb/HTML/HTMLFormElement.h Libraries/LibWeb/HTML/HTMLFormElement.cpp
Several boolean flags track state across programmatic changes and user interactions:
| Flag | Owner | Meaning |
|---|---|---|
m_dirty_value | HTMLInputElement, HTMLTextAreaElement | Set on first user edit; prevents form reset from overwriting user content |
m_dirty_checkedness | HTMLInputElement | Set when user changes checkbox/radio; prevents HTML attribute from resetting checked |
m_user_validity | HTMLInputElement, HTMLSelectElement, HTMLTextAreaElement | Set on user interaction or form submit; enables constraint validation UI |
m_has_uncommitted_changes | HTMLInputElement | Set on each text edit; cleared when change event fires |
m_parser_inserted | FormAssociatedElement | Prevents form owner reset during initial HTML parsing |
commit_pending_changes() (Libraries/LibWeb/HTML/HTMLInputElement.cpp774-799) is called when a text-type input loses focus. It fires change only if m_has_uncommitted_changes is true, then clears the flag.
Sources: Libraries/LibWeb/HTML/HTMLInputElement.h383-409 Libraries/LibWeb/HTML/HTMLInputElement.cpp774-799 Libraries/LibWeb/HTML/HTMLTextAreaElement.h177-182
How user keyboard input reaches form controls and contenteditable elements:
Sources: Libraries/LibWeb/DOM/InputEventsTarget.h Libraries/LibWeb/DOM/EditingHostManager.cpp37-48 Libraries/LibWeb/HTML/FormAssociatedElement.cpp Libraries/LibWeb/HTML/HTMLInputElement.cpp565-580 Libraries/LibWeb/HTML/HTMLTextAreaElement.cpp422-439
Refresh this wiki