WICG / webcomponents

Web Components specifications
Other
4.38k stars 374 forks source link

[idea] Allow HTML Element attributes to accept any type of value, not just strings. #519

Closed trusktr closed 8 years ago

trusktr commented 8 years ago

517 covers two things:

  1. ability to define attributes for custom elements (and optionally specify getters/setters for those attributes)
  2. Ability for DOM API to accept anything, not just strings, for attributes.

I'd like #517 to be about the first idea, and would like to make this issue specifically about the ability for DOM APIs like setAttribute/getAttribute to be able to accept any JavaScript values besides strings so that we can avoid performance costs from serialization/deserialization. We would be able to pass objects, arrays, numbers, instances of custom classes, etc.

Please see #517 for details (maybe I can move those details here...).

For example, imagine some error component specialized in displaying errors, who's error attribute can accept an actual instance of an Error:

try {
    // ...
}
catch (err) {
    let errorDisplay = document.createElement('error-display')
    errorDisplay.setAttribute('error', err)
    document.querySelector('#error-list').appendChild(errorDisplay)
}

Or, using the setter/getter feature described in #517:

try {
    // ...
}
catch (err) {
    let errorDisplay = document.createElement('error-display')
    errorDisplay.error = err
    document.querySelector('#error-list').appendChild(errorDisplay)
}

I really think making APIs easier to use (f.e. opt-in setters/getters mechanism for attributes on Custom Elements, not requiring serialization/deserialization by allowing attributes to accept values other than strings, etc), is a good goal for Web stack to have!

ghost commented 8 years ago

Honestly, I think that’s a better job for frameworks to do rather than the platform.

Attributes are meant for simple string usage. If you want something more complex, you can simply have a property that is not bound to an attribute.

All I wanted is to have a certain pattern that HTML elements’ property names are guaranteed to never follow. (For example, I want a guarantee that HTML elements’ properties are never going to start with data, so I can safely define my own dataFooBar property/function on my custom elements, and know it will never collide with HTML’s properties). Of course not starting with data is a horrible pattern to follow. They are horrible enough, the data- attributes we have today.

trusktr commented 8 years ago

I think that’s a better job for frameworks to do rather than the platform.

@Zambonifofex Why?

ghost commented 8 years ago

@trusktr Generally, attributes are meant for authors to communicate with the DOM, and not for JavaScript to communicate with other JavaScript. That’s what properties are for.

When I say that that’s a job for frameworks, I think that they should simply allow foo="13" to be seen as a number instead of a string. Not for full serialization/deserialization of objects.

trusktr commented 8 years ago

@Zambonifofex Yes, but now that Custom Element are living thing, part of those "DOM" that you are referring to are JavaScript objects. It no longer makes sense to require converting attributes to strings when those DOM elements receiving the attributes are also JavaScript objects.

Allowing non-string attributes makes the DOM API better because JavaScript-based DOM (Custom Elements) won't be hindered by the unnecessary performance cost of string serialization/deserialization...

Imagine: if we have 10 layers of ShadowDOM trees (very easy to do in a webcomponent-based app), then that means there can be up to 10 serializations and 10 deserializations (20 total) just for data to flow from element to element from the outter tree to the most inner tree.

That is obviously not a good thing.

ghost commented 8 years ago

@trusktr it will always only be possible for authors to specify strings as values for attributes.

unnecessary performance cost of string serialization/deserialization...

But that’s the point I’m trying to make: you don’t have to do any serialization/deserialization; you can simply have a property that is not bound to an attribute.

trusktr commented 8 years ago

it will always only be possible for authors to specify strings as values for attributes.

No, not if the spec is changed. The spec was changed in order to add Custom Elements, and it's possible to further change it to allow non-string attributes.

But that’s the point I’m trying to make: you don’t have to do any serialization/deserialization; you can simply have a property that is not bound to an attribute.

Then, how does the server send data to the client? It sends it as a string, which needs to be deserialized. Those strings can be inside HTML attributes. Deserializing strings is still great, when it comes to parsing an initial HTML payload, but once we have things rolling on the client-side at runtime, we can completely avoid the string-based requirement (assuming we make changes to the spec).

Basically, we still need serialization/deserialization for when we want to generate actual HTML to save somewhere or to receive from a server; it is great. We just need to give Custom Elements more freedom.

