bigskysoftware / bigskysoftware/htmx
Feature Request: `hx-live`: Support Boolean Attribute Binding (`:?attr` / `hx-live:?attr`) for Custom Attributes & Web Components
- Dominant language
- JavaScript
- Stars
- 49.4k
- Forks
- 1.7k
- Avg merge
- 3d 22h
- Merged PRs (30d)
- 30
Description
#### Summary
Add an explicit boolean attribute binding modifier—`:?` (and its long form `hx-live:?`)—to `hx-live`.
While `hx-live` handles standard native boolean attributes (such as `disabled` or `required`) based on truthiness, generic attributes always write their stringified value (e.g., `:my-flag="false"` becomes `my-flag="false"`). This breaks Custom Elements, Web Components (like Lit's `@property({ type: Boolean })`), and dynamic state attributes (`selected`, `checked`) where DOM attribute *presence* dictates state rather than string value.
Borrowing Lit's established `?` prefix syntax, `:?` ensures that truthy values set/keep the attribute, while falsy values (including empty strings and the string `"false"`) remove the attribute entirely via native `toggleAttribute()`.
---
#### Problem & Motivation
Under the current `hx-live` attribute writing rules:
1. **Known Booleans:** Predefined native attributes like `disabled` or `required` toggle correctly.
2. **Generic Attributes:** Any custom attribute (e.g., `:multiple="false"`, `:active="false"`) falls through to the default branch and writes directly to the DOM as `multiple="false"` or `active="false"`.
When integrating Web Components built with Lit, Stencil, or native Custom Elements:
```html
```
Under standard HTML and DOM semantics, `element.hasAttribute('multiple')` returns true. Lit's boolean converter therefore treats the element as `multiple` regardless of the `"false"` string.
Adding `:?` allows developers to explicitly declare any arbitrary or standard attribute as a boolean toggle. This cleanly avoids having `hx-live` maintain or perpetually update a rigid, hardcoded registry of standard HTML5, ARIA, and custom boolean attributes.
---
#### Proposed Behavior & Truthiness Evaluation
When hx-live processes attributes matching the pattern `^(?:hx-live:|\:)\?([a-zA-Z0-9_-]+)$:`
1. Extract Attribute Name: Strip the `:?` or hx-live:? prefix (e.g.,` :?selected -> selected, :?checked -> checked`).
2. Evaluate Truthiness: Coerce the expression result to determine attribute presence.
3. Toggle Attribute: Invoke native `element.toggleAttribute(attrName, isTruthy)`.
Evaluation Rules:
- true, non-empty strings (e.g., `"active"`) -> Add/retain attribute (``)
- `false`, literal string `"false"` -> Remove attribute (``)
- `""` (empty/blank string) -> Remove attribute (prevents empty interpolation from activating flags)
- `null, undefined, 0, NaN `-> Remove attribute
```javascript
const boolMatch = name.match(/^(?:hx-live:|\:)\?([a-zA-Z0-9_-]+)$/);
if (boolMatch) {
const targetAttr = boolMatch[1];
const val = evaluate(expr, el);
const isFalsy =
val === false ||
val === null ||
val === undefined ||
val === 0 ||
Number.isNaN(val) ||
(typeof val === 'string' && (val.trim() === '' || val.trim() === 'false'));
el.toggleAttribute(targetAttr, !isFalsy);
}
```
---
#### Why This Fits `hx-live`
- Zero Breaking Changes: Existing `:attr `expressions remain untouched.
- Web Component First-Class Support: Solves a major interoperability blocker when using modern Web Components with `hx-live`.
- Standard Idiom: Follows the established `?` boolean convention popularized by Lit and the broader Web Components ecosystem.
---
#### Willingness to Contribute
I would be happy to submit a Pull Request.
Contributor guide
Research direction
The payload names no source file or test. Start by tracing hx-live's attribute-binding evaluation and existing native-boolean handling; then verify both :? and hx-live:? forms, including the listed truthy and falsy values, while confirming existing :attr expressions remain unchanged.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript
- Domain
- frontend
- Issue type
- Feature
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 68/100