The goal of this tutorial is to show how to use Drupal 8.5's new off-canvas dialog in your own Drupal modules.

The term "off-canvas" refers to the ability for a dialog to slide in from the side of the page, in addition to resizing the page so that no part of it is obstructed by the dialog. You can see the off-canvas dialog in action in this animated GIF:

Animated GIF of Drupal off-canvas dialog tutorial

This new Drupal 8.5 feature allows us to improve the content authoring and site building experience by turning Drupal outside-in. We can use the off-canvas dialog to enable the content creator or site builder to seamlessly edit content or configuration in-place, and see any changes take effect immediately. There is no need to navigate to the administrative backend to make edits. As you'll see in this tutorial, it's easy to use the off-canvas dialog in your own Drupal modules.

I use a custom album module on https://dri.es for managing my photo albums and for embedding images in my posts. With Drupal 8.5, I can now take advantage of the new off-canvas dialog to edit the title, alt-attribute and captions of my photos. As you can see in the animated GIF above, every photo gets an "Edit"-link. Clicking the "Edit"-link opens up the off-canvas dialog. This allows me to edit a photo in context, without having to go to an another page to make changes.

So how did I do that?

Step 1: Create your form, the Drupal way

Every image on https://dri.es has its own unique path:

https://dri.es/album/<album-name>/<image-name>

I can edit my images at:

https://dri.es/album/<album-name>/<image-name>/edit

For example, https://dri.es/album/niagara-on-the-lake-2017/niagara-falls-by-night-1 gives you the image of the Niagara Falls. If you have the right permissions you could edit the image at https://dri.es/album/niagara-on-the-lake-2017/niagara-falls-by-night-1/edit (you don't 😉). Because you don't have the right permissions, I'll show you a screenshot of the edit form instead:

Drupal off-canvas dialog tutorial: regular Drupal form

I created those paths (or routes), using Drupal's routing system, and I created the form using Drupal's regular Drupal form API. I'm not going to explain how to create a Drupal form in this post, but you can read more about this at the routing system documentation and the form API. Here is the code for creating the form:

<?php

namespace Drupal\album;

use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\album\Image;
use Drupal\Core\Url;

class ImageEditForm extends FormBase {

  public function getFormId() {
    return 'album_edit_image';
  }

  public function buildForm(array $form, FormStateInterface $form_state, $dir = NULL, $img = NULL) {
    $image = Image::loadImage("$dir/$img");

    $form['path'] = [
      '#type' => 'hidden',
      '#value' => $image->getUrlPath(),  // Unique ID of the image
    ];
    $form['title'] = [
      '#type' => 'textfield',
      '#title' => t('Title'),
      '#default_value' => $image->getTitle(),
    ];
    $form['alt'] = [
      '#type' => 'textfield',
      '#title' => t('Alt'),
      '#default_value' => $image->getAlt(),
    ];
    $form['caption'] = [
      '#type' => 'textarea',
      '#title' => t('Caption'),
      '#default_value' => $image->getCaption(),
    ];
    $form['submit'] = [
      '#type' => 'submit',
      '#value' => t('Save image'),
    ];

    return $form;
  }

  public function submitForm(array &$form, FormStateInterface $form_state) {
    $values = $form_state->getValues();

    $image = Image::loadImage($values['path']);
    if ($image) {
      $image->setTitle($values['title']);
      $image->setAlt($values['alt']);
      $image->setCaption($values['caption']);
      $image->save();
    }

    $form_state->setRedirectUrl(Url::fromUserInput('/album/'. $image->getUrlPath()));
  }
}

?>

Step 2: Add an edit link to my images

First, I want to overlay an "Edit"-button over my image:

Drupal off-canvas dialog tutorial: "Edit"-link

If you were to look at the HTML code, the image link uses the following <a href> tag:

<a href="https://dri.es/album/niagara-on-the-lake-2017/niagara-falls-by-night-1/edit" 
   class="edit-button">Edit</a>

