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

Slotting Dojo Web Components #255

Closed
devpaul opened this issue Feb 15, 2019 · 12 comments
Closed

Slotting Dojo Web Components #255

devpaul opened this issue Feb 15, 2019 · 12 comments
Labels
discussion The issue is up for discussion

Comments

@devpaul
Copy link
Member

devpaul commented Feb 15, 2019

I would like to create a Web Component using Dojo that allows me to slot in children components at designated places in the widget. For instance, if I had a container style widget with an icon, title, and children, how can I inject the desired dom?

interface MyContainerProperties {
	icon: DNode;
	title: DNode;
}

class MyContainer extends WidgetBase<MyContainerProperties> {
	render() {
		const { icon, title } = this.properties;
		return v('div', { classes: css.root }, [
			v('header', [
				v('span', [ icon ]),
				v('span', [ title ])
			]),
			v('content', [
				this.children
			])
		])
	}
}

I'd like to be able to use templates and slots from the dom

<my-container>
    <div slot="icon"><i class="icon"></div>
    <div slot="title">Title</div>
    <ul>
        <li>Item 1</li>
        <li>Item 2</li>
    </ul>
</my-container>

Is there a recommended approach for slotting in children elements in a Dojo web component?

@matt-gadd
Copy link
Contributor

We currently don't support this, you would have to provide the appropriate slotted components via a property like we do natively in the widget system.

You could potentially enhance the customElement wrapper to take slotted children, orphan them and pass them to the appropriate widget property like a kind of slot to property mapper. That's something I think would work well in the existing system anyway. In the future when dojo/webpack-contrib#43 has landed and if the above is possible we can then automatically map any property that is a DNode to a named slot.

@matt-gadd matt-gadd added the enhancement New feature or request label Feb 15, 2019
@matt-gadd
Copy link
Contributor

Would definitely be interested in a POC for this 👍

@rorticus
Copy link
Contributor

rorticus commented May 3, 2019

Made an idea for this....

@dojo/framework PR
example

Basically, there are two types of slots. Regular DNodes and arrays of DNodes.

Regular DNodes can be passed using a named slot:

interface MyContainerProperties {
	icon: DNode;
	title: DNode;
}
<my-container>
    <div slot="icon"><i class="icon"></div>
    <div slot="title">Title</div>
    <ul>
        <li>Item 1</li>
        <li>Item 2</li>
    </ul>
</my-container>

Arrays of DNodes can be passed by using a slot-array attribute:

interface MyContainerProperties {
	icons: DNode[];
	title: DNode;
}
<my-container>
    <div slot="icons" slot-array="true">
        <i class="icon icon1" />
        <i class="icon icon2" />
    </div>
    <div slot="title">Title</div>
    <ul>
        <li>Item 1</li>
        <li>Item 2</li>
    </ul>
</my-container>

Let me know what you think!

@devpaul
Copy link
Member Author

devpaul commented Jun 3, 2019

@rorticus and I had a chance to talk some about this today!

First, the POC is really cool. It's nice seeing experimentation with Dojo and Web Components.

Here's a summary of what was discussed:

Regarding the slotting DNode[] there was some concern about deviating from the web components spec. If we made a feature like that it would be best to use a different attribute name.

The POC is missing some functionality that web component templates, slots, and shadow doms provide. Primarily if the slotted node is updated in any way the dojo widget's custom element doesn't update. If we wanted to implement a solution for this we could

  1. add observables to watch for changes in slotted nodes or the addition of slotted nodes
  2. update and render a dom node that is a copy of the slotted node
  3. add css to hide all slotted children * > [slot] { display: none }

Using this approach we could probably make Dojo work without a shadow dom. However there would likely still be some outlying behavior and we'd be on the hook to match dojo slot and web component slot behavior.

@rorticus and I also talked about creating a POC with a custom element that created a shadow node and had a dojo widget render to the shadowroot. This should allow web-component aware widgets to use slots directly using the native web components framework. This seems like a good next step so we can get a good idea of the pros and cons of rendering to a shadowroot.

@matt-gadd
Copy link
Contributor

@devpaul @rorticus i'm not sure if you got anywhere with your POC for rendering to a shadowroot, but last time I checked we would have to change the way we inject, override and generally use css in dojo due to the shadow dom. Thats probably quite a big a piece of work.

@devpaul
Copy link
Member Author

devpaul commented Aug 5, 2019

I think we're finding that it's likely to be a big piece of work regardless of our direction. Practically no framework to web component build implements the full web components API. So I think we need to find the right developer experience (whatever that may be) to implement this common Dojo pattern in a web component context. Maybe we might be able to find "slotted" children, attach observables to them, wrap them in render functions (i.e. () => DNode) and pass them to the widget. I don't know. Regardless of the approach, we definitely want to provide a good experience, preferably one that is similar to web components.

Would you provide some details around how Dojo works with css? It could help inform our next POC. I'd also like to know if there's a way to use and change css variables with Dojo components in a similar way to how a shadow dom allows.

@matt-gadd
Copy link
Contributor

matt-gadd commented Aug 5, 2019

@devpaul yeah sorry by big i meant the css part would affect not just custom elements but the whole widget ergonomics and build. Dojo doesn't do anything specific re: css, it's all global css scoped with css modules, css variables wouldn't be an issue, but localising the css to each component would be and would entirely replace the css modules pipeline. We'd definitely want to be considering the scope (pun semi intended) of what that would mean for everything.

For the basic "slot" scenario, I don't think we really need to know about changes to the child, as we don't really support the parent decorating children anyway. This would actually be no different to the children scenario we have currently in custom elements.

@devpaul
Copy link
Member Author

devpaul commented Aug 5, 2019

Given the example above

<my-container>
    <div slot="icon"><i class="icon"></div>
    <div slot="title">Title</div>
    <ul>
        <li>Item 1</li>
        <li>Item 2</li>
    </ul>
</my-container>

If there is a change to slot="title" like the textContent changes from 'Title' to 'New Title' then I'd expect the parent component to update that text where it's slotted in.

I hear you about the complexity around CSS and shadowdom though. It'd require a fair amount of work. Not something to walk into lightly.

Maybe we should take a step back and look at the design requirements, the developer ergonomics, and the problem we're trying to solve. Initially I thought that following the slot/shadowdom pattern would be the most straight-forward way, but maybe Dojo would be more comfortable simply passing renderers as functions to properties and we should simply provide advice and examples around that. The more I work with web component libraries the more I see that at some level a framework and common interface comes into play for all but the simplest component systems.

@matt-gadd
Copy link
Contributor

matt-gadd commented Aug 5, 2019

We already effectively do something similar to what you’re saying for children like I said. When an author passes a child to the parent the parent can reparent it somewhere else in its content for instance.

I don’t particularly like the renderer functions for basic leaf components, at that point it’s not worth using CE’s at all imo. It’s one of the big things on why children are preferable over render funcs in dojo/widgets right now. But children are limited to a single type of thing. Which is why ultimately the slot like concept is appealing as it’s practically named children.

@matt-gadd
Copy link
Contributor

On the shadowdom front we eventually do want to go there anyway regardless of the repercussions just as a much larger ticket item, css modules were always a hack for the problem that shadowdom solves in encapsulation. Saying that, there is still some real gotchas with styling and shadow dom, and I’m not sure of the status of some of the proposals to remedy them (like shadow parts).

@matt-gadd
Copy link
Contributor

Also hopefully at that point when we do go there, we will have completely dropped IE11 support, as it’s just super tough to get any of this to work nicely with it, we already have enough issues with css vars that make them next to useless in theming as they have to be bulletproofed.

@agubler agubler added discussion The issue is up for discussion and removed enhancement New feature or request labels Sep 10, 2019
@agubler agubler mentioned this issue Sep 10, 2019
@agubler
Copy link
Member

agubler commented Apr 17, 2020

This has been implemented and supports slots with named children, #713 and #714

@agubler agubler closed this as completed Apr 17, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
discussion The issue is up for discussion
Projects
None yet
Development

No branches or pull requests

4 participants