Skip to content

Passing data to custom elements #875

Closed
@Rich-Harris

Description

@Rich-Harris

When passing data to a custom element, there are two possibilities — properties, or attributes.

Right now, Svelte doesn't have any understanding of custom elements, so on encountering something like this...

<custom-element foo='bar'></custom-element>

...it will look here, fail to find a property corresponding to the foo attribute, and fall back to writing this:

setAttribute(custom_element, "foo", "bar");

That's sub-optimal, because it means we can't pass down non-string values — especially not objects and arrays. For those, we need to use props.

At the same time, always using props could be a problem for custom elements that expect attributes to change. It's also a problem if a custom element has CSS like this, say...

:host([active]) {
  font-weight: bold;
}

...because then if you have a situation like this...

<custom-element active='{{thing === selected}}'></custom-element>

...the prop will be maintained correctly but the attribute won't ever change, meaning the styles will never apply.

A possible solution

Do both. Or rather, always set a prop, but also set an attribute if the value is primitive.

So the example at the top would become this:

custom_element.foo = "bar";
setAttribute(custom_element, "foo", "bar");

For dynamic values, it would be more like this:

custom_element.foo = state.bar;

if (typeof state.bar === "boolean" || typeof state.bar === "undefined") {
  if (state.bar) {
    setAttribute(custom_element, "foo", "");
  } else {
    removeAttribute(custom_element, "foo");
  }
} elseif (typeof state.bar === "string" || typeof state.bar === "number") {
  setAttribute(custom_element, "foo", state.bar);
}

Needless to say, all that logic would live in a helper.

kebab-case vs camelCase

Since props can't be kebab-case, I propose that we translate kebab to camel when setting props:

<custom-element the-answer='{{fortyTwo}}'></custom-element>
custom_element.theAnswer = state.fortyTwo;
setCustomElementAttribute(custom_element, "the-answer", state.fortyTwo);

This might seem slightly messy, but I think it's the most pragmatic way to deal with this stuff, and the way that will result in the least surprising behaviour for the largest number of people. No-one ever said custom elements were particularly well designed. (Actually, lots of people did, but most of them work for Google.)

Thoughts?

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions