# How htmx Collects and Resolves Form Data: A Deep Dive into the Serialization Pipeline

> Discover how htmx collects and resolves form data using its serialization pipeline. Learn about FormData objects, input validation, and conflict resolution for seamless form submissions.

- Repository: [Big Sky Software/htmx](https://github.com/bigskysoftware/htmx)
- Tags: deep-dive
- Published: 2026-08-30

---

**htmx collects form data through a multi-step serialization pipeline in [`src/htmx.js`](https://github.com/bigskysoftware/htmx/blob/main/src/htmx.js) that uses dual FormData objects to ensure proper precedence, validates inputs via the HTML5 constraint API, and resolves conflicts between related forms, submit buttons, and `hx-include` targets.**

htmx form data collection is orchestrated by the `getInputValues` function in the bigskysoftware/htmx repository, eliminating the need for manual serialization while maintaining spec-compliant behavior. This article examines the internal mechanics of how htmx processes inputs, manages validation state, and constructs the final payload for AJAX requests.

## The Entry Point: getInputValues in src/htmx.js

The `getInputValues` function (lines 3360–3520 in [`src/htmx.js`](https://github.com/bigskysoftware/htmx/blob/main/src/htmx.js)) serves as the primary entry point for all form data collection within htmx. This function returns a structured object containing three critical properties:

- `errors` – An array of validation errors encountered during processing.
- `formData` – The final `FormData` instance ready for HTTP submission.
- `values` – A proxy object (`formDataProxy`) that exposes the FormData contents as a plain JavaScript object for programmatic access.

According to the htmx source code, this function initiates a ten-step pipeline that carefully balances performance, correctness, and the complex precedence rules required by HTML forms.

## The Multi-Step Collection Pipeline

htmx serializes form data through a strict sequence that guarantees auxiliary elements override standard inputs when appropriate. The pipeline maintains two separate `FormData` instances throughout execution: `formData` for regular values and `priorityFormData` for values that must take precedence.

### Step 1: Initialization and Validation Setup

The pipeline begins by instantiating empty `FormData` objects and determining whether validation should execute. Validation is enabled by default unless explicitly disabled via the `novalidate` or `formnovalidate` attributes, or explicitly forced via `hx-validate="true"` (lines 3510–3518).

**Key validation flags checked:**
- The presence of `novalidate` on the form element.
- The presence of `formnovalidate` on the triggering submit button.
- The explicit `hx-validate="true"` attribute override.

### Step 2: Related Form Processing (Non-GET Verbs)

For HTTP verbs other than GET, htmx first processes the related form via `getRelatedForm(elt)`. This step populates `priorityFormData` through the `processInputValue` helper function (lines 3365–3370), ensuring that values from the primary form container take precedence over potentially conflicting inputs from other sources.

### Step 3: Target Element Processing

The target element (`elt`) is processed next, with its inputs added to the regular `formData` object (lines 3374–3376). This captures the standard inputs associated with the htmx-triggered element, including those found within the element's DOM subtree.

### Step 4: Submit Button Handling

When a request originates from a button or submit input, htmx captures the element's name and value, adding them to `priorityFormData` (lines 3392–3396). This ensures that the clicked button's value overrides any duplicate field names in the regular payload, matching standard browser form submission behavior where the activating submit button is included in the data.

### Step 5: Explicit hx-include Targets

The `hx-include` attribute allows developers to specify additional elements whose values should be included in the request. htmx traverses all elements referenced by `hx-include`, and for non-form nodes, processes every descendant matching the input selector (lines 3398–3405). This mechanism enables ad-hoc inclusion of fields outside the primary form structure.

## Precedence Resolution and Deduplication

After collecting values from all sources, htmx executes `overrideFormData` to merge `priorityFormData` over `formData` (lines 3498–3505). This operation guarantees that related forms and submit buttons win precedence conflicts over ordinary inputs.

**Utility functions managing FormData integrity:**
- **`addValueToFormData`** (lines 3470–3477) – Safely appends scalar values or arrays to a `FormData` instance, handling multi-value fields correctly.
- **`removeValueFromFormData`** (lines 3484–3493) – Removes previously added values, used when a form element appears both directly and via the related form to prevent duplication.

## Input Filtering and Value Extraction

htmx applies strict filtering rules to ensure only valid, submittable data enters the payload. The `shouldInclude` function (lines 3549–3564) filters out:
- Disabled fields.
- Elements without a name attribute.
- Unchecked radio buttons and checkboxes.
- Buttons (unless they triggered the submission).
- File inputs (unless explicitly handling file uploads).

The `getValueFromInput` function (lines 3502–3512) handles type-specific extraction logic for select elements, file inputs, and generic input types, ensuring values are serialized according to their HTML specifications.

## HTML5 Validation Integration

When validation is enabled, the `validateElement` function triggers the `htmx:validation:validate` event and aggregates any constraint violations before the request proceeds (lines 3570–3580). This integration allows htmx to leverage the browser's built-in validation APIs while providing hooks for custom validation logic through events.

## Practical Implementation Examples

The following examples demonstrate htmx form data collection in practice:

```html
<!-- Simple form with automatic input collection -->
<form id="myForm" hx-post="/save" hx-validate="true">
  <input name="title" value="Hello">
  <input type="checkbox" name="published" checked>
  <button type="submit" name="action" value="save">Save</button>
</form>

```

```javascript
// Manual access to the collection routine for debugging
const elt = document.getElementById('myForm');
const {formData, errors} = htmx.getInputValues(elt, 'post');

if (errors.length === 0) {
  for (const [key, value] of formData.entries()) {
    console.log(key, value);
  }
}

```

```html
<!-- Including fields from external elements via hx-include -->
<div id="extra">
  <input name="extraInfo" value="42">
</div>

<button hx-post="/submit" hx-include="#extra">Submit</button>

```

## Summary

- **`getInputValues`** in [`src/htmx.js`](https://github.com/bigskysoftware/htmx/blob/main/src/htmx.js) (lines 3360–3520) is the central function responsible for htmx form data collection.
- The system uses two `FormData` objects—`formData` and `priorityFormData`—to manage precedence between standard inputs, submit buttons, and related forms.
- **`overrideFormData`** merges priority values last, ensuring submit buttons and related forms override duplicate names in the main payload.
- **`shouldInclude`** and **`getValueFromInput`** filter disabled/invalid inputs and extract values according to HTML specifications.
- Validation is handled by **`validateElement`**, which integrates with the HTML5 constraint API and triggers custom validation events.
- The **`hx-include`** attribute allows arbitrary elements to contribute values to the submission payload.

## Frequently Asked Questions

### How does htmx handle multiple submit buttons with different values?

htmx captures the specific button that triggered the request and adds its name-value pair to `priorityFormData`. During the final merge via `overrideFormData`, this value takes precedence over any identically-named fields in the regular `formData` object, ensuring the server receives the correct action identifier without requiring hidden input workarounds.

### What is the difference between formData and priorityFormData in htmx?

`formData` stores values from the target element and standard inputs, while `priorityFormData` stores values from related forms and the clicked submit button. When constructing the final payload, htmx copies `priorityFormData` entries over `formData`, guaranteeing that auxiliary elements override standard inputs when name conflicts occur.

### How does hx-include affect form data collection?

The `hx-include` attribute directs htmx to traverse the specified selectors and process all matching elements. For each included element, htmx runs the input collection algorithm: form elements are processed directly, while non-form elements have their descendant inputs extracted. These values are added to the primary `formData` object alongside the main form fields.

### Does htmx validate forms before serialization?

Yes. When validation is enabled (the default unless `novalidate` or `formnovalidate` is present), htmx executes `validateElement` which triggers `htmx:validation:validate` and checks HTML5 constraint violations. If validation errors exist, they are returned in the `errors` array and the request typically halts, allowing developers to display feedback before network transmission occurs.