Modal

Sage modal


React Component

Example Modal

Example Subheader

Example Popover Title

Popover content

Page 2 of 5

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

Example Modal

Example Subheader

Example Popover Title

Popover content

Page 2 of 5

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse urna leo, condimentum nec pellentesque finibus, ultricies pulvinar ante. Donec eu interdum ligula. Pellentesque aliquam ullamcorper orci, nec tempor libero tristique in. Aliquam vitae felis at leo condimentum placerat eget id libero. In dictum tortor ac accumsan aliquam. Donec sit amet tortor porttitor, tincidunt nisl at, egestas lacus. Integer metus augue, aliquet accumsan vulputate eget, tristique id erat. Donec a venenatis nibh, ac molestie risus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Vivamus in orci vitae ex tempor ultrices in a leo. Sed purus magna, vulputate aliquet ligula eget, consectetur sagittis nunc.

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse urna leo, condimentum nec pellentesque finibus, ultricies pulvinar ante. Donec eu interdum ligula. Pellentesque aliquam ullamcorper orci, nec tempor libero tristique in. Aliquam vitae felis at leo condimentum placerat eget id libero. In dictum tortor ac accumsan aliquam. Donec sit amet tortor porttitor, tincidunt nisl at, egestas lacus. Integer metus augue, aliquet accumsan vulputate eget, tristique id erat. Donec a venenatis nibh, ac molestie risus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Vivamus in orci vitae ex tempor ultrices in a leo. Sed purus magna, vulputate aliquet ligula eget, consectetur sagittis nunc.

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse urna leo, condimentum nec pellentesque finibus, ultricies pulvinar ante. Donec eu interdum ligula. Pellentesque aliquam ullamcorper orci, nec tempor libero tristique in. Aliquam vitae felis at leo condimentum placerat eget id libero. In dictum tortor ac accumsan aliquam. Donec sit amet tortor porttitor, tincidunt nisl at, egestas lacus. Integer metus augue, aliquet accumsan vulputate eget, tristique id erat. Donec a venenatis nibh, ac molestie risus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Vivamus in orci vitae ex tempor ultrices in a leo. Sed purus magna, vulputate aliquet ligula eget, consectetur sagittis nunc.

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse urna leo, condimentum nec pellentesque finibus, ultricies pulvinar ante. Donec eu interdum ligula. Pellentesque aliquam ullamcorper orci, nec tempor libero tristique in. Aliquam vitae felis at leo condimentum placerat eget id libero. In dictum tortor ac accumsan aliquam. Donec sit amet tortor porttitor, tincidunt nisl at, egestas lacus. Integer metus augue, aliquet accumsan vulputate eget, tristique id erat. Donec a venenatis nibh, ac molestie risus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Vivamus in orci vitae ex tempor ultrices in a leo. Sed purus magna, vulputate aliquet ligula eget, consectetur sagittis nunc.

Example Modal

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

Example Modal

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

Example Modal

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

Example Large Modal

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

Example Spaced Modal

Lorem ipsum dolor sit amet

Consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

Example Modal

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

Example Modal

Reached limit: 44% progress

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

Animated

Example Modal

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

Example Modal

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

Example Modal

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

Example Modal

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

Asyncronous Modals

There are a number of situations where it might be most practical to load content for a modal asyncronously. For example, in a list of products, each product may allow an option to edit that product's details in a modal. In this case you may have a route that delivers only the contents of the modal that can be called asyncronously when the modal trigger is clicked.

Set this up as follows:

  1. Ensure that you have at least one modal stub in your view using SageModal and be sure to provide an id for it along with any other configurations. As best practices consider:
    • Use the remove_content_on_close: true to ensure that any asynchronous content is removed from the modal when it is closed.
    • You can provide default content (typically inside of a SageModalContent nested within the SageModal stub) such as a SageLoader inside this modal stub. This will be replaced by the asynchronous content once it loads and be put back when the content unloads.
  2. Ensure you have an endpoint that delivers only the content of the modal, typically wrapped by the SageModalContent component.
  3. In the primary view, add hyperlinks, buttons, or other clickable triggers. On such triggers use the following:
    • data-js-modaltrigger="[modal-id]" where modal-id is the id you placed on the corresponding SageModal stub.
    • data-js-remote-url="[url]" where url is the edpoint that delivers the content.

Note as well that you can set up remote_url's on both the main SageModal stub and on triggers. In such cases, the remote_url from the triggers overrides the one on the modal stub; but if no remote_url is provided from the trigger, the one on the modal itself is used. As shown elsewhere on this page default content (such as SageLoader) can also be manually populated inside the SageModal that is then replaced by asynchronous remote_url content.

Loading...

Events (monitor in browser console)

Use these events for hooking into modal functionality using JS event listeners.

Event name Event type Description

sage.modal.active

global

