Slot

Understanding How Slots are Used in Ionic 4



·

As you may know by now, the big change in Ionic 4 is that all of Ionic’s components are becoming web components. Since web components are a feature of browsers, and not of specific frameworks, this will allow Ionic to work with any framework or no framework at all.

The basic idea behind Ionic’s components are not changing – you just plop a custom element into your template:

<ion-list></ion-list>

and you get a smooth scrolling list formatted for mobile out of the box. Although the changes the Ionic team has made behind the scenes are quite massive in scale, the result will remain basically the same for you. You can continue to use:

<ion-list></ion-list>

in Ionic 4 just as you would expect. There have been a few things that have changed in this migration to web components: <button ion-button> is becoming <ion-button>, we are saying goodbye to <ion-navbar> in favour of <ion-toolbar>, and there are a few other minor template updates that will be required. Perhaps the most noticeable change is the sudden appearance of slots:

<ion-toolbar>
    <ion-buttons slot="end"></ion-buttons>
</ion-toolbar>

<ion-button>
  <ion-icon slot="icon-only" name="home"></ion-icon>
</ion-button>

<ion-fab slot="fixed"></ion-fab>

<ion-item>
  <div slot="start"></div>
  <ion-label>Item Label</ion-label>
  <div slot="end"></div>
</ion-item>

<ion-item>
  <ion-label>Apple</ion-label>
  <ion-radio slot="start" value="apple"></ion-radio>
</ion-item>

These are just a few examples, you will find that slots are used just about everywhere where attributes like item-left, end, start, icon-left, range-left, range-right would have been used previously.

In a broad sense, we can see pretty clearly that the use of “slot” is used to affect the positioning or style of an element because of the fact that they are replacing these attributes. I think that most people will see this as a welcome change since it unifies the approach and it means a lot less to remember.

However, I wanted to spend some time in this article explaining exactly what these “slots” are and how they work. Knowledge of how slots work is not required in order for you to effectively build Ionic applications. You can just use the appropriate slot as the documentation describes to achieve what you want. You would only ever create your own implementation using slots if you were building your own web components (which for most people won’t be the case).

That said, I think it is always useful to understand what is going on behind the scenes, and a bit of a dig into the source code powering the framework you are using can be empowering.

What is a Slot?

Slots are a feature of web components that are used to make the components more dynamic. It allows additional content/elements to be supplied when using the component that can then be displayed inside of the component. If you’re familiar with content projection in Angular using <ng-content> it’s basically the same idea, but slots are for web components and are thus natively supported in the browser (no framework required).

It is much easier to explain the concept of a slot with code than with words. Inside of a web components template (like <ion-toolbar>) it can have <slot> elements:

<div>Some stuff here</div>
<slot></slot>
<p>A paragraph!</p>

Let’s pretend that this is the template of our own custom web component called <my-useless-component>. Since we have a <slot> in the template, we can supply content to it when using the component. If we were to do this:

<my-useless-component>
    Hello!
</my-useless-component>

Then our Hello! message will be injected where the <slot> is, and the rest of the template will remain as is. We can also use multiple slots and give them names:

<slot name="left"></slot>
<slot name="right"></slot>

By naming the slots, we are able to target the specific slot we want the content to be injected into. This is where we might start using the slot property like this:

<my-useless-component>
    <div slot="left">To the left!</div>
    <div slot="right">To the right!</div>
</my-useless-component>

and this is pretty much the same thing that is going on with Ionic’s own <ion-toolbar> component. Components that can take on a “slot” property (e.g. slot="start") are referred to as Slotable. Slottable elements are slotted into the slots available in a web component.

NOTE: Remember that this is a feature of web components, you would not be able to use this directly in your own components in an Ionic/Angular application. If you are using Stencil to build your own web components, then you could use this feature.

How are Slots used in Ionic?

To see how slots are used in Ionic, we are going to dive right into the source code and take a look. Any time you see an element using a slot attribute (something that is Slottable) you can deduce that the parent element is a web component that is making use of slots. The first example I gave before was:

<ion-toolbar>
    <ion-buttons slot="end"></ion-buttons>
</ion-toolbar>

We can position <ion-buttons> inside of our toolbar using slot, so the template for <ion-toolbar> must be using <slot> in its template. Let’s check by looking at the /source for the Toolbar component:

  render() {

    const backgroundCss = createThemedClasses(this.mode, this.color, 'toolbar-background');
    const contentCss = createThemedClasses(this.mode, this.color, 'toolbar-content');

    return [
      <div class={backgroundCss}></div>,
      <slot name="start"></slot>,
      <slot name="secondary"></slot>,
      <div class={contentCss}>
        <slot></slot>
      </div>,
      <slot name="primary"></slot>,
      <slot name="end"></slot>
    ];

  }

This is some Stencil code that is used to generate the web component. Once again, you will not be required to use Stencil in order to use Ionic, this is just a tool that Ionic uses to build their own web components (but you can use it if you want to build your own web components).

If we look at the template that is being returned inside of the render() method, we can see various slots being used. We have the generic <slot></slot> which is where all of the content inside of will go by default, but we also have additional slots with names of start, secondary, primary, and end. This means that if we add an element inside of <ion-toolbar> and assign one of these slots, it will be placed in that particular position.

A typical toolbar implementation in an Ionic application might look like this:

  <ion-toolbar color="success">
    <ion-title>
      The Title
    </ion-title>
    <ion-buttons slot="end">
      <ion-button (click)="doSomething()">
        <ion-icon slot="icon-only" name="add-circle"></ion-icon>
      </ion-button>
    </ion-buttons>
  </ion-toolbar>

We are supplying the toolbar with an <ion-title> and an <ion-buttons>. The <ion-title> doesn’t specify a slot, so that is just going to be inserted into the place of the generic <slot> in the template. However, since we specify slot="end" on the <ion-buttons> component, then that is going to be inserted specifically into the <slot name="end"></slot> portion of the toolbars template.

You may notice that in the example above we have also used an <ion-icon> that specifies a slot of icon-only. Since that is inside of an <ion-button> then that must mean that the <ion-button> component also uses slots (and that there is specifically an icon-only slot. Let’s take a look at the /source:

<span class="button-inner">
    <slot name="icon-only"></slot>
    <slot name="start"></slot>
    <slot></slot>
    <slot name="end"></slot>
</span>

The full template for this component is quite complex, but this is the important part. We can see that it does indeed have an icon-only slot, along with a start, end, and a generic slot as well. So, we can see that if we specify icon-only on an icon inside of a button it will be added to a specific slot… but why? What would be the difference between placing it in the icon-only slot instead of the start slot?

In this case, the positional difference between start and icon-only doesn’t really matter, but the reason we use icon-only is to increase the size of the icon since it is being displayed by itself and not with text.

If we look at the styling being used for this component, we will find the following:

.button ion-icon[slot="icon-only"] {
  font-size: 1.8em;
}

We can see that this CSS rule is targeting icons that are specified in the icon-only slot (this CSS selector targets ion-icon elements that have a slot property that is equal to icon-only) and applying a style (in this case, increasing the font size to make the icon bigger). So, as well as using the web component functionality of slots to position content within templates, Ionic is also using this same method to apply specific styles.

Summary

As I mentioned at the beginning, none of this is super important to know if you aren’t interested in building your own web components. However, I think it is nice to understand why certain changes are being made, and it can make development easier as well. If you get comfortable with diving into the source code and figuring out what is happening behind the scenes, you will likely find yourself becoming stuck less often.

What to watch next...