@sebmarkbage (one of React's creators) mentioned this string-based problem:

How do you pass data when everything is a string?

(@sebmarkbage Your input on this would be highly appreciated!)

The criticism here (regarding strings and HTML attributes) is huge; it is one of the things that makes the web less appealing to "native" developers.

Example: JavaScript libraries made for animating DOM elements using CSS matrix3d (see some of those libraries listed here) always complain about the awful concept of having to convert matrix number arrays into CSS matrix3d strings just so the strings can be converted back into numbers on the HTML-engine's side. That's flawed, awful, and we shouldn't have to do that.

Plain JavaScript properties aren't exactly the same as attributes, they are not accessible through HTML. Libraries like React ultimately send their props via HTML attributes (as strings) to the built-in elements in the leaf-most components. This is flawed.

The suggestion to "just use JS properties" is only a temporary workaround, not a solution. The complete solution is to allow non-string attributes. The explicit benefits are:

  1. Performance increase
  2. Cleaner code
  3. We still have the ability to serialize/deserialize when sending/receiving HTML code to/from a server when that is what we want. For example, for serialization, a Custom Element can simply ensure that JS object stored in an attribute has a toString method that performs the serialization. When a Custom Element receives an arg via setAttribute, then if the value is a string (which can be caught in attributeChangedCallback), then the Custom Element can perform the conversion, and use setAttribute again to store the actual JS object to use during runtime. Additionally, for further performance increase, the Custom Element can store that plain JS object in a regular JS property if desired.

This proposed change isn't a difficult change to make, and would bring the web forward more.

ghost commented 8 years ago

No, not if the spec is changed. The spec was changed in order to add Custom Elements, and it's possible to further change it to allow non-string attributes.

Okay, how do you expect the syntax to be? How would one differentiate a string attribute from a number attribute? And how would you pass more complex things like objects?

And honestly, I do not understand what’s that superior about attributes compared to properties.

This proposed change isn't a difficult change to make, and would bring the web forward more.

How do you know it wouldn’t be difficult to make? Imagine all the code in browsers and libraries/frameworks that expect attribute values to be strings.

trusktr commented 8 years ago

Okay, how do you expect the syntax to be?

As far as HTML syntax, nothing new, that stays the same. For example:

<some-element some-attribute="anything here is just a string still">
</some-element>

A Custom Element can define any string format they wish (by documenting it). The Custom Element's attributeChangedCallback can parse a string value and convert it into anything (an array, an Object, a number, anything, like currently). For example, suppose I want to store an Object, then I can document in my component's documentation that some-attribute can accept a string like this:

<some-element some-attribute="0, 30, 0">
</some-element>

The attributeChangedCallback for <some-element> can look like this:

class SomeElement extends HTMLElement {
    // ...

    attributeChangedCallback(name, oldValue, newValue) {
        if (name == 'some-attribute') {
            if (typeof newValue == 'string') {
                // if the attribute is a string of comma-separated numbers,
                // convert to an array (i.e. "deserialize").
                this.setAttribute('some-attribute', convertToArrayOfNumbers(newValue))
            }
            else if (newValue instanceof Array) {
                // ... work with an actual array ...
            }
        }
    }
}

function convertToArrayOfNumbers(string) {
    // ... possibly validate syntax here first ...
    return string.split(',').map(str => parseInt(str))
}

As you can see from the example, when a string value is detected, the Custom Element deserializes it into an array of numbers. The advantage here is huge: it means any library like React can pass non-string values directly to leaf-most Custom Elements!

How would one differentiate a string attribute from a number attribute?

I believe my example gives you an idea of that.

And how would you pass more complex things like objects?

My example shows you can pass anything to setAttribute. That's the key. Note, HTML markup would still be string based, not change there, and would require deserialization. The benefits of non-string values would be apparent when using the JavaSript APIs directly (setAttribute, getAttribute). If we use innerHTML to set a component's content, then we're going to have string values and there's no way around that, there's no special syntax to denote JS objects. It is completely up to the Custom Element to handle that.

Furthermore, it is up to the Custom Element to supply ensure that the item stored in an attribute has a toString method. In my above example, Arrays already have a toString method defined. For example, [0,30,0].toString() will result in 0,30,0, which is the string format that the Custom Element expects.

Here's another example that shows how we would convert the comma-separate-number-string into something more complex like a Coordinates object:

class Coordinates {
    constructor(x, y, z) {
        this.x = x
        this.y = y
        this.z = z
    }
}

class SomeElement extends HTMLElement {
    // ...

    attributeChangedCallback(name, oldValue, newValue) {
        if (name == 'some-attribute') {
            if (typeof newValue == 'string') {
                // if the attribute is a string of comma-separated numbers,
                // convert to Coordinates object (i.e. "deserialize").
                this.setAttribute('some-attribute', convertToCoordinates(newValue))
            }
            else if (newValue instanceof Coordinates) {
                // ... work with the Coordinates object ...
            }
        }
    }
}

function convertToCoordinates(string) {
    // ... possibly validate syntax here first ...
    const args = string.split(',').map(str => parseInt(str))
    return new Coordinates(...args)
}

I do not understand what’s that superior about attributes compared to properties.

Can you explain what you mean by "properties"? Maybe I don't understand? Do you mean regular JS properties? If so, plain JS properties aren't hooked into the HTML engine, that's the downside.

How do you know it wouldn’t be difficult to make? Imagine all the code in browsers, libraries, and frameworks that expect attribute values to be strings.

With this change, built-in elements can continue to take/give string values, those parts won't break. However, and in my opinion, if the style attribute of built-in elements can be updated to accept (via setAttribute) an Object with CSS typed-om, that'd be awesome because it would greatly increase performance. For backwards compatibility, the getAttribute method would still return a string. Recommended would be to read an accessor or property (like you mention) to get the Object with numbers in it, skipping the performance cost of the string conversion that will happen when using getAttribute. Etc.

As far as Custom Elements, the API in the wild is v0 right now. It can change. People using Custom Element right now can expect things to break for the better good of the web.

sebmarkbage commented 8 years ago

FWIW React uses properties when it can. E.g. we don't want to first stringify a true/false value and pass the string 'checked' when we can just directly call .checked = true.

The problem is that the ecosystem of DOM, as well as the ecosystem of custom elements, rely so heavily on attributes to do things that should also be available as properties.

If I had my way, custom elements wouldn't support attributes directly but always translate them to property operations so that custom element authors are encouraged to use them - always. Same goes for events. There should always be a property that corresponds to the event. That is mostly true for the built-in DOM but not for things provided by the ecosystem.

trusktr commented 8 years ago

@sebmarkbage

FWIW React uses properties when it can. E.g. we don't want to first stringify a true/false value and pass the string 'checked' when we can just directly call .checked = true.

Good point! That's definitely good to take advantage of when available. It also requires making some sort of runtime whitelist on what is available, which can be avoided for other cases (generic cases that don't have associated properties or accessors) if attributes can accept non-string values.