Fires when any modal has been opened

sage.modal.closeAll

global

Fires when any modal has been closed

sage.modal.opening

instance Fires immediately when a modal has been opened

sage.modal.open

instance

Fires after a modal has loaded. If animate is enabled, this event will run upon completion of the modal's animation. Otherwise, this event will run immediately along with sage.modal.opening.

Example 'Active' Event Modal

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

Example 'Open' Event Modal

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

Example 'Opening' Event Modal

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

Example 'CloseAll' Event Modal

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

Sage Component

SageModal
<%
  sample_body_text = "<p class='#{SageClassnames::TYPE::BODY}'>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>".html_safe

  long_sample_text = "<p class=' #{SageClassnames::TYPE::BODY}'>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse urna leo, condimentum nec pellentesque finibus, ultricies pulvinar ante. Donec eu interdum ligula. Pellentesque aliquam ullamcorper orci, nec tempor libero tristique in. Aliquam vitae felis at leo condimentum placerat eget id libero. In dictum tortor ac accumsan aliquam. Donec sit amet tortor porttitor, tincidunt nisl at, egestas lacus. Integer metus augue, aliquet accumsan vulputate eget, tristique id erat. Donec a venenatis nibh, ac molestie risus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Vivamus in orci vitae ex tempor ultrices in a leo. Sed purus magna, vulputate aliquet ligula eget, consectetur sagittis nunc.</p>".html_safe
