Svelte: Inject multiple classes with class:x,y,z={condition}

Created on 8 Aug 2019  ยท  14Comments  ยท  Source: sveltejs/svelte

Is your feature request related to a problem? Please describe.
Basically, the needed to repeat the code when you want to inject multiple classes using the same condition, or extract the condition logic.

<div
  class='default-style'

  class:px-10={size === 'large'}
  class:py-5={size === 'large'}
>

// or

<script>
  // ...
  $: isLarge = size === 'large'
</script>

<div
  class='default-style'

  class:px-10={isLarge}
  class:py-5={isLarge}
>

Describe the solution you'd like
I'm not sure if it's the best solution, but I was just thinking something like:

<div
  class='default-style'

  class:px-10,py-5={size === 'large'}
>

Describe alternatives you've considered
For now, I'm using this approach to bypass:

<div class={`
  default-style
  ${size === 'large' ? 'px-10 py-5' : ''}
`}>

But it get big really quick, and if you mix different conditions, every time a single value changes, all the conditions need to be evaluated again.

How important is this feature to you?
Well, I was just thinking to improve the flexibility and the possibilities of the class: syntax.

Additional context
Maybe if we use something like a .split(',') and .map() on the toggle_class function, this feature can be added easily. Because, if I use class:x,y,z={true} today, svelte will inject the string x,y,z on the element, literally!

https://github.com/sveltejs/svelte/blob/8e62bd0b276c3d7e7bc6d61da96d82f187e3861e/src/runtime/internal/dom.ts#L233

Tks guys! ๐Ÿ˜„

proposal

Most helpful comment

I think it fits really good with utility first css libs like: https://tailwindcss.com
Actually, that's the main reason I started to think about that feature, haha!

About the flag, well, I think would be a really good solution! ๐Ÿ‘

All 14 comments

That class:x,y,z={true} currently sets a class called x,y,z means that this would be a breaking change. A syntax like class:'a b c'={true} or class:"a b c"={true} is currently invalid and so would be eligible for this new feature. I don't personally feel particularly strongly in favor of adding this though, nor am I sure that the syntax with the quotes is a great idea.

The css class x,y,z is invalid, so we don't have a breaking change on styles.

If you try to do something like:

<div class='x,y,z'>

<script>
const el = document.querySelector('.x,y,z')
</script>

el will be null, so we don't have breaking change on js selects!

Maybe the only scenario of a breaking change is a very specific thing like:

<div class='x,y'></div>

<script>
const el = document.querySelector('div')

const hasClass = el.className === 'x,y'
</script>

or something like that!

I think it's worth, considering the value and simplicify it can add to inject/remove bulk classes.

@marceloadsj The classname x,y,z is valid, you just forgot to escape the , characters in your selector:

<div class='x,y,z'>

<script>
const el = document.querySelector('.x\\,y\\,z')

console.log(el)
</script>

CSS classes can contain pretty much any character you like so long as it's not a space character, and with HTML5 the same applies to ids as well from what I remember.

Hummm, makes sense. Tried here and confirmed!

On css it became:

.x\,y\,z {
  color: red;
}

Well, weird but, valid! hahaha

Maybe we can think in another solution of how this can be solved. Like the @Conduitry ideas.

In the past when faced with similar situations, we've added a compiler flag that lets you opt in to the sensible behaviour, but defaults to off, so that it's not a breaking change:

const compiled = svelte.compile(code, {
  commaSeparatedClassNames: true
});

Then in the next major version we drop the flag and disable the current behaviour.

I guess that could be a solution here? Don't know if it's too early to start thinking about v4.

I am curious about how often this need arises in real life โ€” I don't think I've ever encountered a situation where I wanted to add two or more classnames based on a single condition.

I think it fits really good with utility first css libs like: https://tailwindcss.com
Actually, that's the main reason I started to think about that feature, haha!

About the flag, well, I think would be a really good solution! ๐Ÿ‘

Guys, I've added a msg on it. I will try to work in the next few days, sorry my delay:
https://github.com/sveltejs/svelte/pull/3419

I think I'm in the camp of - this is extra complexity, when a more appropriate way to do this might be to use tailwind with postcss as documented on their site, to compose a set of classes into a single class, and then use that new class in your class: directive:

https://github.com/tailwindcss/designing-with-tailwindcss/blob/master/01-getting-up-and-running/05-composing-utilities-with-apply/css/tailwind.css

For me, it's a good addition. Even because is an option (default disabled), so, don't have impact to who don't want to use it.

If you guys don't think it's worth, no problem for me! Then I can go as @antony suggested, using the proper tailwind (even having some downsides, like impact on purgecss..).

๐Ÿ˜„

Why not use it as array? class:[px-2, py-1]={codition}? It would be more understandable for me :)

@george-oakling one of the goals of Svelte is to maintain full compatibility with regular HTML, regular CSS, and regular Javascript, which adding an array into the mix would prevent.

Sorry to let this sit for so long. I think that this technically being a breaking change, together with this being a somewhat confusing syntax, together with this encouraging use of Tailwind besides the 'proper' one of using the style preprocessor and purger - all together make this a 'no'. It's still easy to put an expression like {foo ? 'class1 class2' : 'class3 class4'} inside a class= attribute's value.

I don't agree with this, I think that the ternary operator way is less readable and less intuitive.

<tr class={ !isLast ? 'border-b border-gray-200' : '' } >
// vs
<tr class:border-b,border-gray-200={!isLast} >

Please reconsider adding this feature, personally, I chose svelte due to the simplicity of doing this kind of things, compared with Angular, React or Vue.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

matt3224 picture matt3224  ยท  3Comments

juniorsd picture juniorsd  ยท  3Comments

plumpNation picture plumpNation  ยท  3Comments

ricardobeat picture ricardobeat  ยท  3Comments

bestguy picture bestguy  ยท  3Comments