ExpressionEngine Docs

CP/Modal Service

The Modal service organizes various modal views for presentation upon a trigger you specify.

Simple example

Let’s say we want to create a modal that says “Hello, world!”. First, we need to construct the markup that displays the modal. We’ll then just use our shared modal view and pass in our content so we don’t have to worry about maintaining markup:

$modal_vars = array(
  'name' => 'hello',
  'contents' => '<p>Hello, world!</p>'
$modal_html = ee('View')->make('ee:_shared/modal')->render($modal_vars);

We had to specify two view variables: name and contents. name is just a unique identifier for the modal, we’ll reference this later when we decide to show it. contents is the HTML content for the modal.

Great, we’ve got our modal markup, let’s hand it off to the Modal service:

ee('CP/Modal')->addModal('hello', $modal_html);

Now, the modal will be present in our page’s DOM next time we load it, but will be hidden. How do we show it? A simple way is a link that looks like this:

<a href="" class="m-link" rel="hello">Say hello</a>

What makes this link special is the m-link class, and then the following rel= attribute where we specify the unique name of our modal we created earlier. If we click the link, and we should see our modal!

Delete confirmation modals

Probably the most common use case for a modal is a delete confirmation modal. There are two kinds of deletion in the CP: clicking a delete link next to the item to start the deletion process (common in folder lists in the sidebar), and bulk deletion, mostly-commonly used with a table UI where the user can select multiple items from a table, select “Remove” in the bulk action selector, then click “Submit” to display the modal. We’ll cover how to do each.

Single item deletion

Our code will look similar to our simple example, except we’ll set up a placeholder hidden input for the content ID we’ll be deleting, and we’ll use another shared view file specifically for delete confirmations:

$modal_vars = array(
  'name'    => 'modal-confirm-remove',
  'form_url'  => ee('CP/URL')->make('addons/myaddon/remove'),
  'hidden'  => array(
    'content_id' => ''
$modal_html = ee('View')->make('ee:_shared/modal_confirm_remove')->render($modal_vars);
ee('CP/Modal')->addModal('remove', $modal_html);

Constructing our link to display the modal will require a little bit more data than before, because we may have more than one delete link on a page, and we want our modal to say what is about to be deleted. Here’s what our delete link will look like:

<a class="m-link"
   data-confirm="Content Item: <b>My Entry</b>"

Warning: The m-link class is essential. You can add other classes to your link, but you must have the m-link class for the modal to work properly.

Finally, we need some JavaScript to tie it all together. We want to accomplish two goals: show the name of the item being deleted, and pass along relevant data to the form inside the modal so that our controller code knows which item is being deleted:

$(document).ready(function () {
  $('a.m-link').click(function (e) {
    var modalIs = $('.' + $(this).attr('rel'));

    $('.checklist', modalIs)
      .html('') // Reset it
      .append('<li>' + $(this).data('confirm') + '</li>');
    $('input[name="content_id"]', modalIs).val($(this).data('content_id'));


With that, when we click our link, a modal should appear asking us to confirm we want to delete “My Entry”, and when we submit the form, it will POST to our specified form_url with the content_id we passed along.

Bulk item deletion

Bulk item deletion is assumed to be used with a table listing of content. Since that’s how it’s consistently used in ExpressionEngine’s interface, these instructions will be based in that context. Our modal markup generation will look similar to our previous example, except we don’t need to define any hidden inputs:

$modal_vars = array(
  'name'    => 'modal-confirm-remove',
  'form_url'  => ee('CP/URL')->make('addons/myaddon/remove')
$modal_html = ee('View')->make('ee:_shared/modal_confirm_remove')->render($modal_vars);
ee('CP/Modal')->addModal('remove', $modal_html);

Generating table listings is easiest with the CP/Table Service, so we’ll use that and add a column of type Table::COL_CHECKBOX so that users can select data they want to delete. Defining that column will look like this for us:

$columns[] = array(
  'name' => 'content_ids[]',
  'value' => $content->getId(),
  'data'  => array(
    'confirm' => lang('content') . ': <b>' . htmlentities($content->title, ENT_QUOTES, 'UTF-8') . '</b>'

We give the checkboxes an input name of content_ids[], which will then carry over to the modal automatically, so that when we submit the form in our modal, the $_POST key we’ll grab the content IDs from will be content_ids. But we need JavaScript to facilitate this for us, and luckily, it’s already written. Just include this in your controller:

  'file' => array('cp/confirm_remove'),

Finally, we need to create our Bulk Action Controls with some special data attributes that know when to trigger the modal. You can embed shared view in your own view file to do that:

  <?php $this->embed('ee:_shared/form/bulk-action-bar', [
    'options' => [
        'value' => "",
        'text' => '-- ' . lang('with_selected') . ' --'
        'value' => "remove",
        'text' => lang('delete'),
        'attrs' => ' data-confirm-trigger="selected" rel="modal-confirm-remove"'
    'modal' => true
  ]); ?>

Now when a user selects some content in the table, the bulk action controls should appear, and when “Remove” is selected and submitted, a modal will appear showing a list of content about to be deleted, where they can then confirm the deletion and your POST handler will be fired.

CP/Modal Service Methods

class ExpressionEngine\Service\Modal\ModalCollection

addModal($name, $data)

Adds a named modal to the collection

Parameter Type Description
$name String The name of the modal
$data String The contents of the modal
Returns ModalCollection $this


This will start a new modal overwriting any previously defined modal of the same name.

Parameter Type Description
$name String The name of the modal
Returns Void


Ends the modal adding the modal to the collection based on the most recently specified name via startModal.

Parameter Type Description
Returns Void


Gets a named modal from the collection

Parameter Type Description
$name String The name of the modal
Returns Mixed The data stored for the named modal


Gets all the modals stored in this collection

Parameter Type Description
Returns Array An array of stored modal data