Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Attribute capture treated as boolean outside of HTMLInputElement context #20

Closed
jrencz opened this issue Jan 23, 2024 · 7 comments
Closed

Comments

@jrencz
Copy link

jrencz commented Jan 23, 2024

I noticed that rehype (using hast-util-to-html and property-information ultimately) wipes out value of attribute capture (because it's considered a boolean attribute)

capture: boolean,

but it happens on custom element.

I believe that should not be the case.

Attribute capture is defined for input (https://w3c.github.io/html-media-capture/#the-capture-idl-attribute), but the custom element I use it on assigns a different meaning to it.

If it's possible to configure hast-util-to-html or rehype so they know what are the supported attributes of a given custom element - please let me know, but either way I think that property-information should only consider capture as boolean attribute in elements that it's defined on

@jrencz jrencz changed the title Atribute capture treated as boolean outside of HTMLInputElement context Attribute capture treated as boolean outside of HTMLInputElement context Jan 23, 2024
@wooorm
Copy link
Owner

wooorm commented Jan 23, 2024

Please provide information on what you are doing. Actual code to reproduce an issue

@jrencz
Copy link
Author

jrencz commented Jan 23, 2024

In a private project have a custom element (defined as Lit element) named w-search-params-provider

It defines attributes, among which there's capture. Custom element is used on a page in a static generator.
Output is more or less like this:

<!-- (…) -->
<w-search-params-provider capture="foo, bar,baz" />

What it means in context of this component is: "take the values of URL search params named foo, bar and baz and do something with them.

I process such piece of HTML with rehype using rehype-cli without any plugins (I actually use some, but the problem with capture being wiped out occurs without them as well)

I narrowed it down to this line:

const attrs = serializeAttributes(state, node.properties)

https://github.com/syntax-tree/hast-util-to-html/blob/c8d5f675173bb75bde36dd7e01c77010f0c41901/lib/handle/element.js#L79

and 2-3 hops away there's

const info = find(state.schema, key)

https://github.com/syntax-tree/hast-util-to-html/blob/c8d5f675173bb75bde36dd7e01c77010f0c41901/lib/handle/element.js#L168

and that comes from property-information and describes capture as boolean: true

Then there's

 if (info.overloadedBoolean && (value === info.attribute || value === '')) {
    value = true
 } else if (
    info.boolean ||
    (info.overloadedBoolean && typeof value !== 'string')
 ) {
    value = Boolean(value)
 }

https://github.com/syntax-tree/hast-util-to-html/blob/c8d5f675173bb75bde36dd7e01c77010f0c41901/lib/handle/element.js#L176-L183

Now when I looked into this last one I see the concept of info.overloadedBoolean and I'll take a look into that - maybe this is a solution to my case

EDIT: no, overloadedBoolean is something else - it's boolean that may have value

* `overloadedBoolean` (`boolean`)
— the property is like a `boolean` (for example: `download`)
These properties have an on state plus more states when defined and an off
state when not defined

@wooorm
Copy link
Owner

wooorm commented Jan 23, 2024

Thanks for providing info.

This project is from 2015. Custom elements are much more recent.

This project here does not care about tag names. It’s a general, global, list of how HTML works. Adding support for knowing about elements could be interesting, but is involved. Perhaps it’s a better solution though.
But, how would more common attributes work? Say, class, is that still space-separated? Or could it be arbitrary? Is an id still an id?

Is there any reason you think there is a bug in hast-util-to-html instead of hast-util-from-html?
If it is indeed in hast-util-to-html and works throughout all other projects, then that sounds like a quick fix there.

@jrencz
Copy link
Author

jrencz commented Jan 24, 2024

This project here does not care about tag names.

Right, I get it.

It’s a general, global, list of how HTML works.

May it be that a given attribute works differently for one HTML element or elements, and differently for other?


I see that originally might - I guess - be about capture in some different context (I'm not sure what USE_ATTRIBUTE meant)

'capture': USE_ATTRIBUTE | BOOLEAN_VALUE,

But now it's described as related to HTML Media Capture:

// Media capture on `input[type=file]`
// https://www.w3.org/TR/html-media-capture/
'capture',

And capture in a sense of HTML Media Capture is a string:

I tracked it becoming a DOMString at 2017-08-31: https://www.w3.org/TR/2017/CR-html-media-capture-20170831/#status-of-this-document

Actual fragment: https://github.com/w3c/html-media-capture/blob/88efb33a0f8c4509d6f7c41a8492ae048f74a810/releases/CR4.html#L965-L976

but it's a change from enumeration https://www.w3.org/TR/2017/CR-html-media-capture-20170504/#dom-capturefacingmode, not from a boolean, but lack of value was also allowed by that enumeration:

The capture attribute is an enumerated attribute that specifies the preferred facing mode for the media capture mechanism. The attribute's keywords are user and environment, which map to the respective states user and environment. In addition, there is a third state, the implementation-specific state. The missing value default is the implementation-specific state. The invalid value default is also the implementation-specific state.

My guess is that the definition in here just doesn't keep up with the standard which was very new at the time

@wooorm
Copy link
Owner

wooorm commented Jan 25, 2024

May it be that a given attribute works differently for one HTML element or elements, and differently for other?

Not before. Stuff like width is pretty typically a number for example.
I do wonder, as I did in #20 (comment), what happens on custom elements with things like class and hidden; are they classes? Do they make things hidden?

That being said, when some random string is used for width, it should be kept in the hast as a string. And also serialized as that string.

(I'm not sure what USE_ATTRIBUTE meant)

The source of this data originally is React. Which works with virtual DOMs. Some things need to be set as DOM properties and some as attributes. Over the years, the data specific to virtual DOM use cases was removed.

My guess is that the definition in here just doesn't keep up with the standard which was very new at the time

capture is still not in the HTML spec (the living document, maintained by whatwg).
That’s why it’s in next in tests.
It moving to a string however is something that should be reflected here. And should solve your problem.

@wooorm wooorm closed this as completed in 172b09b Jan 25, 2024
@jrencz
Copy link
Author

jrencz commented Jan 25, 2024

For now I decided to just raname the attribute of the custom element, which I happen to be not only the consumer but also an author of 😅, but I'll check and I'll come back with whether it helps with change reverted or not

The question of width or class is definitely a good question to be asked - I honestly don't know yet, bit I'll try those as well. Those two are for sure interesting as they seem to be more of a property of element in document - whatever that element would be - than an input of element (like captute is).

My guess is that they will either work as they used to or they will both work that way and be treated as any other inputs - it will depend on the internals of the custom element how it reads inputs. It's a getAtrribute() call at the very bottom.

It's pretty clear that one may not try to alter behavior of width or class. It looks like a gray area.

Same is in case of using attributes which may later become defined: in my case it was like this, that I wasn't even aware of existence of capture. If it was in fact a global attribute, I (or consumers of my custom element) would be in trouble supposing capture wasn't global when element was authored and becomes later. I wonder if it's even safe to add any new global attribute to the spec after custom elements were added 🤔

@wooorm
Copy link
Owner

wooorm commented Jan 27, 2024

👍

There is also the case where custom elements can “inherit” from a particular element. You can make a my-button and have the attributes work the same as a button. So there are definitely cases where you want custom elements to work like regular elements.

For the global attributes, yes, id, tabIndex, className etc, all “apply” to custom elements too. The HTML spec could always add more global attributes.

There’s always data-* attributes that can be used by custom element authors.

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants