Most (well maintained) Angular projects eventually reach the point where they would benefit from having a few generic components that use transclusion.

Maybe you have a timeline feed screen with multiple types of feed items.

Or some tabs widget.

Or a generic modal you use across the app.

Transclusion allows us to create very customizable components since you can inject them with other components, and not just pass rigid inputs (e.g. specific bindings). That’s pretty much how things like ng-repeat work: you provide those directives with inner HTML that they then use.

Prior to Angular 1.5 a component could only transclude a single entry: whatever you gave it was had to be used as a whole.

But, among other goodies introduced in 1.5 we also got multiple slot transclusion, which comes in handy at times.

Example

Say you want to create a generic modal, that can have both the title and body customized.

Here’s an example of someone using the modal component we’ll create:

1 2 3 4 5 6 <modal> <modal -title > Are you sure ? < /modal-title> <modal -body > You can only do this times < /modal-body> </modal>

Those modal-title and modal-body elements are the transclusion slots we will now define and use in our modal component:

1 2 3 4 5 6 7 8 9 10 11 12 13 app . component ( 'modal' , { template : [ '<div ng-transclude="title"></div>' , '<div ng-transclude="body"></div>' ]. join ( '' ), transclude : { title : 'modalTitle' , body : 'modalBody' }, controller : function () { // Stuff to make this component render as a modal } });

As you can see above, we define the component’s transclude property to have 2 slots, named title and body .

Each slot also has the name of the element it expects to see its content inside.

Then in the component’s template we can decide where to insert the transcluded elements by using the ng-transclude directive and supplying it with the slot’s name.

As you can see transclusion automatically takes care of things like passing the scopes correctly so that even though the templates we passed reference the original component’s scope ( $ctrl ), it’s still properly visible inside.