Skip to content

Distinguish between properties and attributes on custom elements #12624

Open
@Rich-Harris

Description

@Rich-Harris

Describe the problem

One of the many reasons custom elements are a pain in the neck is that it's often rather ambiguous what's supposed to be an attribute and what's supposed to be a property. Some custom elements 'reflect' attributes back to properties and vice versa, but there's no universally agreed upon convention. If you're doing low-level DOM manipulation you can decide whether you want to do element.setAttribute(name, value) or element[name] = value, but everyone stopped writing code like that a decade ago.

It's a messy, flawed design, and different frameworks deal with it in different ways. Preact and Svelte both treat something as a property if prop in node, and an attribute otherwise. Vue does the same thing but additionally gives you a way to force something to be a prop (I don't think you can force something to be an attribute) with some interesting syntax choices:


image

Lit leans even harder into syntax, with ? and . and @ prefixes for boolean attributes, properties and event handlers respectively:


image

I think the explicit control is a good thing, but I think we can provide it more naturally.

Describe the proposed solution

#7925 and #12479 point the way. We're moving to a world in which quoted props on components are stringified:

<script>
  let object = { a: 1, b: 2, c: 3 };
</script>

<!-- in Svelte 6, this will mean `data="[object Object]"` -->
<Thing data="{object}" />

(The reason the quotes are ignored today is historical: in the distant past before Svelte editor extensions, when components were typically written in .html files, it avoided crazypants syntax highlighting.)

What if we did something similar for custom elements?

<foo-bar someprop={somevalue} someattribute="{someothervalue}"></foo-bar>

In other words if something is quoted, it's an attribute, otherwise it's a prop. We might need to change some Prettier defaults, but other than that this should be a relatively straightforward change. (I don't see any need to distinguish between 'boolean attributes' and properties like Lit does — they're all just properties.)

It is, of course, a breaking change. We would need to decide whether to do this in 5.0, or have a bunch of warnings and change it in 6.0. Ordinarily the conservative thing to do would be to delay the breaking change, but since it's not currently possible to differentiate properties and attributes I think there's a reasonable case for doing it sooner. As such I've given it a 5.0 milestone for now.

Importance

nice to have

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions