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: Light DOM Support #44

Merged
merged 30 commits into from Sep 10, 2021
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
cb55a94
RFC: Add Light DOM RFC
abdulsattar Sep 3, 2020
72fe402
chore: remove misleading line
abdulsattar Mar 17, 2021
a306839
fix: html template example
abdulsattar Mar 17, 2021
9bf37b0
chore: simplify language
abdulsattar Mar 17, 2021
bad70a8
fix: address review feedback
abdulsattar Mar 18, 2021
6b6572e
fix: move implementation details out, tweak text
abdulsattar Mar 18, 2021
f791aec
fix: fix grammar
abdulsattar Mar 18, 2021
990bc6a
chore: add section on querying
abdulsattar Mar 22, 2021
dea55cf
Update style section based on feedback
pmdartus Apr 1, 2021
0a87dea
Add open questions section
pmdartus Apr 1, 2021
a9b1c55
chore:
pmdartus Apr 12, 2021
ea27928
Replace MacroElement with static field
pmdartus Apr 12, 2021
3a62c00
chore: update based on discussions
abdulsattar Apr 15, 2021
fbcab6b
chore: minor copyedit tweaks
nolanlawson Apr 15, 2021
b2df06f
chore: add details on slots and update based on latest convo
nolanlawson Apr 15, 2021
36a77b8
fix: add more details on light DOM global styles
nolanlawson Apr 20, 2021
8313490
fix: respond to comments
nolanlawson Apr 21, 2021
340f4b9
chore: fix security section
abdulsattar Apr 26, 2021
a00f719
Simplify RFC structure
pmdartus Apr 26, 2021
653b680
fix: s/shadowDOM/shadow/g
nolanlawson Apr 26, 2021
846f6b9
fix: update text/0000-light-dom.md
nolanlawson Apr 30, 2021
74f6da6
fix: update text/0000-light-dom.md
nolanlawson May 5, 2021
458cc0f
fix: update text/0000-light-dom.md
nolanlawson May 5, 2021
619721a
fix: put lwc:no-shadow on <template>, not on <slot>
nolanlawson May 6, 2021
798268f
fix: add some usecases for light versus shadow
nolanlawson May 6, 2021
a3f6d71
fix: reword section to make it clearer
nolanlawson May 6, 2021
c8a76f0
feat: add render-mode instead of static `shadow`
abdulsattar May 20, 2021
e735d3e
fix: add text explaining need for directive
nolanlawson May 21, 2021
3460e3a
chore: remove references to shadow
abdulsattar Jun 1, 2021
baa79bf
Reflect updated state of Light DOM
pmdartus Sep 9, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
192 changes: 192 additions & 0 deletions text/0000-light-dom.md
@@ -0,0 +1,192 @@
---
title: Light DOM Support
nolanlawson marked this conversation as resolved.
Show resolved Hide resolved
status: DRAFTED
created_at: 2020-09-10
updated_at: 2020-09-10
champion: Philippe Riand (priand), Ted Conn (tconn)
pr: https://github.com/salesforce/lwc-rfcs/pull/44
---

# RFC: Light DOM Component

## Summary

As of today, all the LWC components inheriting from `LightningElement` render their content to the shadow DOM. This proposal introduces a new kind of component, which renders its content as children in the Light DOM.

## Basic example
nolanlawson marked this conversation as resolved.
Show resolved Hide resolved

When the Shadow DOM is turned off for a component, its content is not attached to its shadow-root, but to the element itself. Here is an example, showing whenever Shadow DOM is on or off:

_Shadow DOM_

```html
<app-container-blue-shadow>
#shadow-root (open)
| <div>
| <b>Blue Shadow:</b>
| <span class="counter">...</span>
| <button type="button">Add one</button>
| </div>
</app-counter-blue-shadow>
```

_Light DOM_

```html
<app-container-blue-light>
<div>
<b>Blue Light:</b>
<span class="counter">...</span>
<button type="button">Add one</button>
</div>
</app-counter-blue-light>
```

As a result, when the content of a component resides in the Light DOM, it can be accessed like any other content in the Document host, and thus behave like any other content (styling, APIs, accessibility, third party tooling...).

## Motivation

Consumer applications require DOM traversal and observability of an application’s anatomy from the document root. Without this, theming becomes hard and 3rd party applications do not run properly:

- **Theming and branding**

Choose a reason for hiding this comment

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

As Dean said in DRB today, UIP has the same (near-term future) requirements around theming and branding for LEX and LWR apps as Communities.

Choose a reason for hiding this comment

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

I don't believe the LEX requirements are the same as what Communities is requesting because the number of actors in the system is very different. Let's discuss offline.

Copy link
Member

Choose a reason for hiding this comment

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

@hsterlingsfdc Could you make sure to bring the LWC team into the loop when this will be discussed/designed? I would like to better understand the LEX and LWR requirements in this regard.


Because of the CSS isolation, theming is made harder. Typically, theming is done via APIs (CSS properties) and/or CSS theming parts (`::part`). Both come with caveats and issues. Theming is critical for consumer apps, where custom branding is a must have. Some new APIs, like `::theme`, are investigated but they won’t be pervasively available before years.
[Styling is critical to web component reuse, but may prove difficult in practice](https://component.kitchen/blog/posts/styling-is-critical-to-web-component-reuse-but-may-prove-difficult-in-practice)

- **Third party integrations**

Third party tools need to traverse the DOM, which breaks with Shadow DOM and the existing browser APIs (querySelector, ...). Note that the use of Light DOM fixes for Light DOM components, but not for native Shadow DOM ones if the page contains any.

- Analytics tools, Personalization platforms, Commerce tools like PriceSpider or Honey...

- **Testing software**

Tools like Selenium, Cypress etc. face the same issues as third party tools when it comes to traversing the DOM.

Introducing components rendering to the Light DOM opens new possibilities where applications can render most of their content in the Light DOM, but also keep individual widgets (e.g. `select` tag) and leaf components that render in the Shadow DOM. This approach combines the best of both worlds by solving the issues presented above and offering strong encapsulation when needed.
![shadow spectrum](./shadow-spectrum.png?raw=true "Shadow Spectrum")
Copy link
Member

Choose a reason for hiding this comment

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

Image content: Remove "Today" and "Where we want to be" label. The RFC should not present points of view but rather preset facts.


### Prior Art

Most of the libraries designed to support Shadow DOM also propose a Light DOM option, with a variety of Shadow DOM features (slots, scoped styles, etc.). It includes:

- [StencilJS](https://stenciljs.com/docs/styling#shadow-dom-in-stencil)
- [LitElement](https://lit-element.polymer-project.org/api/classes/_lit_element_.litelement.html#createrenderroot)
- [MS Fast Element](https://fast.design/docs/fast-element/working-with-shadow-dom#shadow-dom-configuration)

## Detailed design

Choose a reason for hiding this comment

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

The list of invariants and constraints is missing. From the live discussion on this RFC today it became obvious that there are many you're working with.

  • Support all standard Light DOM APIs at runtime
  • What the developer codes in the template is what they see in the rendered DOM
  • Align with standards where possible; when no standard exist align with pre-existing LWC concepts, and finally other frameworks
  • A constraint is that the LWC compiler operates on 1 file at a time, not one component (eg HTML + Javascript)

There are many others that need to get captured here. This'll bring visibility to the rationale driving this design.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm still fuzzy about:

What the developer codes in the template is what they see in the rendered DOM

what I see in the PR is that the content of the slot is flatten, so the slot element itself never gets rendered.


### Selecting Light DOM vs Shadow DOM

In raw JS, developer has the choice to use or not use shadow DOM for their custom element. For example,

```js
// uses Shadow DOM
class MyShadowElement extends HTMLElement {
connectedCallback() {
this.attachShadow({ mode: "open" });
this.shadowRoot.innerHTML = "<p>My custom element that uses Shadow DOM";
}
}

// doesn't use Shadow DOM
class MyLightElement extends HTMLElement {
connectedCallback() {
this.innerHTML = "<p>My element that does not use Shadow DOM";
}
}
```

In LWC as well, the developer will retain the choice: they can choose to inherit from `LightningElement` to select Shadow DOM (which already exists) or inherit from a new class, `MacroElement`, to opt into Light DOM.

```js
import { MacroElement } from "lwc";

export default class MyLightComponent extends MacroElement {
renderedCallback() {
this.querySelector("child-element"); // note the absence of this.template
}
}
```

`MacroElement` is a new class that will be exported from the `lwc` module. Its API and functionality remain identical to `LightningElement` with the primary difference of not using Shadow DOM.
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm a bit concerned about exposing light DOM via MacroElement. I can break my concerns into two groups: 1) deviation from other WC frameworks, and 2) potential class proliferation.

Deviation from other WC frameworks

Here is how other frameworks handle light DOM:

Stencil

@Component({
  tag: 'my-component',
  shadow: false // or omitted
})
class MyComponent {}

Fast

@customElement({
  name: 'my-component',
  template,
  shadowOptions: null // or `{ mode: 'closed' }` for closed shadow
})
class MyComponent extends FASTElement {}

Lit

class MyComponent extends LitElement {
  createRenderRoot() {
    return this // or return `this.attachShadow(...)` here
  }
}

So we have 2 frameworks opting for decorators, and another opting for an overridable method. LWC would be the only WC library using separate classes (unless I missed one).

Potential class proliferation

In the future, we may want to support closed shadow roots (edit: my mistake, didn't realize we already did 🤦 ). Would that be another class?

import { ClosedShadowElement } from 'lwc'

There is also a proposal for "open stylable roots" (WICG/webcomponents#909). Would this be another one?

import { OpenStylableElement } from 'lwc'

In that proposal, there is even some talk of attachShadow() eventually looking like this:

this.attachShadow({
  mode: 'open',
  styles: 'closed'
})

If the options bag for attachShadow continues to grow like this, then we could end up with a combinatorial explosion of classes to handle every possible case.

My personal preference would be for decorators or mixins, but mostly I'm just concerned about choosing classes here.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think the original reason we chose a different class was to emphasize that these are different kinds of components because the programming model is different. I'm not sure if we still feel that is the case.

I'm curious how the createElement API will change which currently takes the mode.

Copy link
Contributor

Choose a reason for hiding this comment

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

@tedconn Ah my mistake, I didn't even know we supported closed shadow roots. 🙂 It seems that createElement would be the right place to put the options bag (if it becomes a big bag!).

So it looks like my concerns about class proliferation might not apply, since we only plan on having MacroElement for this one case (light DOM). But then why not have light DOM as an option in createElement?

Copy link
Collaborator

Choose a reason for hiding this comment

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

But then why not have light DOM as an option in createElement

Because we need an API on the component, so component authors can toggle, not on the engine. Something like this would be nicer though, right?

import { LightningElement } from 'lwc';

export default class LightDomElement extends LightningElement {

  static shadowOptions = {
    mode: null
  }

}

Copy link
Member

@pmdartus pmdartus Mar 22, 2021

Choose a reason for hiding this comment

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

We discussed in the past 2 options, using a static field or using a brand new base class. Until the decorator proposal goes back to stage 3, I don't think it is safe to introduce a brand new decorator.

The main advantage of introducing a brand new class over static fields is around component inheritance. You can shadow (by inadvertence or intentionally) a base class static field. It means that you can turn a Shadow DOM component into a Light DOM one (and vice-versa) by extending from it. Such override can't be done when inheriting from a different base class.

In the following example, let say that we introduce a new shadowDOM static boolean to indicate whether the component rendered in the Light DOM or in the Shadow DOM. It is something we should discourage.

import { LigthningElement } from 'lwc';

class ShadowDOMComponent extends LightningElement {
  static shadowDOM = true;
}

class LigthDOMComponent extends ShadowDOMComponent {
  static shadowDOM = false;
}

Now that you speak about class proliferation, I am more favorable to adding a signal via a static field.

Copy link
Contributor

Choose a reason for hiding this comment

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

After discussion with the team, we landed on the static field rather than MacroElement, correct? AFAICR, we concluded:

  • Any solution we land on (classes, field, method, decorators, etc.) needs to be resolved at runtime. In other words, developers can always do shenanigans such that you need to do a runtime evaluation to figure out whether the element is shadow or light. Since the LWC compiler to know at compile-time, we would just have to teach developers to use patterns that are friendly for compile-time evaluation.
  • Decorators are not standard yet
  • Classes may result in class proliferation
  • Static fields seem to have nice ergonomics
  • So we should go with static fields

Is this right? @pmdartus @abdulsattar

Copy link
Member

Choose a reason for hiding this comment

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

You are right.


### Component features when using Light DOM

Some of the LWC component capabilities are directly inherited from Shadow DOM, or emulated by the synthetic-shadow. Despite the use of Light DOM, we’d like to keep these features available, even if their behavior is slightly adapted to the Light DOM:
pmdartus marked this conversation as resolved.
Show resolved Hide resolved

- **Slots**

As we mentioned before, the component composition model in LWC is provided by slots. Light DOM will provide the same mental model for developers building Light DOM components.

In Light DOM, `<slot>` will denote the place where the slotted component will be attached. The `<slot>` element itself won't be rendered. The slotted content (or the fallback content) will be flattened to the parent element at runtime.

Since the `<slot>` element itself isn't rendered, adding attributes or event listeners to the `<slot>` element in the template will throw a compiler error.
Copy link
Contributor

Choose a reason for hiding this comment

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

Out of Stencil, Fast, and Lit, only Stencil opted to make slots "work" with light DOM.

Fast says:

If you choose to render to the Light DOM, you will not be able to compose the content, use slots, or leverage encapsulated styles.

Lit is also against slots in light DOM:

I don't think <slot> makes much sense outside of shadow DOM [...]

Based on discussion in this thread, it seems like Stencil's choice may have resulted in significant performance overhead, which is understandable given that a lot of behavior you get "for free" with slots in shadow DOM now has to be reimplemented for light DOM.

Before committing to this, I'd be interested to see some more details about how we plan to handle slots in light DOM:

  • How does MutationObserver work?
  • How does the timing between slotted versus non-slotted children work?
  • Would CSS selectors be able to traverse these boundaries?

I'd also be interested to see some benchmarks, to understand if the issues Stencil ran into were just problems with Stencil's implementation, or if they're inherent to trying to make slots "work" in light DOM.

Copy link
Contributor

Choose a reason for hiding this comment

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

Another interesting point of comparison: Aurelia has slots, but they explicitly mark it as <au-slot>, not <slot>:

An obvious question might be "Why not simply 'turn off' shadow DOM, and use the slot itself"? We feel that goes to the opposite direction of Aurelia's promise of keeping things as close to native behavior as possible. Moreover, using a different name like au-slot makes it clear that the native slot is not used in this case, however still bringing slotting behavior to use.


- **Scoped Styles**
pmdartus marked this conversation as resolved.
Show resolved Hide resolved

Shadow DOM styles are scoped to the enclosing shadow tree. Styles don't leak out to the rest of the page and the page styles don't leak into this component. In Native shadow, it is enforced by the browser whereas in Synthetic shadow it is enforced by adding few attributes to the elements and scoping all CSS rules by those attributes.

Styles scoping in Light DOM will be done differently. The styles will be scoped not just to the component they belong, but also to its children. These styles won't leak out to the parents (or their children) though.

E.g.

```html
<x-a>
<style>
p {
color: blue;
}
</style>

<p></p> <!-- will be blue -->
<p class="red"></p> <!-- will still be blue. red class from child won't leak out here -->

<x-b>
<style>
p.red {
color: red;
}
</style>

<p></p> <!-- will be blue. Style from x-a will be applied -->
<p class="red"></p> <!-- will be red -->
<p class="red"></p> <!-- This paragraph is coming from A and slotted into B. Will also be red. -->
</x-b>
</x-a>
```

Opting out of this scoping is not supported. There's no way for a component author to say a CSS rule shouldn't be scoped to that specific component (and its children). If global scoping is desired, a global stylesheet can be injected manually.
Copy link
Contributor

Choose a reason for hiding this comment

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

With synthetic shadow DOM, we implemented a system for style scoping similar to this (using attribute selectors). However, with shadow DOM, it was kind of implied that eventually we would migrate to native shadow, so the synthetic system wasn't designed to last forever. With this system, though, we are committing to support a new styling system indefinitely, including whatever implementation details we land on, which will impact compatibility moving forward. For instance:

  1. Whether to use attribute selectors / classes / etc. for scoping? This has performance implications (browsers tend to have more optimizations for class than for attribute selectors) as well as specificity implications (e.g. specificity conflicts with global styles). FWIW, Vue uses attribute selectors whereas Svelte uses class selectors.
  2. Whether styles are inherited to the children or not. This also seems to me to have performance implications, since I'm not sure how we could implement this, except by concatenating attributes down the descendant tree. (So for instance, would the 5th light DOM grandchild have 5 separate attributes on every DOM node?)
  3. Whether styles are inherited to light DOM "slots" or not, and whether something like (for instance) sibling selectors would work across both "slot" and non-"slot" light DOM children

It seems to me that the safest option is to not provide any kind of style scoping for light DOM elements. I.e. "if you want style scoping, use shadow DOM." This avoids making any commitments toward one particular styling system in light DOM.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think the goal is to land on the most natural ergonomics for the developer, including developers already versed in LWC.

Styles in LWC are scoped today, but for end users this is not a natural consequence of the shadow DOM encapsulation, rather it just makes sense since the authoring model is per-component. This is why Vue scopes styles, not because it aligns with the Shadow DOM model. For us that is just a bonus.

Not scoping styles would mean that without any extra code on our side, styles would leak into shadow DOM children, which would not match the native shadow DOM behavior when we turn off synthetic.

Copy link
Contributor

Choose a reason for hiding this comment

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

@tedconn

Styles in LWC are scoped today, but for end users this is not a natural consequence of the shadow DOM encapsulation

It is due to synthetic-shadow, sure, but the long-term goal is to migrate to native shadow DOM. So then it would be a natural consequence. 🙂

This is why Vue scopes styles, not because it aligns with the Shadow DOM model.

I'm not saying scoped styles aren't good for developer ergonomics; I cede that point. 🙂 My point is just that "which scoped styles?" is an important question, especially since we have to indefinitely maintain whatever we choose today.

Not scoping styles would mean that without any extra code on our side, styles would leak into shadow DOM children

I'm not sure I follow this. Today, in a purely non-LWC, non-synthetic world, I can have a light DOM-using component with a shadow DOM-using component as its child, and the only styles that leak in are inheritable styles like font-family and color, which is per the spec. It should work this way both in native shadow DOM and in our synthetic shadow DOM.

Copy link
Collaborator

Choose a reason for hiding this comment

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

It should work this way both in native shadow DOM and in our synthetic shadow DOM.

I may be wrong but my thinking was that If styles aren't scoped, in synthetic shadow DOM, those styles will leak in, because there's no other mechanism to prevent that.

Copy link
Contributor

Choose a reason for hiding this comment

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

I wasn't sure, so I just ran a quick check. It looks like if you add the style body { font-family: monospace; } to a Salesforce page, it will indeed leak in to synthetic shadow DOM components. (This is the same as what would happen with a light DOM-using component wrapping a shadow DOM-using component.) So it appears we are following the spec correctly on that.

Copy link
Member

Choose a reason for hiding this comment

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

those styles will leak in, because there's no other mechanism to prevent that.

@tedconn You can prevent inherited styles to be applied by resetting all the properties on the host element. It works in both native shadow and synthetic shadow.

:host {
  all: initial;
}

We discussed CSS scoping at length and we reached the conclusion that it something we would like to preserve with Light DOM for developer ergonomic reasons, as @tedconn mentioned.

We considered the following approach to style scoping:

  1. component content scoping: Styles are applied to the content the component renders and aren't applied to children components. This approach is similar to the way styles are scoped today in synthetic shadow. It also behaves the same as Vue, Svelte, and Angular. An HTML attribute is added to all the CSS selectors, the same attribute is also added to all the elements rendered by the component.

  2. component subtree scoping: Styles are applied to the content the component renders and also to the content rendered in the children's components. This is a similar approach to Aura styling. All the CSS selectors are prefixed with a CSS attribute selector and the same attribute is applied to the root element to scope the subtree.

/* Input */
.foo .bar {}

/* Ouput: component content scoping */
.foo[data-scope] .bar[data-scope] {}

/* Output: component subtree scoping */
[data-scope] .foo .bar {}

We decided to go with the component subtree scoping approach for the following reasons:

  • This approach map with the way querySelector works in the light DOM. It applies to the entire subtree and not only the current element.
  • One of the main reason for using light DOM is to let a component author override it children components style. This is possible with the subtree scoping approach but not with the content scoping one. Overriding children component styles with the subtree scoping approach would require the introduction of a non-standard CSS selector to escape the scoping (>>> in Vue and Angular or :global in Svelte).

The main downside for me of the component subtree scoping approach is that you can run into a style clashing issue where the parent component can unintentionally override children's component styles because the parent selector has a higher specificity.

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks, that makes sense. Two comments:

First, I'm not sure that preferring Aura's styling model to Vue/Svelte's styling model is the best choice from the perspective of developer ergonomics. Aura is well-known inside Salesforce, but not so much outside. (Also if I'm not mistaken, most React CSS-in-JS libraries follow something more like the Vue/Svelte model.) Personally I would find it a bit surprising that parent light components can affect child light components' styles.

Second, for this CSS:

[data-scope] .foo .bar {}

I find this to be a bit scary from a performance perspective. Imagine something like:

/* Input */
div {}

/* Output */
[data-scope] div {}

Now you're potentially the telling the browser to check the ancestor chain for every div to see if its attributes match. For class selectors, there is already a Bloom filter to handle this, but I'm not sure if browsers have gotten around to optimizing attribute selectors in the same way. I may have to whip up a benchmark to test this. 🙂

Copy link
Member

Choose a reason for hiding this comment

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

Personally I would find it a bit surprising that parent light components can affect child light components' styles.

This is good to know. We can survey developers internally to see which approach they find the most intuitive.

Now you're potentially the telling the browser to check the ancestor chain for every div to see if its attributes match.

I don't think we can use classes because component developers can set classes via the template (from outside) or in the component via this.classList (from within). We would need to special-case this scoping class and ensure that it is always present even when the author manipulates the component classes. I am not sure if we can do this in an efficient way.


- **`this.template`**

In `LightningElement`, `this.template` returns the shadow-root. It will return `null` in `MacroElement`.
Copy link
Collaborator

Choose a reason for hiding this comment

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

It will return null in MacroElement.

How do I reference the root element in a light dom component?

Copy link
Member

Choose a reason for hiding this comment

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

With LightningElement, all the properties and methods on the this value interacts with the host element (this.getAttribute, this.querySelector, this.classList). And this.template allows to interact with the shadow root. However, LWC never exposes the host element itself to the component instance. You can get access to it, via this.template.host but it is more a hack than anything else.

The same model is preserved with MacroElement. It is possible to interact with the host element using methods and properties on the this value. But there is currently no workaround (like this.template.host) to access the host element from a MacroElement component instance.

If accessing the host element is necessary, I would vote for making it available to both LitghtningElement and MacroElement in a similar fashion. For example via a host getter.


### Security (WIP)

- In some applications, light-dom components may not be allowed... it’s up to the app context
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we have an example of how light DOM components can be disabled? Will there be a compiler flag to accomplish this?

- **what is the behavior when it’s not allowed?**
- Some applications might disable light-dom as a whole
- Some applications might disable light-dom selectively using a “privileged code” model
Copy link
Collaborator

Choose a reason for hiding this comment

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

way more detail necessary here. Does this mean that a component was authored in the LightDom but app requested it in the shadow dom for ex?


### Component Migration

There is no migration of the existing components. Existing components inherit from `LightningElement` and light DOM components will inherit from `MacroElement` and they are two different things. If a component author wishes to use Light DOM for any of their existing components, they will have to make the relevant changes manually.

### Server Side Rendering

The engine-server module should provide the SSR capability to seamlessly render Shadow DOM or Light DOM. It should include the component children, as well as the scoped styles.

## Adoption strategy

This new feature does not break any existing components, it simply adds a new feature that developers have to opt for. There is no migration of the existing components needed.

This feature should be exposed and explained to the component library developers as they might change how they develop their components internally.

## How we teach this

Shadow DOM and Light DOM are already names accepted by the industry, see: [Terminology: light DOM vs. shadow DOM](https://developers.google.com/web/fundamentals/web-components/shadowdom?hl=en).
We need to provide the proper documentation to educate the LWC developers:

- What are the differences between Shadow DOM and Light DOM
- We need a guide on when to use one or the other
nolanlawson marked this conversation as resolved.
Show resolved Hide resolved
Binary file added text/shadow-spectrum.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.