Some time ago I wrote a tutorial for a super-simple modal dialog for Ember. I was frustrated with the complexity of bringing in extra packages with fancy functionality when you sometimes just need a quick pop-up! I also wanted to explore the Component workflow to make a modular bit of code I could reuse later.

Since then, Ember's undergone some pretty radical changes. The framework has moved from pushing the traditional Model-View-Controller pattern to "encouraging" (in that maddening, wonderful, Tomster way) a workflow based on Web Components. Views have been deprecated, controllers are on their way out, and components are the way to go for continued health and happiness!

Unfortunately, while I was working in the right direction by creating my modal as a component, I remained dependent on my old MVC fallback - in particular, the "V" (View). Today, I aim to correct that! We'll walk back through creating an identical modal to my previous tutorial's, but with some key changes to make it more compatible with the latest view-less builds of Ember (1.13 & 2.0.0-beta.1, at the time of this writing).

tl;dr? Code for you. Good luck.

Ready? Let's dive in!

Framework All The Things!

We'll leverage Ember CLI's kickass generators to get started:

$ ember new <your-app-name>
$ cd <your-app-name>
$ ember generate controller application
$ ember generate component simple-modal

These commands will create an empty scaffold of everything we need to continue. The great thing is that Ember is ready to roll in this state - use ember server in your terminal, and point your browser at http://localhost:4200. Boom! You're Ember-ing!

Component-First Development

We'll build our component first. Components need two files:

  • a component file in app/components
  • a component template in app/templates/components

Before we decide on appearance, let's get our basic functionality down. Open app/components/simple-modal.js and update it to match the following code:

import Ember from 'ember';
import layout from '../templates/components/simple-modal';

export default Ember.Component.extend({
    actions: {
        toggleModal: function() {
            // Joel wuz here!
    layout: layout

That's all we need for our component. The most important property is the actions object, which includes a method to toggle the modal on and off. This will come in handy later on. We're also defining the component's layout explicitly here. This takes advantage of ES6's import directive to get our template file that ember generate helpfully made for us.

A quick note: layout is optional! If you don't define it, Ember will just look for a file in templates/components with the same root name as your component's .js file. I'm keeping it here to provide a better example of the ES6 syntax, but feel free to blow both that and the corresponding import line away and watch the magic happen anyway!

Playing Dress-Up

Take a breath - this is the halfway point. No, seriously. I promised "simple".

To style our component we need to fill in the layout file we referenced earlier. You can find it at app/templates/components/simple-modal.hbs - open that file and fill it in like so:

{{#if enabled}}
  <div {{action 'toggleModal'}} class="modal-fog">
    <div class="modal-frame">
      <div class="modal-title">
      <div class="modal-body">

Let's walk through that:

  • {{#if enabled}}..{{/if}}: This means we only render if the component's enabled property is true. Remember .toggleProperty('enabled') from earlier? This is the second half of that equation.
  • <div {{action 'toggleModal'}} ..>: This will close our modal when the background overlay is clicked (Ember's action helper acts as an onClick event, by default).
  • {{title}}: This will print the value of the title property on our component.
  • {{yield}}: Yield is a special helper than spits out whatever is passed inside a block's body. In this case, we'll declare our component in block form on our app, and we'll use yield as the modal's body content.

Now we have a component. That's it - two files, no whammies! It's a great time to make sure you don't have unexpected errors. Make sure ember server is still running and refresh your browser (still at http://localhost:4200). You should have no errors on your console.

Looking Good, Feeling Good

We could render our component now, but it won't look much like a modal. Let's add some flair. Open app/styles/app.css and add the lame CSS from below:

.modal-fog {
  background: rgba(30, 30, 30, 0.5);
  position: fixed;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
.modal-frame {
  position: absolute;
  top: 10%;
  left: 20%;
  border: 1px solid #333;
  background: #ddd;
  height: 200px;
  width: 200px;
.modal-title {
  position: absolute;
  top: 0;
  width: 100%;
  text-align: center;
  border-bottom: 2px solid black;
.modal-body {
  margin-top: 40px;
  padding: 5px;
  overflow: scroll;

We won't win any design awards, but this will make our component look more like the modal we're used to and less like some random text on a page. Our next step is to hook the component into our page layout.

Ta-Dah! (again)

It's time to present our creation. For simplicity's sake, we're just going to stick our component on our default application controller. Open your default application template at app/templates/application.hbs and wire in your new component like so:

{{#simple-modal enabled=true title="--Simple Modal--"}}
    This is our modal - now with Ember 2.0 capabilities! (Click anywhere to dismiss this notification.)
 <h2 id="title">Welcome to Ember.js</h2>

The most important things to note here are the enabled=true setting, to ensure we see the modal at startup, and the {{#simple-modal}}...{{/simple-modal}} block syntax - you'll see errors if you forget to close that tag!

Save your work and reload your browser. Prepare to be astounded...

Looking Snazzy...

Go Dynamic Or Go Home

Congratulations, you've made your modal. If what you'd like is a dialog that appears every time the page is reloaded and then is gone until the next reload, then we're done here. That's not very useful though. Let's explore how to call and dismiss our modal at will.

First, we need to do a little plastic surgery. We'll add a button to our application template, ensure our modal is invisible until it's called, and add and identifier to the modal tag. Modify your app/templates/application.hbs like so:

{{#simple-modal enabled=false title="--Simple Modal --" id="modal-main"}}
  Modal text. Oh girl!
<h2 id="title">Welcome to Ember.js</h2>
<button {{action 'openModal' 'modal-main'}}>Open Modal Window</button>

Next, we'll add functionality to our application controller (app/controllers/application.js):

import Ember from 'ember';

export default Ember.Controller.extend({
    actions: {
        openModal: function(target) {
            var modal = this.get('comp-' + target);

The new component workflow means we're putting a lot more work on our components and less on...well, everything else. Our application controller is therefore kind of dumb. All our action is doing here is looking for a property called "comp-<some-modal-name>" on our controller and telling that property's value to execute its toggleModal function. This is roughly equivalent to "Hey, you! Do the thing!"

Our component file will be the most complex of our work. Update your app/components/simple-modal.js to match, and then we'll review:

import Ember from 'ember';
import layout from '../templates/components/simple-modal';

export default Ember.Component.extend({
    expose: function() {
        var app_controller = this.get('targetObject');
        var exposedName = "comp-" + this.get('id');
        app_controller.set(exposedName, this);
    actions: {
        toggleModal: function() {
    layout: layout

That's much heavier than was previously needed for this action, but let's take it step by step:

  • expose: With the removal of Views, Ember has given Components their own contexts. This means the component doesn't have to be a child of a controller - ideally, we're moving into a phase where components handle themselves and provide a nice separation of concerns inside our apps. We have to let the controller know who we are manually for now. We used to have Views.views[], but that's long-gone. Now, we'll create our own function called expose, to "expose" our component to its parent controller.
  • this.get('targetObject'): targetObject is a special property on Ember.Component that provides the parent of the current object. In this case, it refers to our application controller.
  • "comp-" + this.get('id'): This sets our name to be known as to "comp-<our-id-value>". This is somewhat arbitrary, so follow your heart if you prefer to use some different values. I like prefixing with comp here for component, but a common pattern is to prefix with x on component names, so you may see that in the wild.
  • app_controller.set: Set a property named after our exposedName variable to our own handle on our app controller. Now we're exposed to the world. Hope it's not too cold out.
  • .on('init'): This function is run when the modal is initialized. Each time the page loads we're calling this, so it should be good to go on every visit.

The New Flow

Let's do a quick rundown of how this component is communicating, because it's pretty different from our previous workflow.

  1. You load the page. The application controller is called. It sets up its action handler for our button. It renders its template.
  2. The first thing to render is the component. The enabled, title, and id properties are set right on the template.
  3. The expose() function is called as we initialize the component. We formulate our exposedName and paste it onto our app_controller.
  4. The component template is rendered. It's variables and handed down from the component. It's hidden initially - remember the {{#if enabled}} block?
  5. Everything's on the page. Now, when we press our button, our openModal action looks for a property on its controller with a particular name (in this case, comp-simple-modal). It asks the value of that property - a handle pointing to our component - to call its own toggleModal function.
  6. Our component gets the idea. It toggles its enabled property and re-renders, displaying itself to the world!
  7. When we click on our modal while it's visible, step 6 goes in reverse - enabled goes false and the modal disappears.

This pattern follows the Ember concept of "Data Down, Actions Up".

Odd Choices and Things to Come

There are a few things to note about this tutorial that have either already pissed you off or will confuse you when you dive deeper in the near future.

For one thing, my method of exposing our component is a little non-standard. I adapted it from this excellent tutorial, and it works well for our purposes. I chose this method because it's more explicit about the Component flow and because it lets us name our components directly in the view, but that's not great practice. Instead, the Ember docs recommend attaching your component to a global object, like App, and accessing its handler from there. You can absolutely do this if you prefer - it will save a little bit of code in your component.

The second problem with this tutorial is that I'm using a controller. Controllers, like views, are going the way of the dodo - soon to be replaced by routable components. I'm excited about the prospects of a completely component-based workflow, but sadly I haven't stayed informed on Ember the way I'd like so I'm not sure when controllers will be phased out entirely. I'll certainly run through this modal tutorial again when the need arises.

The End Again

With a little luck and a little elbow grease, you've got the same modal you had before, but on a shiny new Ember version. As always, please remember that this is just a demo - in production, you'd want something significantly more secure and with proper error handling. I sincerely hope this gets you started on your modal journey.

This code's entirely open-source, free as in beer for personal projects or commercial use.
Please remember - If I find out you used this to make one of those annoying "Enter Your Email To View This Page" pop-ups, I will personally revoke that license for just you. What will you do then, huh?

Thanks for sticking around! Questions or suggestions? @ADotMartin