Web Components Named Slots
- The key is the name of a element or directive in camel-case slot we can later use in our template, the value the name of an element or directive in camel-case we want to transclude. We replaced the default 'Details' summary with an element that has ng-transclude='summarySlot'.
- CPU Motherboards Offer PCIe® Slots and a Home for the CPU The CPU connects to the motherboard, and provides Peripheral Component Interconnect express (PCIe) slots to connect devices. Depending on the motherboard, you can add video and graphics cards, a Solid State Drive (SSD) and more.
- PCI: The PCI slot is the most common form of internal expansion for a PC. Some PCs have a mixture of PCI and PCI Express slots. If so, go with PCI Express when you have that option. AGP: This type of expansion slot was specifically designed to deal with graphics adapters. In fact, AGP stands for Accelerated Graphics Port.
Named Slots Creating more complex elements that can take various pieces of content from the element’s user can be done easily using named slots. You can see a simple example here where a named slot is used alongside a regular slot.
With the upcoming final 1.5 release of the AngularJS framework, tons of new features, improvements and bug fixes are right around the corner. One of those features is multiple transclusion via named slots. While transclusion is already a very nice and powerful feature, with the 1.5 release it’s going to be taken to the next level. In this article we’re going to discuss what multiple transclusion is all about and how it helps the framework to align more with the web components technologies.
Understanding Transclusion
We surely don’t have to make a huge recap on what transclusion is, since there are tons of resources out there in the internet already and most of us are probably very familiar with that feature. However, just to pick up everyone reading this article, here’s what transclusion is (stolen from Wikipedia):
In computer science, transclusion is the inclusion of part or all of an electronic document into one or more other documents by reference.
Clear, right? Well, not really.
It’s actually way simpler than it sounds. In Angular world, when we build directives, transclusion allows us to take the HTML from the outer world, that is in between our directive tags, and insert it somewhere inside our directive template, which the outside world doesn’t really know about.
The easiest way to illustrate that is the <details>
element. <details>
renders a UI component (in some browers), which we can click on to open and close it.
As you can see, we can put some HTML in between the <details>
tags and it gets somehow magically projected somewhere else. The thing that makes this possible are Content Insertion Points which are part of the Shadow DOM specification. They allow us to mark places in an element’s template where Light DOM is going to be projected.
Angular’s transclusion feature is basically some sort of polyfill for this kind of functionality, however, pretty much implemented in an Angular specific way. It really just works with the framework.
We can easily reimplement a <details>
element with Angular like this:
Setting transclude
to true
enables transclusion for the directive, whereas ng-transclude
in the template tells Angular where to put the HTML from the outside world. Of course, this is a very very simple reimplementation, but it’s really just to demonstrate the point of transclusion.
Tero has written an amazing guide on transclusion, if you want to dig deeper on that topic I highly recommend his guide.
Even though transclusion is a very neat feature to provide APIs where consumers can hook into, it turns out that there’s at least one drawback. We either take everything or nothing. Whenever we use transclusion, there’s no way to specify what we want to transclude, we always have to take the whole DOM. This is where Shadow DOM and Content Insertion Points really shine.
Content Selection and Shadow DOM
Shadow DOM uses a <content>
tag to specify insertion points. If we’d reimplement the <details>
tag with web components technologies, our component’s template could look something like this (simplified):
This is more or less the equivalent of transclusion in Angular. However, Shadow DOM takes it even further. It allows us to specify what we want to project into our shadow DOM. This is where the select
attribute comes into play. Let’s say we’re only interested in projecting <h2>
elements, we can update our template with content selection like this:
Super powerful! The specification has even evolved more with another <slot>
tag which is a bit more powerful. However, after all it everything boils down to what we’ve seen so far.
This is where multiple transclusion comes into play, with Angular 1.5 we can finally do exactly that!
Multiple Transclusion
Multiple transclusion has been proposed a loooong time ago. In fact, Vojta came up with this over two years ago. Now, thanks to Pete, it’s right here. So let’s get back to our <ng-details>
implementation and take a look at it.
The <details>
tag allows us to configure a “summary” which defaults to 'Details'
. In order to change it, all we have to do is to put a <summary>
tag inside the <details>
element like this:
This we couldn’t do with Angular’s transclusion before, because we can’t just take all the DOM as it is. We would need to take the <summary>
, transclude at a specific place in our template, and then we’d need to transclude the rest somewhere else.
With multpile transclusion we can totally do that. We just have to extend our directive a tiny little bit (note that we’re using <span>
as summary element, but you can use whatever you want):
We basically made two changes:
- We changed the
transclude
property to an object which specifies the transclusion slots. The key is the name of aelement or directive in camel-caseslot we can later use in our template, the value the name of anelement or directive in camel-casewe want to transclude. - We replaced the default
'Details'
summary with an element that hasng-transclude='summarySlot'
. As you can see,ng-transclude
now excepts a string which is the name of a transclusion slot that we’ve defined earlier.
The original ng-transclude
stays as is, since it simply takes the rest to be transcluded. We can now use our <ng-details>
component like this:
Web Components Named Slots No Deposit
We can even make transclusion slots optional by prefixing the element tag name with a ?
like this:
This is already very cool, but our ng-details
directive still lacks one specific behaviour. If we don’t specify a <summary>
, <details>
defaults to 'Details'
. Our component however, doesn’t do this. We can provide a fallback summary by simply putting something into the DOM where other elements will be transcluded to:
Seen what happened? We just put 'Details'
as text into our span element. This text will be replace with the transcluded DOM, if it is applied.
Web Components Named Slots Games
What are you waiting for? Start using multiple transclusion in your directives and design beautful APIs for your consumers!