Clicking the link doesn't open the off-canvas dialog yet. The class="edit-button" is used to style the button with CSS and to overlay it on top of the image.

Step 3: Opening the off-canvas dialog

Next, we have to tell Drupal to open the form in the off-canvas dialog when the "Edit"-link is clicked. To open the form in the off-canvas dialog, extend that <a href> tag to:

<a href="https://dri.es/album/niagara-on-the-lake-2017/niagara-falls-by-night-1/edit?destination=current-path"
   class="edit-button use-ajax" data-dialog-type="dialog" data-dialog-renderer="off_canvas" 
   data-dialog-options="{&quot;width&quot;:400}">Edit</a>

Some extra HTML in the <a href> tag is all it took; it took my regular Drupal form, showed it in an off-canvas dialog, and even styled it! As I wrote above, it is easy to use the off-canvas dialog in your own modules. Hopefully you'll be inspired to take advantage of this new functionality.

Drupal off-canvas dialog tutorial: open dialog

There are several things being added though, so let's break it down. First we add the a class called use-ajax:

  • use-ajax is the class that is necessary for any link including dialogs that use Drupal's Ajax API.

We also added some data-dialog-* attributes:

  • data-dialog-type="dialog" specifies that you want to open the link in a dialog. The other option you can specify is modal. Unlike a dialog, a modal dialog restricts interaction with the current page until the modal dialog is closed.
  • data-dialog-renderer="off_canvas" specifies how Drupal will actually render the dialog. If data-dialog-renderer is not specified then the dialog will rendered with Drupal's default dialog renderer, which is a pop-up dialog (similar to the modal dialog which is used by the Views module).
  • data-dialog-options="{&quot;width&quot;:400}" is optional and can be used to overwrite the default off-canvas dialog properties. In this case, I'm specifying that I want the width of the off-canvas dialog to be 400 pixels instead of the default 300 pixels. Any valid jQuery UI dialog options can be sent here.
  • ?destination=current-path specifies the page we have to navigate back to after we close the dialog. To have the form redirect to the current page a destination value must be added to the query string of the link. Redirecting the form to the current page works the same for dialog links as it does for other links to forms in Drupal. Luckily Drupal 8 provides a RedirectDestination helper service to handle this. In the example above, submitting the form would redirect you to https://dri.es/current-path.

You can create a link like the example above using a Drupal render array; it will open a form page in the off-canvas dialog and redirect the submitted form back to the current page:

$elements['link'] = [
  '#title' => 'Edit image',
  '#type' => 'link',
  '#url' => Url::fromRoute('album_image', ['album' => $album, 'image' => $image], 
    ['query' => \Drupal::service('redirect.destination')->getAsArray()])->toString();,
  '#attributes' => [
    'class' => ['use-ajax'],
    'data-dialog-type' => 'dialog',
    'data-dialog-renderer' => 'off_canvas',
    'data-dialog-options' => Json::encode(['width' => 400]),
  '#attached' => [
    'library' => [
      'core/drupal.dialog.ajax',
    ],
  ],
];

Because the dialog functionality might not be needed on every page, Drupal won't load it unless needed. We use the #attached element to tell Drupal that we want the JavaScript dialog system to be loaded for this page. It's a bit more work, but it keeps Drupal efficient.

Improving the developer experience

Applying the off-canvas dialog to my blog and writing this tutorial uncovered several opportunities to improve the developer experience. It seems unnecessary to set class' => ['use-ajax'] when data-dialog-type is set. Why do I need to specify both a data-dialog-type and a data-dialog-renderer? And why can't Drupal automatically attach core/drupal.dialog.ajax when data-dialog-type is set?

In discussing these challenges with Ted Bowman, one of the developers of the off-canvas dialog, he created an issue on Drupal.org to work on off-canvas developer experience improvements. Hopefully in a future version of Drupal, you will be able to create an off-canvas dialog link as simply as:

$link = Link::createFromRoute('Edit image', 'album_image', 
   ['album' => $album, 'image' => $image])->openInOffCanvasDialog();
$elements['link'] = $link->toRenderable();

Special thanks to Ted Bowman and Samuel Mortenson for their feedback to this blog post.

Talking about the many contributors to Drupal 8.5, a few of them shouted out on social media that they got their first patch in Drupal 8.5. They were excited but admitted it was more challenging than anticipated. It's true that contributing to Drupal can be challenging, but it is also true that it will accelerate your learning, and that you will likely feel an incredible sense of reward and excitement. And maybe best of all, through your collaboration with others, you'll forge relationships and friendships. I've been contributing to Open Source for 20 years and can tell you that that combined "passion + learning + contribution + relationships"-feeling is one of the most rewarding feelings there is.

I just updated my site to Drupal 8.5 and spent some time reading the Drupal 8.5 release notes. Seeing all the different issues and contributors in the release notes is a good reminder that many small contributions add up to big results. When we all contribute in small ways, we can make a lot of progress together.

Join more than 5,000 others and subscribe to my blog by e-mail:

I recently had the opportunity to read Tiffany Farriss' Drupal Association Retrospective. In addition to being the CEO of Palantir.net, Tiffany also served on the Drupal Association Board of Directors for nine years. In her retrospective post, Tiffany shares what the Drupal Association looked like when she joined the board in 2009, and how the Drupal Association continues to grow today.

What I really appreciate about Tiffany's retrospective is that it captures the evolution of the Drupal Association. It's easy to forget how far we've come. What started as a scrappy advisory board, with little to no funding, has matured into a nonprofit that can support and promote the mission of the Drupal project. While there is always work to be done, Tiffany's retrospective is a great testament of our community's progress.

I feel very lucky that the Drupal Association was able to benefit from Tiffany's leadership for nine years; she truly helped shape every aspect of the Drupal Association. I'm proud to have worked with Tiffany; she has been one of the most influential, talented members of our Board, and has been very generous by contributing both time and resources to the project.

Earlier today, we released Drupal 8.5.0, which ships with improved features for content authors, site builders and developers.

Content authors can benefit from enhanced media support and content moderation workflows. It is now easier to upload, manage and reuse media assets, in addition to moving content between different workflow states (e.g. draft, archived, published, etc).

Drupal 8.5.0 also ships with a Settings Tray module, which improves the experience for site builders. Under the hood, the Settings Tray module uses Drupal 8.5's new off-canvas dialog library; Drupal module developers are encouraged to start using these new features to improve the end-user experience of their modules.

It's also exciting to see additional improvements to Drupal's REST API. With every new release, Drupal continues to extend investments in being an API-first platform, which makes it easier to integrate with JavaScript frameworks, mobile applications, marketing solutions and more.

Finally, Drupal 8.5 also ships with significant improvements for Drupal 7 to Drupal 8 migration. After four years of work, 1,300+ closed issues and contributions from over 570 Drualists, the migrate system's underlying architecture in Drupal 8.5 is fully stable. With the exception of sites with multilingual content, the migration path is now considered stable. Needless to say, this is a significant milestone.

These are just a few of the major highlights. For more details about what is new in Drupal 8.5, please check out the official release announcement and the detailed release notes.

What I'm probably most excited about is the fact that the new Drupal 8 release system is starting to hit its stride. The number of people contributing to Drupal continues to grow and the number of new features scheduled for Drupal 8.6 and beyond is exciting.

In future releases, we plan to add a media library, support for remote media types like YouTube videos, support for content staging, a layout builder, JSON API support, GraphQL support, a React-based administration application and a better out-of-the-box experience for evaluators. While we have made important progress on these features, they are not yet ready for core inclusion and/or production use. The layout builder is available in Drupal 8.5 as an experimental module; you can beta test the layout builder if you are interested in trying it out.

I want to extend a special thank you to the many contributors that helped make Drupal 8.5 possible. Hundreds of people and organizations have contributed to Drupal 8.5. It can be hard to appreciate what you can't see, but behind every bugfix and new feature there are a number of people and organizations that have given their time and resources to contribute back. Thank you!