lwc icon indicating copy to clipboard operation
lwc copied to clipboard

Enable inline css AND dynamic css in the same element

Open AllanOricil opened this issue 2 years ago • 4 comments

Is your feature request related to a problem? Please describe.

At the moment I can't do this

<template>
<div class="style-that-never-changes" class={elementClasses}></div>
</template>

I have to do something like

<template>
<div class={elementClasses}></div>
</template>
controllerVariable = false;

...
get elementClasses(){
return `style-that-never-changes ` + this.controllerVariable ? ` other-class` : null
}
...

I would like it to be implemented because there are classes that will always be part of the template, and leaving them in the template makes it easier to read and understand its structure.

This is possible in other frameworks, like vue.

AllanOricil avatar Feb 04 '22 01:02 AllanOricil

This can be extended to style

AllanOricil avatar Feb 04 '22 19:02 AllanOricil

I agree with you @AllanOricil the current DX regarding static/dynamic styles and classes isn't great. There is certainly room for improvement here.

From day 1, we want to ensure that LWC templates are HTML spec-compliant. I don't think reusing the attribute name multiple times on the same element is the correct approach here since it results in an HTML parsing error: https://html.spec.whatwg.org/#parse-error-duplicate-attribute.

I see 2 major pain-points in the way dynamic class and styles attributes are handled today in LWC:

  1. The need to use string concatenation to build the value: eg. "static " + this.value ? " dynamic" : "" or "color: " + this.color
  2. The fact that those properties are defined in JavaScript, and not in the template.

Today, the class and style attributes in LWC templates only accept string values. We could, for example, make the LWC engine accept arrays and objects, to address pain-point number 1. This is quite similar to what Vue is doing in terms of class and style binding.

We have had multiple discussions about this in the past, but I think that it would be beneficial for LWC to allow more complex template expression. We still have a long way to go, but I am hopeful. This can solve pain point number 2.

Here is the same example, if we were to relax class bindings and allow more complex template expressions:

<template>
  <div class="{['style-that-never-changes', { 'other-class': controllerVariable }]}"></div>
</template>

pmdartus avatar Feb 07 '22 11:02 pmdartus

@pmdartus this way you showed would be a good solution in my opinion. It would also be nice if the "controllerVariable" could be a getter. And I would also like the class to accept an Object, where keys are the class names and the values are booleans to tell the template engine which ones should be added to the html

<template>
  <div class="{getterThatReturnsObject}"></div>
</template>
get getterThatReturnsObject(){
    return {
     'class-1': this.shouldItAppear(),
     class2: this.myControllerVariable
    }
}

AllanOricil avatar Feb 07 '22 13:02 AllanOricil

It would also be nice if the "controllerVariable" could be a getter.

Yes, that's what I had in mind. From the template perspective, getter and class fields are identical. Both are expressed member expression lookups.

pmdartus avatar Feb 07 '22 13:02 pmdartus