hybridsjs / hybrids

Extraordinary JavaScript UI framework with unique declarative and functional architecture
https://hybrids.js.org
MIT License
3.03k stars 85 forks source link

Confusing documentation on "class" attribute #219

Closed BeneSim closed 9 months ago

BeneSim commented 9 months ago

According to the documentation I should be able to use a string (possibly with whitespaces, at least the example contains whitespaces), a list and a map for the attribute class.

However, when I try to pass a whitespace separated string, i.e. a string with multiple classes to "class" attribute like so

const classes = "foo bar";

define({
  tag: "hello-world",
  render: () => html`<div class="${classes}" />`,
});

I'm getting the following error: DOMException:

Failed to execute 'add' on 'DOMTokenList': The token provided ('foo bar') contains HTML space characters, which are not valid in tokens.

Using an array works, e.g.

const classes = "foo bar".split(" ");

define({
  tag: "hello-world",
  render: () => html`<div class="${classes}" />`,
});

or alternatively (and for me preferably)

const classes = "foo bar";

define({
  tag: "hello-world",
  render: () => html`<div className="${classes}" />`,
});

I might have misinterpreted or misunderstood the documentation or maybe I'm lacking some fundamentals but I figured that there might be other people that might stumble upon this, so maybe the documentation could be a little bit clearer (or maybe adjust the templating to also accept whitespace separated string in that case)

BeneSim commented 9 months ago

Small addition:

It's actually more confusing, when I have mixed values then using classNames won't work anymore but class works. E.g.:

Does not work:

const classes = "foo bar";

define({
  tag: "hello-world",
  render: () => html`<div class="${classes}" />`,
});

and

const classes = "foo bar";
const classes2 = "baz bazinga";

define({
  tag: "hello-world",
  render: () => html`<div className="${classes} ${classes2}" />`,
});

Does work:

const classes = "foo bar";

define({
  tag: "hello-world",
  render: () => html`<div className="${classes}" />`,
});

and

const classes = "foo bar";
const classes2 = "baz bazinga";

define({
  tag: "hello-world",
  render: () => html`<div class="${classes} ${classes2}" />`,
});

Personally I find that very very confusing.

smalluban commented 9 months ago

Hi @BeneSim. Thanks for creating an issue. Indeed, there was missing support for multiple strings passed as something like "classOne classTwo".

I made a fix and released v8.2.6, please update the library and check again your case.

BTW, the className="${a} ${b}" does not work, as when you use multiple expressions, the engine fallbacks to setting the attribute, as it always is a string, and for most of the cases, this is correct behavior. In the result, your element will be something like <element classname="a b">, which I suppose wasn't your intention.

This behavior is explained here: https://hybrids.js.org/#/component-model/templates?id=mixed-values

smalluban commented 9 months ago

Feel free to re-open if you still have problems using the lastest version.