%>
<%= sage_component SagePanelBlock, {} do %>
  <%= sage_component SageButtonGroup, { wrap: true, gap: :sm, spacer: { bottom: :sm }} do %>
    <%= sage_component SageButton, {
      style: "primary",
      icon: { name: "launch", style: "right" },
      value: "Modal",
      attributes: {
        "data-js-modaltrigger": "cool-modal",
      }
    } %>
    <%= sage_component SageButton, {
      style: "primary",
      icon: { name: "launch", style: "right" },
      value: "Modal with Content Scrolling",
      attributes: {
        "data-js-modaltrigger": "cool-modal-scrolling",
      }
    } %>
    <%= sage_component SageButton, {
      style: "primary",
      icon: { name: "launch", style: "right" },
      value: "Modal with Header Image",
      attributes: {
        "data-js-modaltrigger": "cool-modal-header-image",
      }
    } %>
    <%= sage_component SageButton, {
      style: "primary",
      icon: { name: "launch", style: "right" },
      value: "Modal with Header Icon",
      attributes: {
        "data-js-modaltrigger": "cool-modal-header-icon",
      }
    } %>
    <%= sage_component SageButton, {
      style: "primary",
      icon: { name: "launch", style: "right" },
      value: "Large Modal (removed)",
      attributes: {
        "data-js-modaltrigger": "cool-modal-large",
      }
    } %>
    <%= sage_component SageButton, {
      style: "primary",
      icon: { name: "launch", style: "right" },
      value: "Modal with Size Option",
      attributes: {
        "data-js-modaltrigger": "cool-modal-size-option",
      }
    } %>
    <%= sage_component SageButton, {
      style: "primary",
      icon: { name: "launch", style: "right" },
      value: "Spaced Modal",
      attributes: {
        "data-js-modaltrigger": "cool-modal-spaced",
      }
    } %>
    <%= sage_component SageButton, {
      style: "primary",
      icon: { name: "launch", style: "right" },
      value: "Fullscreen Modal",
      attributes: {
        "data-js-modaltrigger": "cool-modal-fullscreen",
      }
    } %>
    <%= sage_component SageButton, {
      style: "primary",
      icon: { name: "launch", style: "right" },
      value: "Fullscreen Modal with Header Actions",
      attributes: {
        "data-js-modaltrigger": "cool-modal-fullscreen-header-actions",
      }
    } %>
  <% end %>

  <%# Standard Modal %>
  <%= sage_component SageModal, { id: "cool-modal" } do %>
    <%= sage_component SageModalContent, {
      title: "Example Modal",
      subheader: "Example Subheader",
      help_content: "<p>Popover content</p>",
      help_title: "Example Popover Title",
      help_link: {
        href: "#",
        name: "Learn more about modals"
      }
    } do %>
      <% content_for :sage_header_aside do %>
        <%= sage_component SageButton, {
          style: "secondary",
          subtle: true,
          value: "Close Modal",
          icon: { name: "remove", style: "only" },
          attributes: { "data-js-modal": true }
        } %>
      <% end %>

      <% content_for :sage_header_indicator do %>
        <%= sage_component SageIndicator, {
          current_item: 2,
          label: "Page",
          num_items: 5,
          show_text: true
        } %>
      <% end %>

      <%= sample_body_text %>

      <%= sample_body_text %>

      <% content_for :sage_footer do %>
        <% content_for :sage_footer_aside do %>
          <%= sage_component SageButton, {
            style: "secondary",
            subtle: true,
            value: "Close Modal",
            attributes: { "data-js-modal": true }
          } %>
        <% end %>
        <%= sage_component SageButton, {
          style: "secondary",
          icon: { name: "check", style: "left" },
          value: "Take An Action",
        } %>
        <%= sage_component SageButton, {
          style: "primary",
          icon: { name: "check", style: "left" },
          value: "Take An Action",
        } %>
      <% end %>
    <% end %>
  <% end %>

  <%# Standard Modal with Scrolling %>
  <%= sage_component SageModal, { allow_scroll: true, id: "cool-modal-scrolling" } do %>
    <%= sage_component SageModalContent, {
      title: "Example Modal",
      subheader: "Example Subheader",
      help_content: "<p>Popover content</p>",
      help_title: "Example Popover Title",
      help_link: {
        href: "#",
        name: "Learn more about modals"
      }
    } do %>
      <% content_for :sage_header_aside do %>
        <%= sage_component SageButton, {
          style: "secondary",
          subtle: true,
          value: "Close Modal",
          icon: { name: "remove", style: "only" },
          attributes: { "data-js-modal": true }
        } %>
      <% end %>

      <% content_for :sage_header_indicator do %>
        <%= sage_component SageIndicator, {
          current_item: 2,
          label: "Page",
          num_items: 5,
          show_text: true
        } %>
      <% end %>

      <%= long_sample_text %>
      <%= long_sample_text %>
      <%= long_sample_text %>
      <%= long_sample_text %>

      <% content_for :sage_footer do %>
        <% content_for :sage_footer_aside do %>
          <%= sage_component SageButton, {
            style: "secondary",
            subtle: true,
            value: "Close Modal",
            attributes: { "data-js-modal": true }
          } %>
        <% end %>
        <%= sage_component SageButton, {
          style: "secondary",
          icon: { name: "check", style: "left" },
          value: "Take An Action",
        } %>
        <%= sage_component SageButton, {
          style: "primary",
          icon: { name: "check", style: "left" },
          value: "Take An Action",
        } %>
      <% end %>
    <% end %>
  <% end %>

  <%# Standard Modal with Header Image %>
  <%= sage_component SageModal, { id: "cool-modal-header-image" } do %>
    <%= sage_component SageModalContent, {
      header_image: "card-placeholder-sm.png",
      title: "Example Modal"
    } do %>
      <% content_for :sage_header_aside do %>
        <%= sage_component SageButton, {
          style: "secondary",
          subtle: true,
          value: "Close Modal",
          icon: { name: "remove", style: "only" },
          attributes: { "data-js-modal": true }
        } %>
      <% end %>

      <%= sample_body_text %>

      <% content_for :sage_footer do %>
        <% content_for :sage_footer_aside do %>
          <%= sage_component SageButton, {
            style: "secondary",
            subtle: true,
            value: "Close Modal",
            attributes: { "data-js-modal": true }
          } %>
        <% end %>
        <%= sage_component SageButton, {
          style: "primary",
          icon: { name: "check", style: "left" },
          value: "Take An Action",
        } %>
      <% end %>
    <% end %>
  <% end %>

  <%# Standard Modal with Header Icon %>
  <%= sage_component SageModal, { id: "cool-modal-header-icon" } do %>
    <%= sage_component SageModalContent, {
      header_icon: {
        name: "danger",
        color: "red"
      },
      title: "Example Modal"
    } do %>
      <% content_for :sage_header_aside do %>
        <%= sage_component SageButton, {
          style: "secondary",
          subtle: true,
          value: "Close Modal",
          icon: { name: "remove", style: "only" },
          attributes: { "data-js-modal": true }
        } %>
      <% end %>

      <%= sample_body_text %>

      <% content_for :sage_footer do %>
        <% content_for :sage_footer_aside do %>
          <%= sage_component SageButton, {
            style: "secondary",
            subtle: true,
            value: "Close Modal",
            attributes: { "data-js-modal": true }
          } %>
        <% end %>
        <%= sage_component SageButton, {
          style: "primary",
          icon: { name: "check", style: "left" },
          value: "Take An Action",
        } %>
      <% end %>
    <% end %>
  <% end %>

  <%# Standard Modal with Size Option %>
  <%= sage_component SageModal, { id: "cool-modal-size-option", size: "full" } do %>
    <%= sage_component SageModalContent, {
      title: "Example Modal"
    } do %>
      <% content_for :sage_header_aside do %>
        <%= sage_component SageButton, {
          style: "secondary",
          subtle: true,
          value: "Close Modal",
          icon: { name: "remove", style: "only" },
          attributes: { "data-js-modal": true }
        } %>
      <% end %>

      <%= sample_body_text %>

      <% content_for :sage_footer do %>
        <% content_for :sage_footer_aside do %>
          <%= sage_component SageButton, {
            style: "secondary",
            subtle: true,
            value: "Close Modal",
            attributes: { "data-js-modal": true }
          } %>
        <% end %>
        <%= sage_component SageButton, {
          style: "primary",
          icon: { name: "check", style: "left" },
          value: "Take An Action",
        } %>
      <% end %>
    <% end %>
  <% end %>
  <%# Large Modal %>
  <%= sage_component SageModal, {
    id: "cool-modal-large",
    large: true,
    remove_content_on_close: true
  } do %>
    <%= sage_component SageModalContent, { title: "Example Large Modal" } do %>
      <% content_for :sage_header_aside do %>
        <%= sage_component SageButton, {
          style: "secondary",
          subtle: true,
          value: "Close Modal",
          icon: { name: "remove", style: "only" },
          attributes: { "data-js-modal": true }
        } %>
      <% end %>

      <%= sample_body_text %>

      <% content_for :sage_footer do %>
        <% content_for :sage_footer_aside do %>
          <%= sage_component SageButton, {
            style: "secondary",
            subtle: true,
            value: "Close Modal",
            attributes: { "data-js-modal": true }
          } %>
        <% end %>
        <%= sage_component SageButton, {
          style: "primary",
          icon: { name: "check", style: "left" },
          value: "Take An Action",
        } %>
      <% end %>
    <% end %>
  <% end %>

  <%# Spaced Modal %>
  <%= sage_component SageModal, {
    id: "cool-modal-spaced",
    large: true
  } do %>
    <%= sage_component SageModalContent, {
      title: "Example Spaced Modal",
      gap: "lg",
      spacing: "panel",
    } do %>
      <% content_for :sage_header_aside do %>
        <%= sage_component SageButton, {
          style: "secondary",
          subtle: true,
          value: "Close Modal",
          icon: { name: "remove", style: "only" },
          attributes: { "data-js-modal": true }
        } %>
      <% end %>

      <%= sage_component SagePanelBlock, {} do %>
        <h4 class="<%= SageClassnames::TYPE::HEADING_5 %>">Lorem ipsum dolor sit amet</h4>
        <p class="<%= SageClassnames::TYPE::BODY %>">
          Consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
        </p>
      <% end %>

      <%= sage_component SagePanelTiles, { tiles_in_row: 2 } do %>
        <%= sage_component SageCard, {} do %>
          <p class="<%= SageClassnames::TYPE::BODY %>">
            Lorem ipsum dolor sit amet, consectetur adipiscing elit.
          </p>
        <% end %>
        <%= sage_component SageCard, {} do %>
          <p class="<%= SageClassnames::TYPE::BODY %>">
            Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
          </p>
        <% end %>
      <% end %>

      <% content_for :sage_footer do %>
        <% content_for :sage_footer_aside do %>
          <%= sage_component SageButton, {
            style: "secondary",
            subtle: true,
            value: "Close Modal",
            attributes: { "data-js-modal": true }
          } %>
        <% end %>
        <%= sage_component SageButton, {
          style: "primary",
          icon: { name: "check", style: "left" },
          value: "Take An Action",
        } %>
      <% end %>
    <% end %>
  <% end %>

  <%# Fullscreen Modal %>
  <%= sage_component SageModal, {
    id: "cool-modal-fullscreen",
    fullscreen: true
  } do %>
    <%= sage_component SageModalContent, {
      title: "Example Modal"
    } do %>
      <% content_for :sage_header_aside do %>
        <%= sage_component SageButton, {
          style: "secondary",
          subtle: true,
          value: "Close Modal",
          icon: { name: "remove", style: "only" },
          attributes: { "data-js-modal": true }
        } %>
      <% end %>

      <%= sample_body_text %>

      <% content_for :sage_footer do %>
        <% content_for :sage_footer_aside do %>
          <%= sage_component SageButton, {
            style: "secondary",
            subtle: true,
            value: "Close Modal",
            attributes: { "data-js-modal": true }
          } %>
        <% end %>
        <%= sage_component SageButton, {
          style: "primary",
          icon: { name: "check", style: "left" },
          value: "Take An Action",
        } %>
      <% end %>
    <% end %>
  <% end %>

  <%# Fullscreen Modal with Header Actions %>
  <%= sage_component SageModal, {
    id: "cool-modal-fullscreen-header-actions",
    fullscreen: true
  } do %>
    <%= sage_component SageModalContent, {
      title: "Example Modal"
    } do %>
      <% content_for :sage_header_aside do %>
        <%= sage_component SageButton, {
          style: "secondary",
          subtle: true,
          value: "Close Modal",
          icon: { name: "remove", style: "only" },
          attributes: { "data-js-modal": true }
        } %>
      <% end %>

      <% content_for :sage_header_progress_bar do %>
        <%= sage_component SageProgressBar, {
          color: SageTokens::COLOR_PALETTE[:PRIMARY_200],
          percent: 44,
          label: "Reached limit"
        } %>

      <% end %>

      <% content_for :sage_header_actions do %>
        <%= sage_component SageButton, {
          value: "Save changes",
          subtle: true,
          style: "primary",
        } %>
        <%= sage_component SageButton, {
          value: "Publish changes",
          style: "primary",
        } %>
      <% end %>

      <%= sample_body_text %>
    <% end %>
  <% end %>

