Building a burger is one of the simplest tasks around. The base stays the same while the filling changes, so let's put together our own burger component.

In this piece, we look at how to use ng-content to create a flexible region and support multiple insertion points.

  • Leverage ng-content for content projection.
  • Use multiple slots for targeted content placement.

Feel free to experiment with the live demo.

The setup.

We have a collection of ingredient components ready to assemble into our burger component.

<top-bun></top-bun>
<cheese></cheese>
<bottom-bun></bottom-bun>
<tomato></tomato>
<onion></onion>
<meat></meat>
Enter fullscreen mode Exit fullscreen mode

The goal is to build a burger component that wraps these ingredients, much like a real burger, using two powerful Angular features: content projection and the ng-content element.

Content projection and ng-content

Angular makes components reusable through content projection. This approach lets you declare a region in a component that can be filled with whatever content you choose, whether that's plain elements or other components.

With this technique, we can define a wrapper while deciding which parts of the UI are fixed and which are flexible.

When you place the ng-content tag in a template, Angular swaps that area out for the elements or components you provide.

To get started, generate the burger component and insert the ng-content tag into its template.

import { Component } from '@angular/core';

@Component({
  selector: 'burger',
  templateUrl: './burger.component.html',
})
export class BurgerComponent {}
Enter fullscreen mode Exit fullscreen mode
<div class="burger">
  <ng-content></ng-content>
</div>
Enter fullscreen mode Exit fullscreen mode

That's step one done. Now move the ingredients into the burger component's body.

<burger>
  <top-bun></top-bun>
  <cheese></cheese>
  <tomato></tomato>
  <onion></onion>
  <meat></meat>
  <bottom-bun></bottom-bun>
</burger>
Enter fullscreen mode Exit fullscreen mode

It works. The burger component now accepts child elements and components inside it, with the burger acting as the wrapper.

Burger complete

Why isn't the meat in the middle?

Multiple slots

Every burger needs the meat at the center. We want to stay flexible, adding components or forcing them into place without breaking the burger, so the burger component should render elements in specific areas.

The ng-content element has an optional selector property. This picks up content that matches a CSS selector, such as a class or attribute, letting us define those areas.

Update the default burger with the following:

  • include top-bun and bottom-bun as defaults for all burgers.
  • three ng-content slots with selectors for top, middle, and bottom.
  • an ng-content slot for the price.
  • a default ng-content for ingredients without a specific place.
<div class="burger">
  <top-bun></top-bun>
  <ng-content select="[top]"></ng-content>
  <ng-content select="[middle]"></ng-content>
  <ng-content select="[bottom]"></ng-content>
  <bottom-bun></bottom-bun>
</div>

<div class="price">
  <ng-content select="[price]"></ng-content>
</div>

<div>
  <p>These ingredients don't have a location</p>
  <ng-content></ng-content>
</div>

Enter fullscreen mode Exit fullscreen mode

Now our burger component is ready. Any ingredient or piece without a designated place falls into the other div.

The tomato and onion have no attributes, so they end up in the default ng-content.

<!-- Burger with ingredients without location.-->
<burger>
  <tomato></tomato>
  <cheese top></cheese>
  <meat middle></meat>
  <onion></onion>
  <span price>4€</span>
</burger>
Enter fullscreen mode Exit fullscreen mode

Alt Text

Wrapping up!

We now have a reusable component built with content projection. It's ready to construct new burgers, with the ability to place elements into specific spots or fall back to a default location.

That's all there is to it! Hopefully, this gives you a helpful start with ng-content and adds more flexibility to your components.

If this helped you, pass it along!

Photo by Haseeb Jamil on Unsplash