It would be nice to be able to spread bindings in lit-html. One would be able to spread properties, attributes, and event listeners.
Syntax could look something like this:
const spreadable = { '.property': 1, 'attribute': 'foo', '@click': handler }
html`<div ...=${spreadable}>How convenient</div>`
This feature request was discussed at length in this pull request: https://github.com/Polymer/lit-html/pull/213
We're investigating the tradeoff between convenience and bloat associated with this feature. This issue is for feature tracking.
Here's an implementation of this feature: https://github.com/Polymer/lit-html/pull/925
It added 0.18 KB to the minified and gzipped package size, for a new size of 3.46 KB.
Questions:
uuhhh nice ๐ค - I am probably biased but I would say it's worth the cost ๐ค especially as I would consider it sort of a core features the same as ? or @ or ....
The updating mechanism for this is fundamentally different from how current property/attribute setters work. How will caching/updating things work? What if you spread one less property than in the previous render, does it remove the property from the node? Does it remember the previous value for every property ever spread indefinitely, so it can do updates only when the values changed?
How will caching/updating things work?
At least in #925, Parts are still created for each key-value pair in a spread object. The intention is for each attribute/property/event in a spread object to keep its setValue and commit behavior, including dirty checking.
What if you spread one less property than in the previous render, does it remove the property from the node?
Our thinking is that if a key-value pair is removed from the spread object, that attribute/property/event would also be removed from the element.
I am very excited for how this spreads attributes. The possibility of simplifying passing and template writing is real here. Hope some important questions can find answers/documentation to move this forward.
However, I'm a little wary that the work to form an object to {'.value': bar, '@click': baz, '?disabled', bot} is just about the same as:
<input
.value=${bar}
@click=${baz}
?disabled=${bot}
/>
With the various part types applied via the same ... attribute I'm not sure the extension of the syntax really buys much. I'd also say this would be better as _only_ an attribute or _only_ a property spreader, but I feel there will be as much confusion on either side of the barrier.
I think what would be closer to expectation would be something like ..., ...., @..., ?..., but I can't imagine that could be handled with such a small addition as is being employed in the PR at this point and I understand that it's quite a complicated hurdle when learning the syntax.
@Westbrook I get the concern around object keys. My thinking with keeping the keys aligned to the existing syntax is that once on the JS side of things, regular functions can map the names, ie:
const propsFrom = (o) => ({...Object.entries(o).map(([k, v]) => [`.{k}`, v])});
const eventsFrom = (o) => ({...Object.entries(o).map(([k, v]) => [`@{k}`, v])});
const obj = {value: 'foo', tabIndex: -1};
html`<input ...=${propsFrom(obj)}>`;
@justinfagnani that makes sense and solves most of what I'm getting at. Would that mean that something like: <input ...=${propsFrom(objProps) ...=${eventsFrom(objEvents) ...=${objAttributes} /> will be possible?
And, do you think lit-html will vend these helpers?
I'm not sold that this provides anything _genuinely_ necessary, not something I'd want to pay a price in terms of bytes and possible performance / complexity for anyway. I hope if it's added that it's an ignorable thing that the majority of people who will never need or use it won't have to "pay" for.
It sounds like just another DSL layer to pass into the existing templating DSL
for a concrete user case we have lot's of small "templates" - here is one in "psoidocode".
export function fooTemplate(options) {
return html`
<button
@click=${options.button1click}
?disabled=${options.button1disabled}>${options.button1label}</button>
<button @click=${options.button2click}>no</button>
`
}
// other file
import { fooTemplate } from './fooTemplate.js';
class Foo extends LitElement {
render() {
const fooOptions = { button1click, button1disabled, button1label, button2click };
return html`${fooTemplate(fooOptions)}`;
}
this has 2 drawbacks:
1) if anyone "extends" my class and he want's to extend then it becomes quite complex as they will need to also copy all the "logic" => which makes it rather fragile as if something get's added to the original template I will need to copy and adjust again
// example I want to wrap the 2nd button in an extra div as my styling is different
export function myFooTemplate(options) {
return html`
<button
@click=${options.button1click}
?disabled=${options.button1disabled}>${options.button1label}</button>
<div>
<button @click=${options.button2click}>no</button>
</div>
`
}
2) whenever I want to add an additional property/content I will need to add it to the fooOptions, fooTemplate function and fooTemplate template literal.
if ... would be available it would make it easier to maintain an extension layer.
// example I want to wrap the 2nd button in an extra div as my styling is different
export function myFooTemplate(options) {
return html`
<button ...=${options.button1}>${options.button1label}</button>
<div>
<button ...=${options.button2}>no</button>
</div>
`;
}
Doing so the code I am extending can still add additional attributes/properties/events if needed without the extender needing to do anything.
PS: deliberately not using object destructuring on this example to make it "easier" to compare
@CaptainCodeman I sympathize with that opinion a lot. To be clear, we're not _definitely_ going to land this, but we wanted to see what a new implementation would look like and how much it would cost. I do want to see concrete use cases, and on that front, thanks @daKmoR :)
I wonder if anyone with experience with React spread props can help us see if the use cases translate. At a glance the one form their docs page doesn't: https://zhenyong.github.io/react/docs/jsx-spread.html
Personally, this feature feels like syntax sugar to me, and I don't think it adds significant new capabilities to the library. I'd welcome this as a directive, but I'm not sure adding additional overhead to the core library is worth it to me. I understand the use case of having a dynamic set of properties, and wanting to keep a declarative format. However, I have not encountered this case in any of the the projects that I have worked on, so that makes me feel like it's not a common case. To me, this change will effectively be 5% additional overhead.
I _did_ encounter several developers who would like to use spread operators in their templates, not because their properties are dynamic, but simply because they like the style. I do expect that when this feature is added, that a significant number of developers will adopt this as a default way to bind their properties for that reason. If this feature has a performance cost compared to normal static bindings (which I believe it does), that may be an additional reason to be careful with adding this feature. Having different ways to do the same thing is generally not a great pattern in software.
As a user, i'd like to give my 2c here as well, and I'm with captaincodeman and ruphin on this one. I don't see how this adds significant value for whats seemingly only a 'nice to have'/sugar/familiarity with other frameworks. Also having to use helpers like <input ...=${propsFrom(objProps) ...=${eventsFrom(objEvents) />, or pre-define objects as {'.value': bar, '@click': baz} seem to beat the purpose of the simplicity of the spread operator.
I originally envisioned this as an optional helper or directive. So the
overhead to the user would be optional, no?
The current proposed implementation is a builtin, so it is not optional.
This is a way to make this optional by subclassing the DefaultTemplateProcessor:
export class SpreadTemplateProcessor extends DefaultTemplateProcessor {
handleAttributeExpressions(
element: Element, name: string, strings: string[],
options: RenderOptions): ReadonlyArray<Part> {
if (name === '...') {
// Only one part per key is allowed via Spread
const attributeHandler = (name: string): Part =>
this.handleAttributeExpressions(element, name, ['', ''], options)[0];
return [new SpreadPart(element, attributeHandler)];
}
return super(element, name, strings, options);
}
}
export const spreadTemplateProcessor = new SpreadTemplateProcessor();
export const html = (strings: TemplateStringsArray, ...values: unknown[]) =>
new TemplateResult(strings, values, 'html', spreadTemplateProcessor);
export const svg = (strings: TemplateStringsArray, ...values: unknown[]) =>
new SVGTemplateResult(strings, values, 'svg', spreadTemplateProcessor);
To reiterate, this issue is very much up for debate and in no way guaranteed to to be added. One reason @straversi worked on this was to at least close out the oldest PR we had and use this as a tool to get to know the library. Those purposes are satisfied even if the new PR gets closed out too.
I think this subclass example is the right balance. It's optional (cost)
and a useful use case solution (benefit). Thanks for consideration. If it
doesn't land, it could be added to example docs, etc. at the least. Cheers.
Per @ruphin
Having different ways to do the same thing is generally not a great pattern in software.
Thus the lift would need to be sufficiently great that it justify the increased surface area of the learning interface.
hello friends
i want to be clear about the premise of this discussion
are we skeptical about the spread feature altogether?
or are we really only skeptical about adding @click and ?bool and .prop syntax to the spread feature?
i hope it's just premise 2, because the basic ability to spread simple string attributes will save me a lot of ugliness โ please humor me about my use case with a video element i'm working on, i want help finding the best practice here
<my-video
title=${video.title}
description=${video.description}
numeral=${video.numeral}
thumbnail=${video.thumbnail}
duration=${video.duration}
>
</my-video>
this obviously isn't scaling well, so i assumed i'd use spread, as is familiar in other templating libraries and also javascript generally, <my-video ...${video}></my-video>, and i was surprised to find myself here in this thread instead of in lit-html's spread feature documentation
i can hear you say it already: "just use .video=${video}"
however i cannot, because this component is intended to be used via pure html (neither js nor lit-html are required), and since string attributes are what pure html supports, that's what my video component accepts โ it's a good user experience for pure html usage
however in lit-html, without spread, the user experience of this component is bad โ when you are handed a video object, you have to be as verbose as my bad example above
from what i've gathered, there seem to be two possible resolutions to my dilemma
spread for lit-html would simply knock this problem out of the park
i should always implement both interfaces โ <my-video> could accept all of the string attributes from pure-html users, but then also accept a .video property from js โ then i must have some disgusting logic in the lit-elements like this.videoActual = this.video || this or perhaps Object.assign(this, this.video) โ one caveat to this workaround is that the video object cannot have a child video property of the same name โ (edit: somebody in this thread mentioned that it's bad in software to have two ways of doing the same thing, so here i think about the duplication that this lack of spread is forcing me to endure, forging two separate routes in my lit-elements to pass the same information)
obviously until spread lands, i'll be using resolution 2 as my workaround, but i'm not really sure if it's pretty cool, or kind of hacky
maybe there's a better remedy for my use case? or a different way of thinking about the problem? i'd love to hear different perspectives about how you folks think around this kind of use-case
:wave: thanks fellas
I'm skeptical that it's really required, especially with the extra needs for the different types (props, attributes, events) and because it will impact package sizes + perf (I assume).
For your example, I'd rather use something like:
<my-video .video=${video}></my-video>
I'd have the video element responsible for understanding and handling the video object passed into it.
It might come down to coding style (and using a lot of Go) but I've just found it easier if I add a property to an object if I don't have to go updating all the element signatures. Just like if you passed an object to a function vs the individual values as primitive types (e.g. do you break an address into street / city / region / country / country / postal code or just pass "address").
It may depend on whether you are building elements for in-app use vs public consumption. There's a stronger case for using primitive types for the latter so they behave more like regular elements, allowing attributes to set properties etc... but if you're binding to the properties in lit, I don't see why you wouldn't pass an object instead of breaking the object up just to make the call.
@CaptainCodeman
For your example, I'd rather use something like:
<my-video .video=${video}></my-video>
i'm afraid you've missed my point
as i mentioned in my previous post, using the .video=${video} syntax is not a valid option for my use-case, because we want to allow simple configuration via html attributes (without having to use javascript or lit-html)
the pattern you described is only possible when using lit-html, and actually then cannot be configured simply via html attributes
in typescript terms, MyVideo component implements the Video interface, whose properties are realized in terms of html attributes โ this is simple, and makes for a good user experience for html-only users
There's a stronger case for using primitive types for the latter so they behave more like regular elements, allowing attributes to set properties etc... but if you're binding to the properties in lit, I don't see why you wouldn't pass an object instead of breaking the object up just to make the call.
exactly as you said it, "so they behave more like regular elements" is a requirement for my use-case
but if you're binding to the properties in lit, I don't see why you wouldn't pass an object instead of breaking the object up just to make the call.
exactly the point: in some cases, we're not using lit, just html
my concern is that if this use-case is overlooked, lit won't play seamlessly with other components in the ecosystem because we can't nicely use an element configured by many attributes
i see the lack of spread as an interoperability problem
i'll use my workaround for the time being, however i'm open to any alternative solutions
I don't quite follow - if you're creating a component for public use and want to support the separate attributes then how does the spread operator help _you_? Aren't they going to be consuming those attributes / properties separately (so they are already split up)? Your example has them using lit which is maybe where I'm confused (and I have flu, I may re-read this in the morning and realize I'm talking gibberish)
Is it that you are then passing those elements on to a child element? In which case, if you're then back at the point where you can just pass them as an object - the same object that you might want to "spread" (?)
@CaptainCodeman
I don't quite follow - if you're creating a component for public use and want to support the separate attributes then how does the spread operator help you?
we need robust components that are easy to use in different contexts
<my-video title="cool video" description="very cool video"><my-video {...video}><my-video ...${video}><my-video ...${video}>as i mentioned before, i can use that workaround having two separate ways for each component to ingest data โ however that's a special thing i'd have to do just for lit-html users, because lit-html lacks this common feature in a flourishing ecosystem that includes the interplay of many different templating libraries
edit: the interoperability concern: imagine you're consuming a web component whose author used htm, and it accepts a hundred different attributes, and it gives you an api function which returns an object for all of those attributes โ the author is expecting you to spread, just like you do in htm or in jsx or in esx โ however because you are a lit-html user, you're now in a pickle: you have no recourse but to map every single attribute like in my bad example, or fork the component to add the workaround specific to lit-html โ i hope this helps illustrate how spread is actually an important feature for lit's interoperability with the ecosystem
i'm curious about why the syntax includes the equal sign?
<my-video ...=${video}>
other templating languages are not using an equal sign for spread (jsx, esx, htm, even javascript itself)
<my-video ...${video}>
in this proposal, is the equal sign optional?
The equals sign is not optional, because of how the parser works. The spread is interpreted as a special case of an attribute, which requires the equals sign.
Supporting the spread without equals sign would require changes to the parser.
@ruphin
Supporting the spread without equals sign would require changes to the parser.
yes, changing the parser to implement the new feature would be progress ๐
are there any other reasons to require the equal sign, besides the parser work being hard?
We're currently deciding if 5% additional library size is a good tradeoff for adding a spread feature, and opinions are divided on this point.
I think it will be very difficult to get broad support for significantly increasing the library size, only to make a minor change to the syntax.
Everything in software is a tradeoff. Making changes is not always progress.
i created issue #934 "spread syntax proposals" with hopes to discuss and compare syntax possibilites for spread, and hoping to avoid overcrowding this thread
@straversi, @westbrook, and @justinfagnani: the new issue attempts to round up the syntax ideas you've all been discussing
@ruphin
We're currently deciding if 5% additional library size is a good tradeoff for adding a spread feature
of course i think spread is well worth the weight, to solve the interoperability problem, but there's no reason to argue about it:
i propose we make spread an opt-in feature, so that it doesn't affect the size or performance for users who don't use it
one possible manifestation of this could be
import {html} from "lit-html/extended.js"
// spread is available here
maybe there are other goodies that could join spread in the extended area
if i recall correctly there used to be extended functionality in lit, i suppose it was merged at some point
there are also other ways to manifest this opt-in feature: perhaps a separate package could implement spread by replacing portions of the lit-html parser through clever hooks, etc
edit: the good news is that the lacking-spread interoperability problem only affects lit-html's consumption of certain components, and so making spread opt-in still actually resolves the interoperability problem ๐
I'm not a fan of it. I don't understand the problem it's solving. It seems to obfuscate the wonderfully expressive element syntax.
What I see happening is encouraging the writing of large monolithic application type elements instead of encouraging composition and intentional thought into component / element design.
For example, 20 attributes/properties/event bindings put in an array keeps my markup fairly clean with this spread implementation - however, if I'm forced to look at the mess I'm creating, I'll be encouraged to break it apart and into smaller and more specific elements.
We are building an application with lit right now, and we have layers and design constraints we apply to our elements. It's working wonderfully and I don't see this syntax adding anything of value to us. I'm open to being convinced to the contrary, though.
We use and like lit because it is light weight "sugar" - rather than a framework.
It would be nice to be able to spread bindings in lit-html. does not seem like a reasonable argument. If it's not broke, don't fix it. Please.
Definitely down voting this one until someone can tell me how this adds value.
@chase-moskal While it's very clear you want this new behavior - here's a few other options.
Finding that adding too many attributes to a single element is unsustainable, you might consider decomposing your element into a few different element or utilize some other strategies like slots. Generally speaking, this will give you and your customers a more flexible solution. A purely hypothetical example:
<my-video
title=${video.title}
description=${video.description}
numeral=${video.numeral}>
<img src="${video.thumbnail}" slot="video-thumbnail" />
<video-control duration=${video.duration}></video-control>
</my-video>
@chase-moskal I don't think we need another issue to discuss the syntax, we can do that here, though there are constraints on the HTML syntax that pretty much determine the syntax for us.
@chase-moskal
yes, changing the parser to implement the new feature would be progress
Not really. The fact that we have "parsing" at all (it's not really parsing, because it's not fully context aware and doesn't build any representation) is a bit of a wart and we'd like to leave ourselves an eventual out. The more custom features we add, like special spread syntax, self-closing custom elements, dynamic element names, the more we're going to always be locked into a complex scanning phase of template prep.
@chase-moskal again :)
Regarding attributes vs properties, this is already something that built-in elements have to contend with. Consider the data attributes and the dataset property, the style attribute and the styleproperty, or the class attribute and the className, and classList properties.
I don't think it would be that unusual to have a data object that synchronizes with multiple attributes. We could think about how to make that easier with a helper.
I am just thinking out load here ๐
how about moving the logic into a directive?
import { spread } from 'lit-html/directives/spread.js';
const videoData = {
'.foo': 'fooprop',
'bar': 'barAttribute',
'@click': ev => console.log('clicked', ev),
};
return html`<my-video ...=${spread(videoData)}>`;
would that still allow for performant updates?
PS: ... would be just a fake in that case - you could easily also say bar=${spread(videoData)} right? I would consider using ... as a best practice in that case.
I'm not in favor of straying into, or further into if we're calling the very limited one in plac, a custom parser. I know I favored the spread feature, but as the discussion progressed I'm starting to regret that initial reaction. I'm asking myself, and others, whether the additional overhead is worth it. Adding a custom parser potentially seems slippery slopish.
html`<my-video ...=${spread(videoData)}>`
โ๏ธ will not need any parser changes
html`<my-video ...=${videoData}>`
โ๏ธ will only need a very small addition to identify ... beside already supporting ., ?, @
html`<my-video ...${videoData}>`
โ๏ธ that will need some more "advanced" parsing => so imho not a good idea
@daKmoR I do like the idea of making this 100% opt-in via the directive approach.
@straversi and @justinfagnani do you two think that would be a viable approach for this situation? If the idea would already be to suggest users do:
const propsFrom = (o) => ({...Object.entries(o).map(([k, v]) => [`.{k}`, v])});
const eventsFrom = (o) => ({...Object.entries(o).map(([k, v]) => [`@{k}`, v])});
const propsObj = {value: 'foo', tabIndex: -1};
const eventsObj = {click: fooMethod};
html`<input
...=${propsFrom(propsObj)}
...=${eventsFrom(eventsObj)}
>`;
Then tweaking that a little to be:
import {propsFrom} from 'lit-html/directives/props-from.js';
import {eventsFrom} from 'lit-html/directives/event-from.js';
const propsObj = {value: 'foo', tabIndex: -1};
const eventsObj = {click: fooMethod};
html`<input
...=${propsFrom(propsObj)}
...=${eventsFrom(eventsObj)}
>`;
Seems like a reasonable alternative here, right? In the case that this actual separates us from the ... attribute requirements of the parser approach, this could even open a good practice pattern of being more declarative and using spreadProps=${propsFrom(obj)} or similar to clarify what's actually happening in our template code with this usage...
Discussion has died down -- in my opinion the most convincing case for spread syntax is @chase-moskal's interop case. However, I agree with other viewpoints that it's not worth (a) adding complexity that needs to be maintained and (b) obfuscating expressive @, ., and ? syntax, and (c) adding KB to the package.
As others have suggested, I think this functionality would best be implemented by a directive so folks can pull it in if the need interop, or have a compelling individual case for using spread.
@justinfagnani Should we close this, and perhaps add an issue for a spread directive?
@straversi I think we can keep this issue, and rename to "add a directive...". Might as well keep the conversation in one place.
I think solving this could be quite useful in some scenarios. Myself I know I will use a spread operator to limit duplication where I need a common set of props/attributes used on different elements. While dynamic tag is not possible
let tag = 'element-one'
if (condition) {
tag = 'element-two'
}
return html`<${tag} prop1="" prop2="" prop3="">`
I could gather the shared props and spread them to one or the other
const props = { prop1: '', prop2: '', prop3: '' }
if (condition) {
return html`<element-two ...="${spread(props)}">`
}
return html`<element-one ...="${spread(props)}">`
One question though @straversi to your implementation. What happens when in subsequent runs a key is removed from the spread object? Something like
function spread(props) {
return html`<my-element ...="${spread(props)}></my-element>`
}
spread({ hello: 'world', foo: 'bar' })
spread({ hello: 'world' })
Will the foo attribute/property get unset on the element?
@tpluscode Yes, the foo attribute would be deleted from the element in the proposed implementation. Same for properties.
A case I'd really like this for is testing and storybook
/**
* Generates a spread of story parameters
* @param {String} title Story Title
* @param {Object} properties Element properties to set
* @return {Array<[String, () => TemplateResult]>} Story to Render
*/
function story(title, { renderers } = {}) {
const { rows, columns, select } = require(`../test/${title.toLowerCase()}/input.json`);
const render = () => html`
<fc-table
.rows="${rows}"
.columns="${columns}"
.select="${ifDefined(select)}"
.renderers="${ifDefined(renderers)}"
></fc-table>
`;
return [title, render];
}
vs
function story(title, defaults = {}) {
const configuredProps = require(`../test/${title.toLowerCase()}/input.json`);
const render = () => html`
<fc-table ...="${spread({...defaults, ...configuredProps})}"></fc-table>
`;
return [title, render];
}
And you can imagine a similar function for setting up test fixtures.
Irrespective of syntax or implementation, this would be really helpful in large projects.
We also have some neat-o configurable UI features in our app that would really really benefit from this.
@customElement('configured-container')
class ConfiguredContainer extends ApolloQuery {
query = gql`
query Controls($userId: ID!) {
user @client { id @export(as: "userId") }
controls(userId: $userId) {
required
type
value
label
}
}
`
render() {
return this.data.controls.map(control => html`
<configured-control ...="${spread(control)}"></configured-control>
`)
}
How cool would that be? would really save us time.
Again, I have no strong opinions on where and how to implement. One thing I really appreciate about the polymer team is that you take the needs of users other than "Senior App Jockey at HuugeCorp".
Any progress ?
In the case of a generator where the api of the underlying custom-element isn't always known providing a utility to spread attributes/properties/events would be helpful.
This is a basic property spread directive you can use:
const previousProps = new WeakMap();
const spreadProps = directive((props) => (part) => {
const prev = previousProps.get(part);
if (prev === props) {
return;
}
previousProps.set(part, props);
Object.entries(props).forEach(([k, v]) => {
if (v !== part.committer.element[k]) {
part.committer.element[k] = v;
}
})
});
You use it like so:
render(
html`
<my-element ...=${spreadProps({ foo: 'x', bar: 'y' })}></my-element>
`,
document.body,
);
Dirty checking might be improved by instantiating child parts, I'm not 100% sure. Setting event listeners is a lot more tricky as you need to be careful not to register multiple listeners.
See it in action in a jsbin: https://jsbin.com/qayaneheka/edit?html,output
We created @open-wc/lit-helpers for these kinds of directives, so that we have a place to experiment and see whether certain functionality is useful before it is added to lit-html officially. https://open-wc.org/developing/lit-helpers.html#spread-directives
Only my 2cent i am doing string preperation lets call it pre string processing befor i pass data to lit-html that works performant and even can overcome problems i don't need any directives as the pre processor is the directive and the updates are blazing fast and consistent as lit-html nevery needs to re render a table no matter what methods i used to do the string pre processing .
String Pre Processing befor handing over strings and arguments to lit is efficent fast and successfull it ads no new syntax and is transperent apply able.
i degrade lit-html to a apply bindings handler and that is what it is great for.
no need to say that this way SSR works out of the box great as expect as we handle strings :)
Leaving some feedback here.
I'm trying to migrate a codebase where it's not uncommon to see form control components, such as a custom textarea for example, render an unknown number of "data-*" attributes given by the user through arguments.
I'm not seeing a way to support this with lit-html, outside of maybe just abusing unsafeHTML. Right now it seems like the choice is between not supporting this, which impacts a lot of teams and code (and styles), or loosing all the lit-html things that made it an appealing library to begin with...
I thought it might be worth mentioning.
@ferhtgoldaraz your conclusion is correct using template string literals and return a additional script tag in it is the way to go for custom elements this days.
@ferhtgoldaraz the spread directive linked above (https://open-wc.org/developing/lit-helpers.html#spread-directives) should be able to do this for you right now.
The current plan is to have a built-in syntax for lit v2: https://github.com/Polymer/lit-html/issues/1182
@LarsDenBakker awesome, thanks for the link, good to know
FYI, while we are going to make some progress with lit-html 2.0, we likely won't have spread out-of-the-box just yet with 2.0's initial release. The reason is that we're still working out how we would manage conflicting attributes/properties. Some use cases that we have from other template systems at Google actually call for the ability to merge attribute values. So we're going to allow directives in "element position" at first, and build out over time.
@ferhtgoldaraz the spread directive linked above (https://open-wc.org/developing/lit-helpers.html#spread-directives) should be able to do this for you right now.
That link seems to be broken now. Looks like the page has moved here (without redirect):
https://open-wc.org/docs/development/lit-helpers/#spread-directives
Most helpful comment
uuhhh nice ๐ค - I am probably biased but I would say it's worth the cost ๐ค especially as I would consider it sort of a core features the same as
?or@or....