<% end %>

<%= sage_component SagePanelBlock, {} do %>
  <h3 class="<%= SageClassnames::TYPE::HEADING_6 %>">Animated</h3>
  <%= sage_component SageButtonGroup, { gap: :sm, spacer: { bottom: :sm }} do %>
    <%= sage_component SageButton, {
      style: "primary",
      icon: { name: "launch", style: "right" },
      value: "Default",
      attributes: {
        "data-js-modaltrigger": "cool-modal-animate-default",
      }
    } %>
    <%= sage_component SageButton, {
      style: "primary",
      icon: { name: "launch", style: "right" },
      value: "To top",
      attributes: {
        "data-js-modaltrigger": "cool-modal-animate-top",
      }
    } %>
    <%= sage_component SageButton, {
      style: "primary",
      icon: { name: "launch", style: "right" },
      value: "To left (blur off)",
      attributes: {
        "data-js-modaltrigger": "cool-modal-animate-left",
      }
    } %>
    <%= sage_component SageButton, {
      style: "primary",
      icon: { name: "launch", style: "right" },
      value: "To right (blur off)",
      attributes: {
        "data-js-modaltrigger": "cool-modal-animate-right",
      }
    } %>
  <% end %>

  <%# Animated Modals %>
  <%= sage_component SageModal, { id: "cool-modal-animate-default", animate: true, css_classes: "custom-class-name-here" } do %>
    <%= sage_component SageModalContent, { title: "Example Modal" } do %>
      <% content_for :sage_header_aside do %>
        <%= sage_component SageButton, {
          style: "secondary",
          subtle: true,
          value: "Close Modal",
          icon: { name: "remove", style: "only" },
          attributes: { "data-js-modal": true }
        } %>
      <% end %>

      <%= sample_body_text %>

      <% content_for :sage_footer do %>
        <% content_for :sage_footer_aside do %>
          <%= sage_component SageButton, {
            style: "secondary",
            subtle: true,
            value: "Close Modal",
            attributes: { "data-js-modal": true }
          } %>
        <% end %>
        <%= sage_component SageButton, {
          style: "primary",
          icon: { name: "check", style: "left" },
          value: "Take An Action",
        } %>
      <% end %>
    <% end %>
  <% end %>

  <%= sage_component SageModal, { id: "cool-modal-animate-top", animate: { direction: "top" } } do %>
    <%= sage_component SageModalContent, { title: "Example Modal" } do %>
      <% content_for :sage_header_aside do %>
        <%= sage_component SageButton, {
          style: "secondary",
          subtle: true,
          value: "Close Modal",
          icon: { name: "remove", style: "only" },
          attributes: { "data-js-modal": true }
        } %>
      <% end %>

      <%= sample_body_text %>

      <% content_for :sage_footer do %>
        <% content_for :sage_footer_aside do %>
          <%= sage_component SageButton, {
            style: "secondary",
            subtle: true,
            value: "Close Modal",
            attributes: { "data-js-modal": true }
          } %>
        <% end %>
        <%= sage_component SageButton, {
          style: "primary",
          icon: { name: "check", style: "left" },
          value: "Take An Action",
        } %>
      <% end %>
    <% end %>
  <% end %>

  <%= sage_component SageModal, { id: "cool-modal-animate-left", disable_background_blur: true, animate: { direction: "left" } } do %>
    <%= sage_component SageModalContent, { title: "Example Modal" } do %>
      <% content_for :sage_header_aside do %>
        <%= sage_component SageButton, {
          style: "secondary",
          subtle: true,
          value: "Close Modal",
          icon: { name: "remove", style: "only" },
          attributes: { "data-js-modal": true }
        } %>
      <% end %>

      <%= sample_body_text %>

      <% content_for :sage_footer do %>
        <% content_for :sage_footer_aside do %>
          <%= sage_component SageButton, {
            style: "secondary",
            subtle: true,
            value: "Close Modal",
            attributes: { "data-js-modal": true }
          } %>
        <% end %>
        <%= sage_component SageButton, {
          style: "primary",
          icon: { name: "check", style: "left" },
          value: "Take An Action",
        } %>
      <% end %>
    <% end %>
  <% end %>

  <%= sage_component SageModal, { id: "cool-modal-animate-right", disable_background_blur: true, animate: { direction: "right" } } do %>
    <%= sage_component SageModalContent, { title: "Example Modal" } do %>
      <% content_for :sage_header_aside do %>
        <%= sage_component SageButton, {
          style: "secondary",
          subtle: true,
          value: "Close Modal",
          icon: { name: "remove", style: "only" },
          attributes: { "data-js-modal": true }
        } %>
      <% end %>

      <%= sample_body_text %>

      <% content_for :sage_footer do %>
        <% content_for :sage_footer_aside do %>
          <%= sage_component SageButton, {
            style: "secondary",
            subtle: true,
            value: "Close Modal",
            attributes: { "data-js-modal": true }
          } %>
        <% end %>
        <%= sage_component SageButton, {
          style: "primary",
          icon: { name: "check", style: "left" },
          value: "Take An Action",
        } %>
      <% end %>
    <% end %>
  <% end %>
