htmx Value Resolution Order for Attributes: How hx-* and data-hx-* Work

htmx resolves attribute values by first checking the direct hx-* attribute, then falling back to the corresponding data-hx-* prefixed version only if the primary attribute is missing.

When working with the bigskysoftware/htmx library, understanding the deterministic two-step lookup process for attribute values is essential for writing clean, valid HTML. This resolution order applies uniformly across all htmx-specific attributes, ensuring consistent behavior whether you use standard attributes or HTML5 data attributes for validation compliance.

The Two-Step Resolution Process

The htmx value resolution order follows a strict precedence:

  1. Direct attribute lookup – The library first checks for the attribute exactly as written (e.g., hx-get, hx-post, hx-target).
  2. Data-prefixed fallback – If the direct attribute is absent, htmx automatically checks for the same attribute name prefixed with data- (e.g., data-hx-get, data-hx-post).

This logic is applied consistently throughout the codebase whenever the library needs to read configuration from DOM elements, including request URL construction, swap style determination, and form value extraction.

Core Implementation in src/htmx.js

The resolution order is enforced by two helper functions defined in src/htmx.js. The hasAttribute function checks for existence using the two-step logic, while getAttributeValue retrieves the actual value following the same precedence:

// src/htmx.js
function hasAttribute(elt, qualifiedName) {
  return !!elt.hasAttribute && (elt.hasAttribute(qualifiedName) ||
    elt.hasAttribute('data-' + qualifiedName))
}

function getAttributeValue(elt, qualifiedName) {
  return getRawAttribute(elt, qualifiedName) ||
         getRawAttribute(elt, 'data-' + qualifiedName)
}

These utilities power higher-level functions like getClosestAttributeValue and findAttributeTargets, ensuring that every attribute read operation respects the same deterministic order. Because the fallback always uses the data-hx-* prefix, developers can write markup that passes HTML5 validators without sacrificing functionality.

Practical Examples

Basic Attribute Fallback

When both attributes are present, the direct version wins. When only the data-prefixed version exists, it serves as the fallback:

<!-- Direct attribute take precedence -->
<button hx-get="/direct">Direct Request</button>

<!-- Fallback only used when hx-get is absent -->
<button data-hx-get="/fallback">Fallback Request</button>

Both buttons trigger GET requests, but the second resolves its URL from data-hx-get because hx-get is not present on that element.

Value Resolution with hx-vals

The resolution order applies to JSON-valued attributes like hx-vals:

<!-- Direct attribute wins -->
<div hx-vals='{"uid":"123"}'>Uses uid 123</div>

<!-- Data-prefixed acts as fallback -->
<div data-hx-vals='{"uid":"456"}'>Uses uid 456</div>

In the first element, htmx extracts the UID from hx-vals. In the second, it falls back to data-hx-vals to build the request parameters.

Form Handling and Override Behavior

When processing form submissions, htmx uses this resolution order to determine which values to include:

<form hx-post="/submit">
  <input name="name" value="Alice">
  <!-- hx-vals overrides the input's native value -->
  <input name="age" value="30" hx-vals='{"age":"31"}'>
</form>

Upon submission, the request body contains name=Alice and age=31 because the hx-vals attribute—found via the direct lookup—takes precedence over the input element's default value.

Implications for HTML Validation

This dual-attribute resolution strategy allows developers to maintain HTML5 validation compliance while using htmx. Standard hx-* attributes work immediately, but if your project requires passing strict validators or avoiding custom attribute warnings, you can substitute data-hx-* equivalents without changing application logic. The library treats both identically, ensuring your hypermedia-driven interfaces remain standards-compliant when necessary.

Summary

  • htmx value resolution follows a strict two-step order: direct hx-* attributes are checked first, then data-hx-* fallbacks.
  • The helper functions hasAttribute and getAttributeValue in src/htmx.js enforce this logic across the entire library.
  • Direct attributes always win when both forms are present on the same element.
  • This mechanism enables HTML5-compliant markup by allowing developers to use data-hx-* prefixes without sacrificing functionality.
  • Functions like getClosestAttributeValue and findAttributeTargets rely on this resolution order when traversing the DOM.

Frequently Asked Questions

Does data-hx-get override hx-get?

No. The direct hx-get attribute always takes precedence over data-hx-get. The data-prefixed version only resolves if the direct attribute is completely absent from the element.

Can I mix hx-* and data-hx-* on the same element?

Yes, though the direct attribute will be used exclusively. If an element has both hx-target and data-hx-target, htmx ignores the data-prefixed version and uses only the direct attribute's value.

Does this resolution order apply to all htmx attributes?

Yes. According to the bigskysoftware/htmx source code, this two-step lookup applies uniformly to every htmx-specific attribute, including hx-post, hx-swap, hx-trigger, hx-vals, and all others processed by the internal attribute helper functions.

How does this affect HTML5 validation?

The resolution order allows you to write valid HTML5 by using data-hx-* prefixes instead of custom hx-* attributes when validation is required. Since htmx recognizes both forms with the same priority logic, your application behavior remains identical while satisfying strict HTML5 validators.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →