---
title: Add a Modal from a Redactor Field in Craft CMS
date: 2021-08-09T10:14:00-04:00
author: cc_admin
canonical_url: "https://caffeinecreations.ca/blog/add-a-modal-from-a-redactor-field-in-craft-cms/"
section: Blog
---
![Craftcms](https://caffeinecreations.ca/uploads/blog/_1920x660_crop_center-center_none_ns/craftcms.jpg)

- [Code](https://caffeinecreations.ca/blog/category/code/), [Tutorial](https://caffeinecreations.ca/blog/category/code/tutorial/), [CraftCMS](https://caffeinecreations.ca/blog/category/craftcms/), [Craft Tips](https://caffeinecreations.ca/blog/category/craftcms/craft-tips/)

# Add a Modal from a Redactor Field in Craft CMS

I had a client request that they be able to add a modal pop-up to content with a form from their CRM within a redactor field. There is no out of the box way to do this, but it's not difficult.

I did this by using the `formattingAdd` option in the redactor Config file, using the Retcon plugin to add Alpine Js Attributes to the pop-up trigger text and a new field to hold the pop-up content.

In the redactor config file add the following to formattingAdd which will then create an a link with a class of open-popup. I wanted to use a span, however on saving the trigger text blends in with the regular text even when using the style attribute below.

```
<button class="absolute z-10 flex items-center justify-center w-8 h-8 -translate-y-1/2  -right-4 -top-4" clipboard="" title="Copy to Clipboard" to="" type="button" x-clipboard.raw=""Form Pop-up": {
          "title": "Form Pop-up",
          "api": "module.inline.format",
          "args": {
              "tag": "a",
              "class": "open-popup",
              "type": "toggle",
              "style": {
                "color":"blue"
              }
          }
      }," x-data="">
	<svg class="h-5 w-5" viewbox="0 0 64 64" xml:space="preserve" xmlns="http://www.w3.org/2000/svg">
  <rect fill="#f3f4f6" height="53" rx="3" width="41" x="7" y="2"></rect>
  <rect fill="#f3f4f6" height="51" rx="3" width="39" x="19" y="11"></rect>
  <path d="M53.98 9.143h-3.97c-.082 0-.155.028-.232.047V5.023C49.778 2.253 47.473 0 44.64 0H10.217C7.384 0 5.08 2.253 5.08 5.023v46.843c0 2.77 2.305 5.023 5.138 5.023h6.037v2.268c0 2.67 2.216 4.843 4.941 4.843H53.98c2.725 0 4.942-2.173 4.942-4.843v-45.17c0-2.671-2.217-4.844-4.942-4.844zM7.11 51.866V5.023c0-1.649 1.394-2.991 3.106-2.991H44.64c1.712 0 3.106 1.342 3.106 2.99v46.844c0 1.649-1.394 2.991-3.106 2.991H10.217c-1.712 0-3.106-1.342-3.106-2.99zm49.778 7.29c0 1.551-1.306 2.812-2.91 2.812H21.195c-1.604 0-2.91-1.26-2.91-2.811v-2.268H44.64c2.833 0 5.138-2.253 5.138-5.023V11.128c.077.018.15.047.233.047h3.968c1.604 0 2.91 1.26 2.91 2.811v45.17z"></path>
  <path d="M38.603 13.206H16.254a1.015 1.015 0 1 0 0 2.032h22.35a1.015 1.015 0 1 0 0-2.032zM38.603 21.333H16.254a1.015 1.015 0 1 0 0 2.032h22.35a1.015 1.015 0 1 0 0-2.032zM38.603 29.46H16.254a1.015 1.015 0 1 0 0 2.032h22.35a1.015 1.015 0 1 0 0-2.032zM28.444 37.587h-12.19a1.015 1.015 0 1 0 0 2.032h12.19a1.015 1.015 0 1 0 0-2.032z"></path>
</svg>
<div class="sr-only">Copy to clipboard</div></button>```javascript
"Form Pop-up": {
          "title": "Form Pop-up",
          "api": "module.inline.format",
          "args": {
              "tag": "a",
              "class": "open-popup",
              "type": "toggle",
              "style": {
                "color":"blue"
              }
          }
      },
```
```

In order to get the trigger text to open the modal I needed to add some Alpine Js directives which I was unable to get to work with the redactor config above. Instead I used the [Retcon plugin](https://plugins.craftcms.com/retcon) which I am already using on this site.

Additionally the rich text field and pop-up code need to be wrapped in a div with these alpine js `attributes x-data="{ 'isPopupOpen': false }" @keydown.escape="isPopupOpen = false"` To get the alpine directives added use this code and replace` block.copy` with the name of your redactor field.

On thing to note is that the Retcon plugin does not like the @ character which means that `@click` will create errors. In this case just use the longer option in Alpine `x-on:`

```
<button class="absolute z-10 flex items-center justify-center w-8 h-8 -translate-y-1/2  -right-4 -top-4" clipboard="" title="Copy to Clipboard" to="" type="button" x-clipboard.raw="{{ block.copy | retcon([
        ['attr', 'h2 + h3', { class: 'h3-big' }, false],
        ['attr', 'span.open-popup', { class: 'text-blueBrand-dark cursor-pointer font-bold', 'x-on:click':'isPopupOpen = true' }, false],
      ]) }}" x-data="">
	<svg class="h-5 w-5" viewbox="0 0 64 64" xml:space="preserve" xmlns="http://www.w3.org/2000/svg">
  <rect fill="#f3f4f6" height="53" rx="3" width="41" x="7" y="2"></rect>
  <rect fill="#f3f4f6" height="51" rx="3" width="39" x="19" y="11"></rect>
  <path d="M53.98 9.143h-3.97c-.082 0-.155.028-.232.047V5.023C49.778 2.253 47.473 0 44.64 0H10.217C7.384 0 5.08 2.253 5.08 5.023v46.843c0 2.77 2.305 5.023 5.138 5.023h6.037v2.268c0 2.67 2.216 4.843 4.941 4.843H53.98c2.725 0 4.942-2.173 4.942-4.843v-45.17c0-2.671-2.217-4.844-4.942-4.844zM7.11 51.866V5.023c0-1.649 1.394-2.991 3.106-2.991H44.64c1.712 0 3.106 1.342 3.106 2.99v46.844c0 1.649-1.394 2.991-3.106 2.991H10.217c-1.712 0-3.106-1.342-3.106-2.99zm49.778 7.29c0 1.551-1.306 2.812-2.91 2.812H21.195c-1.604 0-2.91-1.26-2.91-2.811v-2.268H44.64c2.833 0 5.138-2.253 5.138-5.023V11.128c.077.018.15.047.233.047h3.968c1.604 0 2.91 1.26 2.91 2.811v45.17z"></path>
  <path d="M38.603 13.206H16.254a1.015 1.015 0 1 0 0 2.032h22.35a1.015 1.015 0 1 0 0-2.032zM38.603 21.333H16.254a1.015 1.015 0 1 0 0 2.032h22.35a1.015 1.015 0 1 0 0-2.032zM38.603 29.46H16.254a1.015 1.015 0 1 0 0 2.032h22.35a1.015 1.015 0 1 0 0-2.032zM28.444 37.587h-12.19a1.015 1.015 0 1 0 0 2.032h12.19a1.015 1.015 0 1 0 0-2.032z"></path>
</svg>
<div class="sr-only">Copy to clipboard</div></button>```twig
{{ block.copy | retcon([
        ['attr', 'h2 + h3', { class: 'h3-big' }, false],
        ['attr', 'span.open-popup', { class: 'text-blueBrand-dark cursor-pointer font-bold', 'x-on:click':'isPopupOpen = true' }, false],
      ]) }}
```
```

Next I added a field for the pop-up content to be entered. For my client this is a form that is created in their CRM. and then place that code in the template.

```
<button class="absolute z-10 flex items-center justify-center w-8 h-8 -translate-y-1/2  -right-4 -top-4" clipboard="" title="Copy to Clipboard" to="" type="button" x-clipboard.raw="{# check if popup is in use #}
  {% if block.popUp is defined and block.popUp|length %}
    <!-- overlay -->
    <div
        class="overflow-auto bg-black bg-opacity-50 h-screen w-screen top-0 left-0"
        x-show="isPopupOpen"
        x-cloak
        :class="{ 'fixed inset-0 z-10 flex items-center justify-center': isPopupOpen }">

        <!-- dialog -->
        <div
            class="bg-white shadow-2xl m-4 sm:m-8 p-8 pt-4 sm:w-5/6 md:w-auto md:max-w-2/3 w-full mx-4 md:mx-8 relative"
            x-show="isPopupOpen"
            @click.away="isPopupOpen = false"
        >

            <button type="button" @click="isPopupOpen = false" class="absolute top-0 right-0 mr-4 mt-4">✖</button>

            <div class="w-full flex flex-row justify-center">
              {#
                use retcon to add an alpine directive 'x-on:click'
                to close the mobile on submit
              #}
              {{ block.popUp|raw| retcon([
                      ['attr', 'input[type="submit"]', { class: '', 'x-on:click': 'isPopupOpen = false' }, false]
              ]) }}
            </div>
        </div><!-- /dialog -->

    </div>
    <!-- end overlay -->
  {% endif %}" x-data="">
	<svg class="h-5 w-5" viewbox="0 0 64 64" xml:space="preserve" xmlns="http://www.w3.org/2000/svg">
  <rect fill="#f3f4f6" height="53" rx="3" width="41" x="7" y="2"></rect>
  <rect fill="#f3f4f6" height="51" rx="3" width="39" x="19" y="11"></rect>
  <path d="M53.98 9.143h-3.97c-.082 0-.155.028-.232.047V5.023C49.778 2.253 47.473 0 44.64 0H10.217C7.384 0 5.08 2.253 5.08 5.023v46.843c0 2.77 2.305 5.023 5.138 5.023h6.037v2.268c0 2.67 2.216 4.843 4.941 4.843H53.98c2.725 0 4.942-2.173 4.942-4.843v-45.17c0-2.671-2.217-4.844-4.942-4.844zM7.11 51.866V5.023c0-1.649 1.394-2.991 3.106-2.991H44.64c1.712 0 3.106 1.342 3.106 2.99v46.844c0 1.649-1.394 2.991-3.106 2.991H10.217c-1.712 0-3.106-1.342-3.106-2.99zm49.778 7.29c0 1.551-1.306 2.812-2.91 2.812H21.195c-1.604 0-2.91-1.26-2.91-2.811v-2.268H44.64c2.833 0 5.138-2.253 5.138-5.023V11.128c.077.018.15.047.233.047h3.968c1.604 0 2.91 1.26 2.91 2.811v45.17z"></path>
  <path d="M38.603 13.206H16.254a1.015 1.015 0 1 0 0 2.032h22.35a1.015 1.015 0 1 0 0-2.032zM38.603 21.333H16.254a1.015 1.015 0 1 0 0 2.032h22.35a1.015 1.015 0 1 0 0-2.032zM38.603 29.46H16.254a1.015 1.015 0 1 0 0 2.032h22.35a1.015 1.015 0 1 0 0-2.032zM28.444 37.587h-12.19a1.015 1.015 0 1 0 0 2.032h12.19a1.015 1.015 0 1 0 0-2.032z"></path>
</svg>
<div class="sr-only">Copy to clipboard</div></button>```twig
{# check if popup is in use #}
  {% if block.popUp is defined and block.popUp|length %}
    <!-- overlay -->
    <div
        class="overflow-auto bg-black bg-opacity-50 h-screen w-screen top-0 left-0"
        x-show="isPopupOpen"
        x-cloak
        :class="{ 'fixed inset-0 z-10 flex items-center justify-center': isPopupOpen }">

        <!-- dialog -->
        <div
            class="bg-white shadow-2xl m-4 sm:m-8 p-8 pt-4 sm:w-5/6 md:w-auto md:max-w-2/3 w-full mx-4 md:mx-8 relative"
            x-show="isPopupOpen"
            @click.away="isPopupOpen = false"
        >

            <button type="button" @click="isPopupOpen = false" class="absolute top-0 right-0 mr-4 mt-4">✖</button>

            <div class="w-full flex flex-row justify-center">
              {#
                use retcon to add an alpine directive 'x-on:click'
                to close the mobile on submit
              #}
              {{ block.popUp|raw| retcon([
                      ['attr', 'input[type="submit"]', { class: '', 'x-on:click': 'isPopupOpen = false' }, false]
              ]) }}
            </div>
        </div><!-- /dialog -->

    </div>
    <!-- end overlay -->
  {% endif %}
```
```

The full code for this matrix block is in this [text file](https://caffeinecreations.ca/uploads/blog/redactor-popup.txt).

### Video Demo

## Related Articles

[![Reactive Pagination With Sprig and Craft Thumbnail](https://caffeinecreations.ca/uploads/blog/_680x320_crop_center-center_65_none_ns/sprig-hero.jpg)### Reactive Pagination With Sprig and Craft](https://caffeinecreations.ca/blog/reactive-pagination-with-sprig-and-craft/)

[![Creating a Simple Job Board in Craft CMS Thumbnail](https://caffeinecreations.ca/uploads/hero/_680x320_crop_center-center_65_none_ns/job-board-hero.jpg)### Creating a Simple Job Board in Craft CMS](https://caffeinecreations.ca/blog/creating-a-simple-job-board-in-craft-cms/)

[![Grouping Entries by First Letter of Last Name Thumbnail](https://caffeinecreations.ca/uploads/blog/_680x320_crop_center-center_65_none_ns/alphabet.jpg)### Grouping Entries by First Letter of Last Name](https://caffeinecreations.ca/blog/grouping-entries-by-first-letter-of-last-name/)