<% end %>

<%= md("
<h3 class=\"SageClassnames::TYPE::HEADING_6\">Asyncronous Modals</h3>
There are a number of situations where it might be most practical to load content for a modal asyncronously.
For example, in a list of products, each product may allow an option to edit that product's details in a modal.
In this case you may have a route that delivers only the contents of the modal that can be called asyncronously when the modal trigger is clicked.

Set this up as follows:

1. Ensure that you have at least one modal stub in your view using `SageModal` and be sure to provide an `id` for it along with any other configurations.
    As best practices consider:
  - Use the `remove_content_on_close: true` to ensure that any asynchronous content is removed from the modal when it is closed.
  - You can provide default content (typically inside of a `SageModalContent` nested within the `SageModal` stub) such as a `SageLoader` inside this modal stub.
    This will be replaced by the asynchronous content once it loads and be put back when the content unloads.
2. Ensure you have an endpoint that delivers _only_ the content of the modal, typically wrapped by the `SageModalContent` component.
3. In the primary view, add hyperlinks, buttons, or other clickable triggers. On such triggers use the following:
  - `data-js-modaltrigger=\"[modal-id]\"` where `modal-id` is the `id` you placed on the corresponding `SageModal` stub.
  - `data-js-remote-url=\"[url]\"` where `url` is the edpoint that delivers the content.

Note as well that you can set up `remote_url`'s on both the main `SageModal` stub and on triggers.
In such cases, the `remote_url` from the triggers overrides the one on the modal stub; but if no `remote_url` is provided from the trigger, the one on the modal itself is used.
As shown elsewhere on this page default content (such as `SageLoader`) can also be manually populated inside the `SageModal` that is then replaced by asynchronous `remote_url` content.
", use_sage_type: true) %>

<%= sage_component SageButtonGroup, { gap: :sm } do %>
  <%= sage_component SageButton, {
    html_attributes: {
      "data-js-modaltrigger": "test-modal",
    },
    style: "primary",
    value: "Open modal A",
  } %>
  <%= sage_component SageButton, {
    html_attributes: {
      "data-js-modaltrigger": "test-modal",
      "data-js-remote-url": async_path("modal-demo-2"),
    },
    style: "primary",
    value: "Open modal B",
  } %>
  <%= sage_component SageButton, {
    html_attributes: {
      "data-js-modaltrigger": "test-modal",
      "data-js-remote-url": async_path("modal-demo-3"),
    },
    style: "primary",
    value: "Open modal C",
  } %>
<% end %>

<%= sage_component SageModal, { id: "test-modal", remote_url: async_path("modal-demo"), remove_content_on_close: true, } do %>
  <%= sage_component SageModalContent, {} do %>
    <%= sage_component SageLoader, { type: "spinner" } %>
  <% end %>
<% end %>

<%= sage_component SagePanelStack, {} do %>
  <h3 class="<%= SageClassnames::TYPE::HEADING_6 %>">Events (monitor in browser console)</h3>
  <p>Use these events for hooking into modal functionality using JS event listeners.</p>

  <%= sage_component SageTable, {
    striped: true,
    responsive: true,
    headers: [
      "Event name",
      "Event type",
      "Description"
    ],
    rows: [
      {
        col_1: md("`sage.modal.active`"),
        col_2: "global",
        col_3: md("Fires when **any** modal has been opened")
      },
      {
        col_1: md("`sage.modal.closeAll`"),
        col_2: "global",
        col_3: md("Fires when **any** modal has been closed")
      },
      {
        col_1: md("`sage.modal.opening`"),
        col_2: "instance",
        col_3: "Fires immediately when a modal has been opened"
      },
      {
        col_1: md("`sage.modal.open`"),
        col_2: "instance",
        col_3: md("Fires after a modal has loaded. If `animate` is enabled, this event will run upon completion of the modal\'s animation. Otherwise, this event will run immediately along with `sage.modal.opening`.")
      },
    ]
  } %>

  <%= sage_component SageButtonGroup, { gap: :sm, spacer: { bottom: :sm }} do %>
    <%= sage_component SageButton, {
      style: "primary",
      icon: { name: "launch", style: "right" },
      value: "'sage.modal.active'",
      attributes: {
        "data-js-modaltrigger": "cool-modal-event-active",
      }
    } %>
    <%= sage_component SageButton, {
      style: "primary",
      icon: { name: "launch", style: "right" },
      value: "'sage.modal.opening'",
      attributes: {
        "data-js-modaltrigger": "cool-modal-event-opening",
      }
    } %>
    <%= sage_component SageButton, {
      style: "primary",
      icon: { name: "launch", style: "right" },
      value: "'sage.modal.open'",
      attributes: {
        "data-js-modaltrigger": "cool-modal-event-open",
      }
    } %>
  <% end %>

  <%# Event-enabled Modals %>
  <%= sage_component SageModal, { id: "cool-modal-event-active", disable_background_blur: true, animate: true } do %>
    <%= sage_component SageModalContent, { title: "Example 'Active' Event Modal" } do %>
      <% content_for :sage_header_aside do %>
        <%= sage_component SageButton, {
          style: "secondary",
          subtle: true,
          value: "Close Modal",
          icon: { name: "remove", style: "only" },
          attributes: { "data-js-modal": true }
        } %>
      <% end %>

      <%= sample_body_text %>

      <% content_for :sage_footer do %>
        <% content_for :sage_footer_aside do %>
          <%= sage_component SageButton, {
            style: "secondary",
            subtle: true,
            value: "Close Modal",
            attributes: { "data-js-modal": true }
          } %>
        <% end %>
        <%= sage_component SageButton, {
          style: "primary",
          icon: { name: "check", style: "left" },
          value: "Take An Action",
        } %>
      <% end %>
    <% end %>
  <% end %>

  <%= sage_component SageModal, { id: "cool-modal-event-open", disable_background_blur: true, animate: true, css_classes: "custom-class-name-here" } do %>
    <%= sage_component SageModalContent, { title: "Example 'Open' Event Modal" } do %>
      <% content_for :sage_header_aside do %>
        <%= sage_component SageButton, {
          style: "secondary",
          subtle: true,
          value: "Close Modal",
          icon: { name: "remove", style: "only" },
          attributes: { "data-js-modal": true }
        } %>
      <% end %>

      <%= sample_body_text %>

      <% content_for :sage_footer do %>
        <% content_for :sage_footer_aside do %>
          <%= sage_component SageButton, {
            style: "secondary",
            subtle: true,
            value: "Close Modal",
            attributes: { "data-js-modal": true }
          } %>
        <% end %>
        <%= sage_component SageButton, {
          style: "primary",
          icon: { name: "check", style: "left" },
          value: "Take An Action",
        } %>
      <% end %>
    <% end %>
  <% end %>

  <%= sage_component SageModal, { id: "cool-modal-event-opening", disable_background_blur: true, animate: true } do %>
    <%= sage_component SageModalContent, { title: "Example 'Opening' Event Modal" } do %>
      <% content_for :sage_header_aside do %>
        <%= sage_component SageButton, {
          style: "secondary",
          subtle: true,
          value: "Close Modal",
          icon: { name: "remove", style: "only" },
          attributes: { "data-js-modal": true }
        } %>
      <% end %>

      <%= sample_body_text %>

      <% content_for :sage_footer do %>
        <% content_for :sage_footer_aside do %>
          <%= sage_component SageButton, {
            style: "secondary",
            subtle: true,
            value: "Close Modal",
            attributes: { "data-js-modal": true }
          } %>
        <% end %>
        <%= sage_component SageButton, {
          style: "primary",
          icon: { name: "check", style: "left" },
          value: "Take An Action",
        } %>
      <% end %>
    <% end %>
  <% end %>

  <%= sage_component SageModal, { id: "cool-modal-event-close", disable_background_blur: true, animate: true } do %>
    <%= sage_component SageModalContent, { title: "Example 'CloseAll' Event Modal" } do %>
      <% content_for :sage_header_aside do %>
        <%= sage_component SageButton, {
          style: "secondary",
          subtle: true,
          value: "Close Modal",
          icon: { name: "remove", style: "only" },
          attributes: { "data-js-modal": true }
        } %>
      <% end %>

      <%= sample_body_text %>

      <% content_for :sage_footer do %>
        <% content_for :sage_footer_aside do %>
          <%= sage_component SageButton, {
            style: "secondary",
            subtle: true,
            value: "Close Modal",
            attributes: { "data-js-modal": true }
          } %>
        <% end %>
        <%= sage_component SageButton, {
          style: "primary",
          icon: { name: "check", style: "left" },
          value: "Take An Action",
        } %>
      <% end %>
    <% end %>
  <% end %>

<% end %>

<script>
  (function() {
    const modalOpeningExample = document.querySelector("[data-js-modal=cool-modal-event-opening]");
    const modalOpenExample = document.querySelector("[data-js-modal=cool-modal-event-open]");

    document.addEventListener("sage.modal.active", function(e) {
      console.info("sage.modal.active global event fired", e);
    });
    modalOpeningExample.addEventListener("sage.modal.opening", function(e) {
      console.info("sage.modal.opening event fired", e);
    });
    modalOpenExample.addEventListener("sage.modal.open", function(e) {
      console.info("sage.modal.open event fired", e);
    });
    document.addEventListener("sage.modal.closeAll", function(e) {
      console.info("sage.modal.closeAll global event fired", e);
    });
  })();
</script>
Property Description Type Default

active

Enabling this property will return the JS early to not initialize any handlers.

Boolean

nil

animate

When true, in addition to the base fade transition assigned to all modals, the modal will animate into view while being displayed. Default direction of this animation runs from the top of the page down, and can be overridden using animate_direction. All animations are disabled when the user has "reduce motion" enabled in their OS or browser.

Boolean

nil

css_classes

Outputs additional CSS classes as specified.

String

nil

direction

Sets the direction of the animation when animate has been enabled. Options include "bottom" (default), "top", "left", and "right". Use caution when setting multiple direction modals within a page or view to ensure a consistent user experience. This option requires animate to be set to true.

String

nil

disable_background_blur

Disables the background blur filter, with a darkened background color. Recommended for increased animation performance when animate is enabled. This setting is ignored when "reduce motion" is enabled by the user's OS.

Boolean

nil

disable_background_dismiss

Enabling this property will return the JS early to not initialize any handlers.

Boolean

nil

disable_close

Enabling this property will return the JS early to not initialize any handlers.

Boolean

nil

fullscreen

Toggles whether to use the fullscreen variant of the modal by attaching .sage-modal--fullscreen

Boolean

nil

id

Unique identifier for component. Should match the data-js-modaltrigger property on the corresponding button

String

`nil

large

Toggles whether to use the large variant of the modal by attaching .sage-modal--large

Boolean

nil

remove_content_on_close

Toggles whether to delete the innerHTML when closing the modal.

Boolean

nil

remote_url

Specify a url which from which to load the modal content on open. This will be requested & content replaced every time the modal is opened.

String

nil

Modal Content

header_icon

When present, sets the icon with optional color in the header of the comoponent

    {
      color: SageSchemas::COLOR_SLIDER (optional)
      name: SageSchemas::ICON
    }

nil

help_content

Sets the content for the Popover component

String

nil

help_link

Array containing help link title and href for the subheader Popover

String

nil

help_title

Sets the title for the subheader Popover

String

nil

title

Populates the sage-modal__header with a heading containing the provided content

String

nil

spacing

Optionally enforces either a card- or panel-based spacing grid on the sage-modal__content.

panel or card

nil

subheader

Adds an optional subheader under the modal title.

String

nil

Section: header_aside

Populates the sage-modal__header-aside.

String

nil

Section: header_indicator

Populates the the page indicator in the header of standard modals.

String

nil

Section: header_progress_bar

Populates the header of a fullscreen modal with a progress bar.

String

nil

Section: footer

Populates the sage-modal__footer.

String

nil

Section: footer_aside

Populates the sage-modal__footer-aside for buttons or content set to the left of the panel footer.

String

nil

Events
Global/window events

sage.modal.active

This event is fired immediately when any modal has been opened.

sage.modal.closeAll

Fires on when a modal has been closed, either from actuating a button, esc keypress, or clicking a modal's backdrop.

Individual modal events

sage.modal.opening

This modal event is fired immediately when a modal has been opened.

sage.modal.open

Fired after a modal has completed its loading animation. Note that if animate has not been enabled, this event will fire at the same time as sage.modal.opening.

Sections

Element

sage_header_actions

When present, this will show containing SageButtons in the header of the component

SageButton

sage_header_aside

This area holds the button that closes the modal. This resides in the header of the component.

SageButton

sage_header_image

When present, sets the image in the header of the component

HTML image

sage_header_indicator

This area holds the page indicator for the modal. This is to be used on multi-page modals.

SageIndicator

sage_modal_custom_header

This can be used to provide custom header content, typically in lieue of the title or other header-related configurations for more tailored control of this area.

string/HTML

sage_footer

This area holds the cta buttons for the component.

SageButton

sage_footer_aside

This area holds the cancel or close modal button in the footer of the component.

SageButton

Do
  • Be sure that the <button>'s data-js-modaltrigger and the modal id match to establish the necessary link.
Don't
  • DO NOT use the remove_content_on_close property if your modal's content is not populated using JavaScript. The modal will not have content the next time it's triggered