If I had my way, custom elements wouldn't support attributes directly but always translate them to property operations so that custom element authors are encouraged to use them - always

I think simply allowing non-string attributes is exactly the same solution (but better, because it is already part of spec: DOM elements have attributes and they are set with setAttribute/getAttribute).

I also posted a new comment with examples while you were making your comment. What do you think of those (above)?

As for events, is EventTarget with addEventListener/removeEventListener not enough?

trusktr commented 8 years ago

@Zambonifofex Updated above examples; I forgot to convert items into numbers.

ghost commented 8 years ago

Can you explain what you mean by "properties"? Maybe I don't understand? Do you mean regular JS properties? If so, plain JS properties aren't hooked into the HTML engine, that's the downside.

Yeah, I mean just regular JavaScript properties. And so what if they aren’t “hooked into the HTML engine”? You could simply read from an attribute and set a property:

<my-element data-my-attribute="[1, 2, 3]"></my-element>
class MyElement extends HTMLElement
{
    // ...
    attributeChangedCallback(name, o, n)
    {
        if(name === "data-my-attribute")
        {
            this.myProperty = JSON.parse(n);
        }
    }
}
trusktr commented 8 years ago

@Zambonifofex That works, but it isn't obvious for libraries like React which JS properties to set unless we make a convention, and libraries aren't guaranteed to follow the convention. For example, React will not know to set myProperty on those types of Custom Elements unless React contains a whitelist, and that's not possible to do for the whole internet. In the case of Custom Elements, React (and other libraries) will simply send values via setAttribute, so the advantage of making this feature work with setAttribute/getAttribute is that all the libraries, which depend on that, can would be able to pass JS objects, not just strings.

There's no standard on how to map plain JS properties to HTML attributes. Could that be a standard? For example, I already made one such proposal. If something like that existed, then React and other libraries could standardize on using those JS accessors. I would be open to that solution as an alternative (although I think I still prefer attributes more, and those are already standard).

sebmarkbage commented 8 years ago

@trusktr That's true for events too. Libraries like Polymer have to make up their own convention like the on- prefix to determine if something should use addEventListener or setAttribute. So you'd have to make it common practice to set event listeners through setAttribute too.

ghost commented 8 years ago

You can keep then with the same name.

class MyElement extends HTMLElement
{
    // ...
    attributeChangedCallback(name, o, n)
    {
        if(name === "data-my-attribute")
        {
            this["data-my-attribute"] = JSON.parse(n);
        }
    }
}

Or convert then from dash-case to camel-case and vice-versa.

But honestly, I think libraries/frameworks should interact directly with the property instead of with the attribute, having the attributeChangedCallback only be used to allow authors to provide a value to the property from HTML.

trusktr commented 8 years ago

I think libraries/frameworks should interact directly with the property instead of with the attribute, having the attributeChangedCallback only be used to allow authors to provide a value to the property from HTML.

That would work, but it's not a convention that everyone is guaranteed to follow. On the other hand, it is guaranteed that getAttribute will always be used to get values from the original HTML, and likewise pairing setAttribute with that guarantee would be something that everyone would be able to follow.

As @sebmarkbage mentioned, they try to use properties when possible in React, and setAttribute is a fallback. If we make the fallback (setAttribute) work with non-string values, libraries wouldn't need to have a runtime whitelist of what properties to use and when to fall back on setAttribute. HTML element attributes are the guaranteed description of what data an characterizes an element, so I think relying on those is better than properties because properties aren't guaranteed to exist, but attributes are. Servers can't set properties, they can only set attributes, and I think that having a client-side library depend on attributes will make interop between server and client better without having to use (possibly erroneous) whitelists.

trusktr commented 8 years ago

Even with properties created based on attributes, libraries will have no idea what these are (they can guess, but it won't be guaranteed). If a library can simply pass an object to setAttribute, problem solved. The receiving element can handle that however it pleases.

ghost commented 8 years ago

The problem is that nothing currently is prepared to handle non-string attribute values. Nor are libraries/frameworks, nor are browsers. To make this work would be a lot harder than it actually looks like. Browsers would have to completely change the way they handle attributes, and that’s not trivial.

properties aren't guaranteed to exist, but attributes are.

I don’t think that I understand what you mean.

trusktr commented 8 years ago

What I mean is that attributes exist everywhere (even on the server-side). Attributes are the defacto way to characterize an HTML element. Properties are second to that, so that's why I like the idea of working with setAttribute (and allowing non-strings) directly.

treshugart commented 8 years ago

What if attribute methods just proxied the properties?

domenic commented 8 years ago

Let's close this. Attributes are strings. Making them something else would make them no longer attributes. You can use properties (and attributes that reflect them) to store other data.

treshugart commented 8 years ago

As a library author who's dealt with this specific problem, I agree with @Zambonifofex and @domenic. Skate, for example, takes cues from React here. The problem with doing this is that you have to come up with an opinionated convention. Having such a convention at a lower-level implementation such as the DOM specification would be very limiting - for something that's supposed to be a core API for libraries to build on top of - and open up huge can of worms because you would have to define behaviour, at the spec level, with what happens to different types of values (and possibly names) when passed as attributes. I'd even be inclined to say that consensus - when trying to converge on said opinionated convention - would be even more difficult to come to. That's definitely something that the spec does not need right now.

trusktr commented 7 years ago

@treshugart I don't agree.

As part of web manifesto, custom element authors should be able to override get/setAttribute in a consistent manner. Sure, the super class setAttribute will convert things to strings. I don't have to call super. I'm not making that convention, it already exists and is defined in the ES6 spec on classes. :)

If that doesn't work, then the HTML engine design is broken.

And it isn't hard to fix!

What will break?

trusktr commented 7 years ago

@domenic

Making them something else would make them no longer attributes.

You always make statements like this. It's like saying "just because".

Better responses would be appreciated.

