Add Modals, Confirmations, Expanders and Other Messaging to Your Site

In the olden days, if you wanted to grab a user's attention with some additional information, you made a JavaScript alert appear.

Web developers also did other horrible things like create popup windows to divert attention.

Of course, these practices are still sometimes used today — and JS alerts can sometimes have legitimate uses — but in most cases, users have grown wary (and weary) of this functionality. For example, my browser of choice (Chrome) has built-in tools to prevent popups, new windows and multiple alerts from appearing. In other words, Google has slowly deprecated these methods as best practices.

Ah, how times change though, right? When building SuiteCommerce Advanced, we looked at the industry best practices for displaying additional information, including putting thought it how 'in your face' each technique is. We picked out the best (and designed a couple of others) and then built them into the base code so they can be reused.

In this article, I'm going to run through the different ways to supplement page information, including talking about how subtle/annoying each way is.

JavaScript Alerts

OK. So I just talked about how these are effectively obsolete, but let's just quickly talk about them.

In development environments, the most obvious use for them is simply as a way of testing the success or failure of some code you've written. I typically roll with console logs, but if you're doing something that's being particularly chatty (ie producing a lot of logs) then using something like the following could be a quick alternative:

alert('Your promise resolved!')

Because it creates a prompt it can be very useful if you want some code execution to stop and wait for you before proceeding. Thus, it can be quite useful when debugging asynchronous logic.

However, in terms of actual (production environment) uses, I genuinely can't think of a legitimate reason to use them. They are ugly, intrusive and frustrating. As I said there are alternatives.

Modals

Modal dialogs have long since replaced alerts as the go-to way of getting the user's attention and, additionally, requesting confirmation. We use them quite often throughout SCA such as for quick view and add-to-cart confirmation, and they are suitable for all screen widths.

In a previous tutorial I talked about adding modals to forms, which is certainly a neat trick to keeping the user in the context of the page they're currently on. For example, if the user is looking at a list of records they've submitted, navigating away from the page to view a record's data (or to delete or add a new one) is needless as we can do it in that page. This means they don't waste time navigating back and forth, and the server isn't constantly hit with requests for data.

If, however, you're looking to create an arbitrary dialog (ie one that isn't linked to forms) then that is also doable. For example, it's quite common on a number of ecommerce sites to pop up a dialog the first time a visitor hits the homepage to either inform them of some sale, encourage them to sign up to a newsletter, or let them know that returns are free. As the user hasn't requested this dialog appear, this can be quite annoying, but it's certainly less annoying than a JS alert. Let's look at that.

Homepage Modal Example

Modals are included as part of Bootstrap functionality, and we've standardized how you can call them. If you're interested, take a look at GlobalViews > GlobalViews.Modal.View.js, which is a dependency of the application skeleton layout (ApplicationSkeleton > ApplicationSkeleton.Layout.js). What's cool is that the way we've implemented them, you can just tell the application to render a view in a modal without having to add the global view as a dependency.

I've created a new module for the purposes of this tutorial, called HomepageModal. I've created a basic view (extends Backbone view and shows a template) for the modal itself and also a dummy template to render. Then, in my entry point file (HomepageModal.js) I've put the following code:

define('HomepageModal'
, [
    'Home.View'
  , 'HomepageModal.View'
  , 'Backbone'
  , 'underscore'
  ]
, function
  (
    HomeView
  , HomepageModalView
  , Backbone
  , _
  )
{
  'use strict';

  return {
    mountToApp: function(application)
    {
      return _.extend(HomeView.prototype,
      {
        initialize: function () {
          var self = this;
          this.on('afterViewRender', function() {
            var view = new HomepageModalView();
            self.options.application.getLayout().showInModal(view);
          });
        }
      });
    }
  }
});

This creates the popup. Specifically, what we're saying is:

  1. Extend the home view.
  2. Set up a listener for after the view has rendered. This uses the special hooks in Backbone that we have set up as part of BackboneExtras > Backbone.View.render.js — additionally, we also have one (beforeViewRender) that you can use to trigger things before the view has rendered.
  3. Create a new view (using the modal view I created for my module, which renders the template) and then tell the application skeleton to use the showInModal() method to render it in a modal. Note that the view I'm extending already has the application passed to it (make sure the one you're using also has it too).

The result is something along the lines of:

As I say, you can use this for a whole host of things. Why not include newsletter signup in here?

Let's take a look at global messages.

Global Message Banner

These are things that appear on top of the page. If you have the 'cookie warning' banner enabled on your site then this is an example of this functionality.

The benefits of this functionality are:

  • Its presence is immediate without being intrusive: it's at the top of the page, but it isn't large and doesn't block the user from performing actions
  • It can be dismissed, and this dismissal can be stored in a cookie so that it doesn't bother the user again
  • Comes in a range of flavors (success, info, warning and error)

As mentioned, this is used for the cookie warning banner, so take a look at CookieWarningBanner > CookieWarningBanner.js for an example of this.

To make something like the above, you'll need a module set up, including GlobalViews.Message.View as a dependency. Then add (for example, in the mountToApp function) code like the following:

mountToApp: function(application)
{
  var global_view_message = new GlobalViewsMessageView({
    message: 'This is my example message!'
  , type: 'success'
  , closable: true
  });

  application.getLayout().on('afterCompositeViewRender', function ()
  {
    application.getLayout().$('[data-type=message-placeholder]').prepend(global_view_message.render().$el);
  });
}

So what we're doing is creating the global view message by using an instance of the view. After creating it with some parameters, we're then using our old friend, the application skeleton, to listen for the view to finish rendering and then adding the rendered view to the HTML page of the page (specifically at the selector we specified).

That's the core of it. (See below for information on cookies.)

Handlebars Helper

Here's a cool little thing that you may find useful: you can actually generate these messages using a Handlebars helper. I've talked in the past about adding custom helpers, and I mentioned that we also include a number of them that we wrote ourselves in HandlebarsExtras > HandlebarsExtras.js. Well, one of them is displayMessage. For example, add the following code a template:

<div>{{displayMessage 'This is a test message that I created to show you' 'error' true}}</div>

Which results in something like:

The good thing about this is that you don't have to extend/edit a view in order to get this functionality in a template, but you do override/edit a template. The downside is that you can't easily store its dismissal in a cookie, so perhaps it's more suited to messages that bear repeating.

Saving Actions to Cookies

If you want to save the dismissal of a modal or confirmation box in a cookie then you'll need to use jQuery.cookie(), which is included in SCA as a third-party extra.

Usage is very simple. For example, check out what we use for CookieWarningBanner.js:

global_view_message.$('[data-action="close-message"]').on('click', function ()
{
  if (cookie_warning_settings.saveInCookie)
  {
    jQuery.cookie('isCookieWarningClosed', true);
  }
});

Then just be sure to wrap the code that generates the message in a conditional statement that checks whether this cookie has been set; if it has, then don't show it.

Global Confirmation Views

As mentioned, in the old days you simply create a JavaScript alert appear if you wanted someone to confirm something. But we live in the cool, shiny future now — and we don't have to put up with such horrible, out-of-date technology.

If you did the Denali tutorial (for creating the Artist module) then you'll remember that we included a confirmation view for when the user deletes a record. Indeed, this scenario is precisely the sort that you should use the confirmation view.

