The Ionic Framework has a very good reusable component library for building really great UI’s. It’s possible to use these in Stencil Components too. For most of the Ionic Components, the usage involved to include them in your component is standard JSX. Other times (like with overlays) it differs a bit and is different even from the JavaScript usage instructions.

Ionic comes with a collection of different overalay components which are typically created, displayed, and dismissed completely without JSX. This was something confusing to me when first trying to use some of the Ionic Components with Stencil. In this post I’ll go over a basic example of using an Ionic overlay component in Stencil.

Add @ionic/core to Project

In order to use Ionic with Stencil, we need to use the core version of the library. This is meant to be used with standard JavaScript projects without frameworks.

npm i @ionic/core@latest --save-dev

/* src/global/app.ts */

import '@ionic/core'

Make sure to load app.ts as your global startup script.

/* stencil.config.ts */

import { Config } from '@stencil/core';

export const config: Config = {
  globalScript: 'src/global/app.ts',
  // ...

Now it’s possible to use any Ionic Component in the Stencil project.

Using Ionic Components

Let’s create a simple component in Stencil that uses an ion-button to open an ion-alert. This will show two different way of using Ionic components.

The ion-button is straightforward in that we can directly use it in our JSX. No need to import anything since we’re importing @ionic/core in app.ts.

render() {
  return (
      <ion-button>Open Alert</ion-button>

The ion-alert, however works a bit different. It needs to be created and presented via methods. Most of the overlays in @ionic/core have a controller that needs to be imported first to create the HTMLElement.

import { Component, ComponentInterface, Host, h} from '@stencil/core';
import { alertController } from '@ionic/core';

  tag: 'my-button',
  styleUrl: 'my-button',
export class MyButton implements ComponentInterface {

  async openAlert(e: UIEvent) {
    const alert: HTMLIonAlertElement = await alertController.create({
      header: `Button Clicked!`,
      buttons: [{
        text: 'Ok',
        role: 'select'
      }, {
        text: 'Cancel',
        role: 'cancel',
        handler: () => {}

    await alert.present();

  render() {
    return (
        <ion-button onClick={(e: UIEvent) => this.openAlert(e)}>Open Alert</ion-button>