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

Add support for declarative shadow dom #189

Open
wants to merge 11 commits into
base: main
Choose a base branch
from

Conversation

whaaaley
Copy link
Contributor

@whaaaley whaaaley commented Feb 1, 2022

This addresses my issue #188.

This PR would allow you to write views that create shadow-roots. For example when using JSX:

function view () {
  return <div>
    <h1>Heading 1</h1>
    <div>The styles inside this shadow-root below are completely scoped to that node. This pairs great with importing CSS from JavaScript imports.</div>
    <div shadow-root='open'>
      <h1>
        <style>{'h1 { display: flex; padding: 12px; color: white; background: dodgerblue; } div { padding: 0 24px; }'}</style>
        <button onclick={increment}>Increment</button>
        <div>{state.count}</div>
        <button onclick={decrement}>Decrement</button>
      </h1>
    </div>
  </div>
}

Where the DOM output would look like: (The root h1 inside shadow-root is required to mount children into it and the parent div has to exist so we have a place to mount the shadow-root to.)

image

Here's a codepen of the PR in action. https://codepen.io/dustindowell/pen/rNYeLxg

If this is not something you're interested in it's no problem! I just think it's really cool to have encapsulation of styles and scripts without having to touch the custom elements api!

To briefly walk over the changes.

  • I added a slot variable, because children will need to go into the shadow-root instead of the original node if the property shadow-root exists.
  • Inside the new condition, these are the minimum steps needed to create a new shadow node. Shadow root elements can only be a few different tags. The list of valid root tags can be found here: https://developer.mozilla.org/en-US/docs/Web/API/Element/attachShadow. However the most common is obviously <div>. I defaulted to div because I couldn't think of a good way to configure that. This is maybe something that could adjusted. (see changes)
  • Finally, changing the node.appendChild to slot.appendChild so the children nodes are appended to the correct parent node.

EDIT: Perhaps a solution to configuring the node you attach inside the shadow-root would be to not allow "fragments" inside a node which has a shadow-root property. I'll think about this and make some changes. (see changes)

EDIT 2: I also didn't account for patching. 😅 So I do have some work to do still. (patching works fine)

Rename `slot` to `attach`
Add `children` variable
A root element is required inside `shadow-root` vnodes
@whaaaley
Copy link
Contributor Author

whaaaley commented Feb 1, 2022

After some simple tests, it seems like patch doesn't need to be changed for this to work. Let me know if I'm missing something. Here is an updated codepen that includes subsequent patching: https://codepen.io/dustindowell/pen/rNYeLxg

EDIT: Ok there's problems.

@whaaaley
Copy link
Contributor Author

whaaaley commented Feb 1, 2022

I believe I've fixed everything.

@jorgebucaran
Copy link
Owner

@whaaaley Awesome. How are you supporting JSX in your pen?

@whaaaley
Copy link
Contributor Author

whaaaley commented Feb 1, 2022

@jorgebucaran I'm using the typescript option in the pen settings then running that through a function based originally on zaceno's jsx pragma that I tweaked a bit. I just pasted it into the pen for experimenting.

@whaaaley whaaaley changed the title Add shadowRoot nodes Add support for declarative shadow dom Aug 16, 2022
@whaaaley
Copy link
Contributor Author

whaaaley commented Aug 16, 2022

@jorgebucaran I don't know if you're interested in supporting declarative shadow DOM at all. However, last year Chrome added support for declarative shadow DOM syntax. I was unaware of that syntax at the time of this PR. If you're not sold on adding support yet, totally fine, though it would help me out a getting static rendering and SSR working with Superfine views which use shadow DOM. (Isomorphic code and all that)

The syntax Chrome supports.

<div> <!-- this div has a shadow root attached -->
  <template shadowroot='open'> <!-- this template tag gets obliterated by the browser -->
    <h1>hello world</h1> <!-- contents are added to the shadow root -->
    <style>
      h1 { color: red; }
    </style>
  </template>
</div>

Here's a codepen showcasing the above syntax.
https://codepen.io/dustindowell/pen/dymgvNg

Some details of my changes in my last commit to this PR. I removed what I had previously and did something different. When iterating over children I check for a shadow root template, If that check is true I "abort" appending children and forward the contents of that template to a new createNode function. This is the most efficient way I could think of doing this. On that next createNode call, I pass in the mode of the shadow root. If it exists, attach a shadowRoot and continue.

@jorgebucaran
Copy link
Owner

Thanks, @whaaaley. I'll have a look at this. 👍

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.

2 participants