I'm not trying to be offensive, it's just that you have a history of closing multiple issues of mine (and possibly others') with comments that are honestly not helpful at all. (I'm not going to link any, I'm sure you can remember).

That comment is completely useless. I can say that attributes were strings before. Now I'm saying they don't have to be stored in memory as strings, but getAttribute can return a string, or else the HTML engine can coerce the value to string, and honestly this won't break anything at all. If it will, please provide a more helpful comment.

Otherwise please don't blatantly close issues. (Maybe it feels good to have that power, but I don't think you're using the power to it's full potential).

annevk commented 7 years ago

We can't change setAttribute() like that. There's too many things that rely on attributes being strings (e.g., selectors) and the behavior of the method is to call ToString on arguments passed (per IDL). Changing that would break content all over.

This is also the wrong place to propose changes to core DOM APIs. Those should go to whatwg/dom, but breaking changes of this nature will end up being rejected.

annevk commented 7 years ago

Whenever you think something is easy I recommend trying to go through the implications and changes to processing models that would be required for the change. How would this change affect mutation observers? How would it affect HTML element definitions that assume attribute values are always strings? How would it affect selectors? Etc.

trusktr commented 7 years ago

Changing that would break content all over.

Not necessarily. getAttribute can turn any value, and the engine can use ToString on it for use with selecting.

How would this change affect mutation observers?

It doesn't: a record is queued when setAttribute is called. The new value (string or not) is stored in the record.

How would it affect HTML element definitions that assume attribute values are always strings?

Which element definition for example?

How would it affect selectors?

String attributes would be useful here still. Selection doesn't have to work on everything. Also if an attribute isn't a string, it didn't mean the steering result is not predictable. An attribute with a numerical array value is still easy to select for example. [position="1,2,3"] if the actual value of the array is [1, 2, 3]. Not everything would be easily selectable, but so? How does this break anything?


What I realized though, is that in my use cases so far, I want this feature in custom elements. I can easily override setAttribute to do this. And per web manifesto, I should be able to. It seems difficult to disagree with the ideal of web manifesto, and as love of the web, I would hope we fight for it.

annevk commented 7 years ago

It sounds like you don't understand the complexity of what you're proposing and I'm not sure how to make it clear to you. 😟

l00mi commented 7 years ago

I read this tread some months ago and by chance stumble just now on it again as you're active here: We have the use case that we have component (which draws some nice line-graph and needs data which is a simple js array) this component itself is encapsulated in another higher abstraction component which basically gets the necessary data from an API. Is it possible to give this data from the outer Webcomponent to the inner without going through a json.jsonify and json.parse cycle?

annevk commented 7 years ago

@l00mi can't the inner component expose some kind of method the outer one can invoke with the data?

l00mi commented 7 years ago

Sure, this is possible? Do you got an example handy somewhere?

annevk commented 7 years ago

Well InnerComponent.prototype.giveData = function(...) { } or some such.

trusktr commented 7 years ago

Suppose we want to use @treshugart's SkateJS (with Preact). Now we're using a library (like many others) where handing data to inner components is done by passing data through attributes of inner components.

How do we pass numerical values to the inner elements in this idiomatic form?

With custom elements (and considering Preact passes values into setAttribute verbatim, which is unlike React), this is possible because we can override setAttribute in order to handle non-string values.

This is really good because we can do performance optimization like that! Some have proposed that non-string values should be set on properties of the element, but this would be a convention, and not standard and idiomatic in the way that all frameworks and libraries pass data from outer components to inner components via attributes.


I guess we can do this with built-in elements too by 🐒 patching the specific element interface prototype.setAttribute methods. Maybe that's all we need now that I think about it. I dont care if selecting, or something else, doesn't work with this, as it isn't what I intend to use it for.

I just need DOM not to be so slow!


Seems to me the value of an attribute should only ever be converted to string when it is observed. I.e., when dev tools shows you HTML, it can call getAttribute and coerce things to strings. I.e. when the selection engine looks up an attribute, it can call getAttribute and coerce to string.

Sure, in this case selection will be slower. But my darn WebGL graphics will be faster, and honestly I'm not going to be selecting things 60 times per second, I will be selecting things once, then using a cached reference inside an animation loop.

When animating DOM, converting everything to string so CSS can convert back to numbers, for example, is performance overhead, among other things. TypedOM will.be imperative, not declarative, so I think it is fair to need this performance optimization with attributes.


Anyways, I will try monkey patching the built-in interfaces now that I think about it, I think that may be enough.

trusktr commented 7 years ago

Here's a graphical custom-element example which yearns to be faster, it works out every day towards this goal:

// Scene rendered by React for example

var xRotation = ...;
var yRotation = ...;
var zRotation = ...;

return <three-dee-scene>
  <mesh-geometry rotation={`${xRotation} ${yRotation} ${zRotation}`}>
  </mesh-geometry>
</three-dee-scene>

As you can see, this is dumb. We have to pass string values that will be converted back to numbers. This is like the element choosing to run a marathon with weights on its ankles and wrist thinking it will be faster. The element was supposed to take the weights off before the marathon, but HTML spec told it not to. Three.js wins, it did not have this restriction, but also Three.js does not have the declarative advantage.

Now look at A-Frame @annevk. It is plausible that people will want to stick such elements inside React/Angular/Vue/etc frameworks and libraries. Surely we don't want their apps to have to have absurdly pointless number-to-string-to-number conversions just because they are passing attributes to inner elements.

We would love to help make the web faster (especially for modern graphics, which is my use case and why I brought this whole issue up in the first place).

I'm not just making generic simple 2D applications. I am trying to make 60fps 3D animated applications. And the declarative paradigm of HTML bring much developer productivity. I'd just like to fine-tune performance, and avoiding number-to-string-to-number conversions is one step towards that.

And it has to be done through setAttribute because setAttribute is the one standard thing (not just a convention @treshugart ) that every HTML-enhancing library or framework relies on for passing data (not something else that isn't standard like instance properties).

trusktr commented 7 years ago

Improving the setAttribute standard ( @treshugart ) is closer to standard than the suggestion of using instance properties or anything else, and would be "a convention" the least.

trusktr commented 7 years ago

Here's a live example: http://trusktr.io/polydance (open in Chrome, may not yet work in other browsers)

Here's the part of source code where the 3D scene is described declaratively:

https://github.com/trusktr/trusktr.io/blob/19da2d1754c65af80e9588ab2c1b4aac56e640c7/meteor-app/client/imports/apps/polydance.js#L193-L331

I will be hacking setAttribute and seeing what difference skipping number-to-string-to-number conversion may have. It might be that isn't the biggest bottle neck in this case. I am just looking to find any way to improve performance. I probably have lots of improvements to make on the WebGL structures, and plus React dom-diffing happens every frame but I think that's the cost of most on-top-of-HTML libs in general except for ones that map changes directly (in theory at least, like Turbine which is not yet benchmarked and is not yet optimized).

SoloJiang commented 2 years ago

Should we have a new method for it, which won't break current system. Just like setProperty/getProperty. First of all, it is different from the node's own properties, such as inputNode.value. Its purpose is to help developers pass data to custom element.

Why not set property directly through node.a = 1:

It should follow the following rules:

Also, it can be initialized by createElement, like:

document.createElement('custom-element', {
  properties: {
    name: 'eidtor'
  }
});

For high performance, might we can allow custom element developer declare the type of properties in advance, here is the reason for it, such as:

// Just like Polymer, but the difference is that property changes do not trigger rerender
// The whole action handled by `propertyChangedCallback` hook
class MyCustomElement extends HTMLElement {
  properties: {
    name: {
      type: 'boolean',
      defaultValue: true
    }
  }
}

The above is just my simple idea.

tema3210 commented 2 months ago

People above have asked about the html syntax for the feature:

<my-custom-element name:  %expr% ;></my-custom-element>

the %expr% is plain javascript expression, ; is mandatory.

Given the syntax is new, it can directly change properties, not the attributes. This way users get choice what they specify.

Considering backward compatibility - we can make getAttribute() to also look at properties (but attributes still first), yet always convert to a string type (setAttribute gets upgrade to any type, and sets both attribute, with conversion, and property).

Effectively making attributes a stringified versions of properties.

Can be limited to custom elements only

justinfagnani commented 2 months ago

@tema3210 the hard questions here aren't about putting expressions into HTML - we can clearly do that with (bad) things like javascript: attributes and such. The hard things are doing this securely and defining the scope that expressions would have access to.

Some of these questions may be addressed in the DOM Parts work, where we would like parts to be able to have initial values as rendered by SSR, but the ideas there are still nascent and we haven't yet discussed how that might work for properties (that I know of).