Creating a Facebook Style Reaction Button in Ionic



·

Near the start of 2016, Facebook released “Reactions” which gave users a way to express themselves more deeply than just with a single “Like”. Rather than adding it a bunch of new buttons for the reactions, Facebook stayed with a single “Like” button that would then display more options when the button was held down:

Facebook Reactions

If the user just taps the “Like” button it will trigger a like, but if the user holds down the “Like” button it will launch the reactions pop up. This keeps the interface simple, but still provides easy access to the new reactions. It is an interesting design, and it is actually quite easy to implement in Ionic as well.

In this tutorial, we are going to create a simplified version of the reactions button that looks like this:

Ionic Reactions

This is a bare-bones implementation with not much effort put into styling it well, but if there is enough interest, I may do a follow-up blog post with a more complete implementation.

Before We Get Started

Last updated for Ionic 3.6.1

Before you go through this tutorial, you should have at least a basic understanding of Ionic concepts. You must also already have Ionic set up on your machine.

If you’re not familiar with Ionic already, I’d recommend reading my Ionic Beginners Guide or watching my beginners series first to get up and running and understand the basic concepts. If you want a much more detailed guide for learning Ionic, then take a look at Building Mobile Apps with Ionic.

1. Create a Template

We’re going to need some content to play around with, so if you don’t already have something with a “Like” button or an equivalent, you should add the following to your application.

Add the following code to one of your templates:

<ion-header>
  <ion-navbar color="primary">
    <ion-title>
      Reactions
    </ion-title>
  </ion-navbar>
</ion-header>

<ion-content padding>

	<ion-card>

	  <ion-item>
	    <ion-avatar item-start>
	      <img src="http://placehold.it/75">
	    </ion-avatar>
	    <h2>Marty McFly</h2>
	    <p>November 5, 1955</p>
	  </ion-item>

	  <img src="http://placehold.it/300x200" />

	  <ion-card-content>
	    <p>Wait a minute. Wait a minute, Doc. Uhhh... Are you telling me that you built a time machine... out of a DeLorean?! Whoa. This is heavy.</p>
	  </ion-card-content>

	  <ion-row>
	    <ion-col>
	      <button ion-button icon-left clear small>
	        <ion-icon name="thumbs-up"></ion-icon>
	        <div>12 Likes</div>
	      </button>
	    </ion-col>
	    <ion-col>
	      <button ion-button icon-left clear small>
	        <ion-icon name="text"></ion-icon>
	        <div>4 Comments</div>
	      </button>
	    </ion-col>
	    <ion-col center text-center>
	      <ion-note>
	        11h ago
	      </ion-note>
	    </ion-col>
	  </ion-row>

	</ion-card>

</ion-content>

This is just using a <ion-card> example from the documentation.

2. Create a Reactions Page

In order to achieve the reactions popup, we are going to use Ionic’s Popover directive, which will allow us to display a modal window next to an element.

We can pass a component to Popover and it will display that component as a modal. The Popover component is documented as requiring a page, but an Ionic page is just a normal Angular component, so you don’t technically have to generate a “page” if you don’t want to – that is what we will be doing, though.

Generate a new page to use for the Reactions

ionic g page Reactions

All we are going to do on this page is add a few buttons, but we will also need to do some styling to remove a lot of the normal page styling which is going to make the popover look weird.

Modify src/pages/reactions/reactions.html to reflect the following:

<ion-content>

    <ion-grid>
        <ion-row>
            <ion-col col-2>
                <button (click)="share()" ion-button small round icon-only><ion-icon name="happy"></ion-icon></button>
            </ion-col>
            <ion-col col-2>
                <button (click)="share()" ion-button small round icon-only><ion-icon name="wine"></ion-icon></button>
            </ion-col>
            <ion-col col-2>
                <button (click)="share()" ion-button small round icon-only><ion-icon name="heart"></ion-icon></button>
            </ion-col>
            <ion-col col-2>
                <button (click)="share()" ion-button small round icon-only><ion-icon name="sad"></ion-icon></button>
            </ion-col>
            <ion-col col-2>
                <button (click)="share()" ion-button small round icon-only><ion-icon name="outlet"></ion-icon></button>
            </ion-col>
            <ion-col col-2>
                <button (click)="share()" ion-button small round icon-only><ion-icon name="star"></ion-icon></button>
            </ion-col>
        </ion-row>
    </ion-grid>

</ion-content>

This adds 6 buttons to a grid, and each of those buttons triggers a share function. This function won’t actually do anything, we will just use it to trigger the closing of the popover (but you could use it to do something else, of course).

Modify src/pages/reactions/reactions.ts to reflect the following:

import { Component } from '@angular/core';
import { IonicPage, NavController, NavParams, ViewController } from 'ionic-angular';

@IonicPage()
@Component({
  selector: 'page-reactions',
  templateUrl: 'reactions.html',
})
export class ReactionsPage {

    constructor(private navCtrl: NavController, private navParams: NavParams, private viewCtrl: ViewController) {

    }

    ionViewDidLoad() {
        console.log('ionViewDidLoad ReactionsPage');
    }

    share(){
        this.viewCtrl.dismiss();
    }

}

This just sets up the ViewController so that we can dismiss the popover when the share function is called. Now we just need to add a couple of styles.

Modify src/pages/reactions/reactions.scss to reflect the following:

page-reactions {

    ion-content {
        padding: 0;
    }

    button {
        width: 40px;
    }

}

This will make our reactions page display nicely, but we are also going to make some additional style changes so that the popover that is displayed looks more like the Facebook reactions bar.

Add the following variables to the src/theme/variables.scss file:

// App iOS Variables
// --------------------------------------------------
// iOS only Sass variables can go here

$popover-ios-width: 95%;

// App Material Design Variables
// --------------------------------------------------
// Material Design only Sass variables can go here

$popover-md-width: 95%;

This will modify the popover so that it takes up 95% of the width of the page. Finally, we are going to add a global style to give the popover a bit more of a shadow.

Add the following styles to src/app/app.scss:

.popover-wrapper .popover-content {
    box-shadow: 0px 3px 15px 0px rgba(0,0,0,0.25);
}

3. Trigger the Popover

We have our reactions popover set up nicely – now we just need to trigger it. We are going to add two handlers to our “Like” button to handle cases where the user just taps, and cases where the user holds down on the like button.

Modify the like button to reflect the following:

<button (click)="like()" (press)="showReactions($event)" ion-button icon-left clear small>

We are creating an event binding for the press event, which will only trigger if the user taps and holds down on the screen. It’s important that we pass the $event through to the showReactions function because, in order for the popover to know where on the screen it needs to be displayed, it needs access to the pointer event that triggered it.

Now we just need to create the functions to handle these events.

Modify your page to include the following two functions:

import { Component } from '@angular/core';
import { NavController, PopoverController } from 'ionic-angular';
import { ReactionsPage } from '../../pages/reactions/reactions';

@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {

    constructor(public navCtrl: NavController, private popoverCtrl: PopoverController) {
        // THIS IS JUST FOR TESTING
        window.addEventListener("contextmenu", (e) => { e.preventDefault(); });
    }

    showReactions(ev){

        let reactions = this.popoverCtrl.create(ReactionsPage);

        reactions.present({
            ev: ev
        });

    }

    like(){
        console.log("like");
    }

}

When we call the present method on the popover, notice that we are sending the event we passed in along with it. I’ve also added some code to the constructor that will prevent the context menu from launching. This is not required for production, but if you are using the Chrome device simulator, the context menu is triggered by clicking and holding on the screen. Since this is the same way that our reactions popover is triggered, it makes it annoying to test.

Summary

This was a reasonably simple tutorial, but it is quite a cool little technique. As I mentioned, if there is enough interest I may do a more advanced implementation that more closely mimics Facebook’s implementation.

What to watch next...

  • Denislav Popov

    It would definitely be interesting to see how far can we take this option, both ui and functionality wise!

  • JTumain

    Awesome. I would definitely be interested to see a follow-up to this.

  • I would definitely like the animation be added as we see on facebook.

  • Arturo Blanco

    Awesome Josh!!!! we’d really love a follow-up post….