Confirmation dialogs (regardless of the system one's using) are always meant to obtrusive. They deliberately get in the way and force the user to deal with it before doing anything else. Thus, they should only be used when something serious is about to happen (such as deleting a record).

You can refer to the Artist module tutorial for more detailed information on how to implement it, but the gist is that you include GlobalViews.Confirmation.View and jQuery as dependencies and then call it much the same way you would a modal. Key differences are that you can attach callbacks to it, which are vital for getting this functionality to work. After all, when the user confirms the action they want to do, the code needs to be made aware of this and the callback is what makes this so. For example, this.removeModel could be called, which is what removes the model from the collection (which then triggers other actions, such as re-rendering the view).

For actual uses of this functionality in SCA, check out OrderWizard.Module.PaymentMethod > OrderWizard.Module.PaymentMethod.Creditcard.js, where we use it to create a confirmation dialog when the user requests to delete a card.

Push Panes

These are another example of functionality that has come up before. Push panes are a useful little add-on we include in SCA so that you can 'push' content off the screen for mobile users. In other words, when visual real estate is limited, hide non-essential information until the user specifically requests it.

I shan't go into detail here (read the article) but they can be included in your view simply by adding jQuery.scPush as a dependency, adding a couple of functions and then marking up your template.

The benefits for this method is that removes distractions and noise from the path of mobile users, allowing them to stream through the page to important parts. In base SCA, we use this for the saved items functionality in the cart. If you have items in your cart and then save one for later, the cart will refresh without the saved items on show. There will be, a little lower down the page, a large button that, when clicked, pulls in the saved items. These can then be added to the cart.

It's hard to think of other situations where this functionality may be useful, but if the saved items functionality is anything to go by then I think it's useful for when there are ancilliary actions that the user could do but aren't essential to the current flow.

Expanders

Similar to push panes, expanders hide information that isn't immediately relevant but, rather than hide it off-screen, it is hidden within the page and can be summoned by clicking on it. Once clicked, it 'expands' into the page.

Indeed, these are useful in similar situations, but the animation of them appearing is less-dramatic and jarring. After all, push panes temporarily change the context of the screen: it becomes focussed on the saved items, before flowing back in the main page. Expanders are different in the sense that it temporarily shows and hides additional information. Thus, you could think of expanders as useful when you want to show something, but perhaps only offers supplementary information rather than additional actions.

Unlike other functionality in this article, this one can be added purely with template and Sass changes. This is because this functionality is included with Bootstrap, so all it requires is a little markup. For example, I could add the following to my home page:

<div class="home-summary-expander-container">
    <div class="home-summary-expander-head">
        <a class="home-summary-expander-head-toggle collapsed" data-toggle="collapse" data-target="#home-summary-body" aria-expanded="false" aria-controls="estimate-shipping-form">
            Click me! <i data-toggle="tooltip" class="home-summary-expander-tooltip" title="Click this thing" ></i><i class="home-summary-expander-toggle-icon"></i>
        </a>
    </div>
    <div class="home-summary-expander-body collapse" id="home-summary-body" role="tabpanel">
        <div class="home-summary-expander-container">
            <p>Hi there</p>
        </div>
    </div>
</div>

The important things to note here are the following:

  1. We've created a container for the expander, which helps us keep everthing together. This is then split into two parts: one for the clickable element, another for the element that is revealed when requested.
  2. The data-toggle attribute that informs the JavaScript that this element is going to toggle showing/hiding some information (ie, marks that this is the expander toggle).
  3. The data-targer attribute that informs the JS of the selector to search for when the request to toggle has been made (ie, the thing that will get expanded when toggled).
  4. The id value on the expander body, which makes the selector we just specified.

Then there just needs to be some styling. For this, we use the classes that we include in BaseSassStyles > molecules > _accordions.scss. For example:

.home-summary-expander-container{
  padding: $sc-base-padding * 3;
  clear:both;
}
.home-summary-expander-head{
  @extend .accordion-head;
}
.home-summary-expander-head-toggle{
  @extend .accordion-head-toggle;
}
.home-summary-expander-toggle-icon{
  @extend .accordion-toggle-icon;
}
.home-summary-expander-body{
  @extend .accordion-body-alt;
}

In combination with the template, we get something like the following:

We use expanders quite a lot throughout SCA, certainly a lot more than push panes. As a single example, you could take a look at the CartSummary module, which is used to show/hide the items the user is in the process of ordering. It is minimized because at this point in the funnel, the shopper should be aware of the items they are buying and so needn't be reminded. (However, should they need reminding, then they can simply expand it to see the items.)

Flyouts

Phew, more ways to show this sort of stuff.

Flyouts are kinda like mini expanders — they provide extra information, but on a much smaller scale.

In the above example, we use them to offer the product lists the shopper can add the item to. However, there's no reason why you could use it to offer information about something, additional actions, or perhaps a simple confirmation step.

Like the other functionality, this is also built into SCA and you can find the required styling and markup in BaseSassStyles > Sass > atoms > _flyout.scss.

Final Thoughts

In this article we looked a whole host of different ways of displaying messaging. Included in SCA are things like modals, message boxes and push panes, as well as simpler things likes expanders and flyouts.

When adding in additional actions or information, consider the impact that you want to make as different methods have different effects on the user. If you want something quite jarring and 'in your face' then a modal certainly achieves that; if you want something small and subtle, then consider an expander.

Consider also if you want the message to be dismissable, and whether that dismissal should be stored in a cookie — again, we have the ability to quickly store cookie values, built into SCA.

The overarching takeaway from this article is that we have a lot of resuable bits of functionality that you can make use of when building an SCA site, so it's best to make use of them and see what experiences you can make with them.