How To Create A Prettier Ionic Side Menu

When you first run the command ionic start myApp sidemenu, the default sidemenu is lackluster. In an age where mobile apps all have sidemenus, it might be important to you that your app can keep up. In this post we will look at creating a custom Sidemenu component to abstract the sidemenu code in an Ionic 4 app – and then we’ll look at some simple tricks to customize the menu.

He’s a preview of what we will be making:

If you just want the code, checkout the GitHub repo here.

I have to disclose that my design skills are not very good, and that someone better qualified can certainly do a better job. But as a developer, any step in this direction is a good step forward. Let’s get started…

How to abstract the sidemenu from the AppComponent in an Ionic 4 app

Let’s first look at moving the code out of AppComponent, since really the menu has nothing to do with the component that acts as a shell for our app.

Step 1: Start by creating a new component for the sidemenu. I recommend architecting your application with multiple modules for reasons explained here. But for the purpose of this tutorial, we can keep it simple and create the component in the main AppModule.

The easiest way to do this is using the Ionic CLI:


ionic g c sidemenu

If it isn’t automatically included, be sure to import SidemenuComponent in to the declarations for AppModule.

Step 2: Now clean up the existing sidemenu-related code from app.component.html and app.component.ts. Open the HTML file and replace everything between the tags with . Your app.component.html file should now look something like this:


<ion-app>
    <ion-split-pane>
        <ion-menu>
            <app-sidemenu></app-sidemenu>
        </ion-menu>
        <ion-router-outlet main></ion-router-outlet>
    </ion-split-pane>
</ion-app>

Do the same for the controller file (app.component.ts) too.

Step 3: Open up the template file for the new component created in Step 1 (for me it’s sidemeny/sidemenu.component.html).

First add the scaffolding for a <div> which will contain the logo for your app:


<div class="header">
    <div class="logo">
        <img src="./assets/logo.svg">
    </div>
</div>

If you already have a logo file at hand, add it to the assets folder. You can use any image format here. I prefer using SVGs in PWAs because of their size on the disk, ability to scale and animations.

Step 4: Below the code for the menu header, add the following scaffold for the actual menu. For this part we will make use of the ion-menu-toggle component provided in @ionic/core because it handles a lot of the details around hiding the menu when an option is selected, as well as being able to swipe from the edge of the screen to open the menu.


<div class="nav">

    <ion-menu-toggle auto-hide="false" *ngFor="let p of appPages">
        <div class="nav-item" [routerLink]="[p.url]">
            <span class="icon">{{p.icon}}</span>
            {{p.title}}
            <span class="divider"></span>
        </div>
    </ion-menu-toggle>
</div>

Asides from the wrapping <div>, this code is very similar to what was removed from the original sidemenu in app.component.html. The only significant differences are the custom classes and styling being added to each nav item. This will allow each element to be styled later using CSS.

Step 5: And finally, for the footer of the sidemenu, add the following code:


<div class="footer">
    <div class="footer-nav">
        <ul>
            <li (click)="leaveAReview()">Like this app? Leave a review!</li>
        </ul>
    </div>

    <div class="footer-social">
        <ion-icon (click)="openInstagramProfile()" name="logo-instagram"></ion-icon>
        <ion-icon (click)="openFacebookProfile()" name="logo-facebook"></ion-icon>
        <ion-icon (click)="openTwitterProfile()" name="logo-twitter"></ion-icon>
        <ion-icon (click)="openWebsite()" name="globe"></ion-icon>
    </div>

    <div class="footer-app-version">
        Version v{{version}}
    </div>
</div>

You can remove any elements you don’t think you need in your sidemenu, but for the app I am currently building, a “Leave A Review” link, social icons and the app’s version number are all great features to include.

You’ve completed the first step of this tutorial. Your AppComponent should no longer contain any code related to the sidemenu.

Adding implementation logic for the sidemenu

At this point you can run your code in the browser, and you’ll notice that the sidemenu sort of works. But there’s errors in your console because appPages doesn’t exist in the controller… and, well… the sidemenu is still very ugly.

Let’s fix the controller first…

Step 1: Add the following code to the body of the controller class (sidemenu.component.ts):


...
export class SidemenuComponent implements OnInit {

    version: string = "0.7.2";

    appPages = [
        {
            title: 'Home',
            url: '/home/landing',
            icon: '🏠'
        },
        {
            title: 'My Profile',
            url: '/profile',
            icon: '👤'
        },
        {
            title: 'Switch City',
            url: '/settings/set-location',
            icon: '🏙'
	},
        {
            title: "Promotions",
            url: "/promotions",
            icon: "💸"
        }
    ];
    
    constructor() { }
    
    ngOnInit() { }
    
    leaveAReview() { }

    openFacebookProfile() { }

    openInstagramProfile() { }

    openTwitterProfile() { }

    openWebsite() { }

}

I have intentionally left the implementation of the functions blank as this is beyond the scope of this tutorial. The important bit of code here is the appPages class variable which, if you remember, is almost identical to what we removed from the app.component.ts file. All it does is provide an Array of objects which are then iterated using a *ngFor in the template.

Styling the sidemenu

We’re getting there! Now if you run the app in your browser you’ll begin to see the sidemenu take shape. Granted, it’s a bit all over the place but there is now a logo, a menu and a footer.

The final part of this guide is about styling the sidemenu. As mentioned previously, I have no talents in CSS or design, so what we are about to do here is pretty limited.

Step 1: I like to use SCSS for styling. If you’ve created your project using CSS, that’s fine – but you’ll need to adapt my example code to work with CSS in some places. We’ll be using Flexbox, which again I have no talent in – but this guide is pretty comprehensive and outlines everything we are about to use.

Step 2: Open up the sidemenu.component.scss file.

(Optional) Import the following font from Google Fonts with the following lines of code at the top of the SCSS file:


@import url('https://fonts.googleapis.com/css?family=Varela+Round&display=swap');

Set the background colour (gradient) of the sidemenu component, and initialise it as a Flexbox using the following code:


:host {
    display: flex;
    flex-direction: column;
    height: 100%;
    background: var(--ion-color-secondary);
    background-image: linear-gradient(to right, #3180b6, #2b79af, #2572a7, #1e6ba0, #176499);
    color: var(--ion-color-primary-contrast);
    font-family: 'Varela Round', sans-serif;
    padding-bottom: var(--ion-safe-area-bottom);
}

The :host {} selector is a hacky way to apply styles to the actual sidemenu component (<app-sidemenu><:/app-sidemenu>) itself when using Shadow DOM. If you open the app through your browser now you’ll see a rich blue gradient background for the entire width and height of your sidemenu.

By specifying the flex-direction: column property, this component will now arrange any children elements as a column as opposed to the standard row. Typically this would require a lot of boilerplate code to work on multiple screen sizes, but with Flexbox it’s really simple.

Step 3: Use the following CSS as inspiration to style the rest of the menu to your liking:


.header {
    padding: 1rem;
    padding-top: calc(var(--ion-safe-area-top) + 1.5rem);
	display: flex;
	align-content: center;
	justify-content: center;
	width: 100%;
	padding-left: 0.5rem;
}

.logo img {
	width: 80%;
}

.nav {
    display: flex;
    flex-grow: 5;
    flex-direction: column;
    overflow-x: hidden;
    overflow-y: scroll;
}

.nav-item {
    padding: 0.75rem 0.5rem 0 0.5rem;
    font-size: 1.2rem;
}

.nav-item span.divider {
    padding-top: 0.75rem;
    width: 100%;
    display: block;
    border-bottom: solid 1px rgba(34, 34, 34, 0.18);
}

.icon {
    margin-right: 0.5rem;
}

.nav-item:hover, .nav-item:active {
    background: rgba(var(34, 34, 34), 0.1);
}

.footer {
  	display: flex;
  	flex-direction: column;
  	justify-content: flex-end;
}

.footer-nav {
    padding: 0.5rem;
}

.footer-nav ul {
    width: 100%;
    padding: 0;
    text-align: center;

    li {
        padding: 0;
        list-style: none;
    }
}

.footer-social {
    display: flex;
    flex-direction: row;
    justify-content: space-evenly;
    padding-top: 0.5rem;
    padding-bottom: 0.5rem;
    font-size: 2rem;
}

.footer-app-version {
    padding: 0.3rem;
    text-align: center;
    font-size: 0.8rem;
}

The completed version of this code is available from this GitHub repo. Clone the repository, run npm install and then ionic serve. That’s all there is to it!

Subscribe to Email Updates