Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC: Declarative host element #72

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open

Conversation

nolanlawson
Copy link
Contributor

@nolanlawson nolanlawson commented Jan 19, 2023


### Supporting `lwc:ref`

Supporting `lwc:ref` is technically feasible, but doesn't make much sense, as there are already alternatives. In shadow DOM, developers can use `this.template.host`, and in light DOM, they can use `this`.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically this in light DOM is not exactly the same as what you'd get with lwc:ref, since the former is the internal view of the component and the latter is the external view. But it's ~99% the same. You can do this.classList, this.children, this.setAttribute, etc., and it works as expected.


The above also applies to the timing of when event listeners are attached using `on*`.

No guarantees are made about the ordering of changes made to `<lwc:root>` versus elements inside of the template.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ordering of changes made to <lwc:root>

Is this referring to the ordering of how classes, event handlers, etc. are applied from <lwc:root> to the host element?

versus elements inside of the template

Does this mean that there could be a difference in the order the classes, event handlers, etc are applied on the host vs to elements within the host?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I didn't think of that. Updated! bbbc288


## Detailed design

The `<lwc:root>` element is a synthetic element defined in a component's template HTML file. Similar to [dynamic components](https://github.com/salesforce/lwc-rfcs/pull/71), it does not actually render in the DOM.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this element be available for light DOM as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Clarified: 815466f

text/0000-declarative-root.md Outdated Show resolved Hide resolved
text/0000-declarative-root.md Outdated Show resolved Hide resolved

Also, the whole point of this feature is to avoid needing programmatic access to the root/host element. So adding `lwc:ref` would be counter-productive.

## Adoption strategy
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would go a step further and deprecate all APIs exposed on the LightningElement that are covered by this proposal.

The main motivation would be to remove those programmatic APIs on the engine server. Removing programmatic host element mutation would certainly greatly simplify the SSR logic and would enable us to get rid of some of the DOM APIs polyfills we have to maintain for SSR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To clarify, are you proposing that we remove all DOM-like APIs on the this exposed to component authors? E.g.:

renderedCallback() {
  console.log(this.children)
  console.log(this.getAttribute('class'))
  console.log(this.querySelector)
}

?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I was wondering if we should deprecate all those DOM-like APIs. That said there are some APIs like dispatchEvent that would certainly have to stay on the LightningElement prototype.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My understanding was that, someday, we might converge the "bridge element" and "lightning element" classes. It would be a nice simplification from my POV if this just referenced the element (as it does in other web component frameworks like Lit). In that world, all of these APIs would "just work."

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was always under the impression that the long-term goal should be to merge the LightningElement instance with the host element.

But I am now questioning this, because of the tension it creates with SSR. In a world where we can achieve this merge. Does it mean that we would have to polyfill all the DOM APIs available on the host element to make LWC components compatible with SSR?

Something that I really about this proposal is that we provide a declarative alternative to those DOM APIs. Those APIs enable developers to write isomorphic components without having to worry about the environment they are running in. Another added benefit of this declarative approach is that it enables the LWC compiler to optimize the usage of those APIs.

This is just food for thought, I don't have yet a formal opinion on this.

text/0000-declarative-root.md Outdated Show resolved Hide resolved
However, this proposal prefers "root" to "host," because "root" is a more generic term that does not imply shadow DOM. This
makes it clear that, for example, a child light DOM component cannot set attributes on a parent shadow DOM component by using this technique. (Whereas a child light DOM component can indeed style its parent's root node using `:host` in unscoped CSS.)

### Placing attributes on the root `<template>` tag.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about replacing the template tag with <lwc:root>?

e.g.

<lwc:root class="klass">
  <h1>regular elements</h1>
</lwc:root>

Of course, the regular <template> will still be supported.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To me, this seems like too much of a drastic change to the existing system. Developers are very accustomed to putting <template> at the top.

It also raises questions of how we would need to support lwc:render-mode, lwc:preserve-comments, etc. on <lwc:root>. Whereas if the two are separated, then it's clear which directives apply to which tag.


Many attributes and directives that can be applied to a normal `HTMLElement` can also be applied to `<lwc:root>`. These include:

- Standard [global HTML attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes), such as `class` and `tabindex`
Copy link

@jhefferman-sfdc jhefferman-sfdc Jan 20, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sounds very good, ones that are important to us include aria-xyz, role, size, id

@nolanlawson nolanlawson changed the title RFC: Declarative root element RFC: Declarative host element Jan 20, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants