JS to open window

This is the code that I currently use to open a window for a click here for explanation.

<div class=body><a id="terms" name="explain" style="font-size:12px;color:blue;text-decoration:underline; cursor:pointer;" onclick="window.open('Yourpage.html','terms','height=550,width=650,top=0,left=0,status=no,addressbar=yes,menubar=no,scrollbars=yes')">click here</a></div>

Some of your nicer website has really cool open windows with a big X in the right corner to close it. Some might even have a nice transition when opening and will often close if you touch the main page.

I want to sharpen that look - anything out there that would work? I am guessing it would probably have to be JS for that to happen.

Thanks

You are looking for what is called a Modal window (pronounced mow-dell).

Here’s a list of several tiny plugins that make it easy to create modal windows.
http://microjs.com/#modal

1 Like

Thank you for that. The name “modal” is new to me.

Could my code be improved or is this rather standard?

Modals have become more and more the standard, no doubt partially because people found popups rather annoying and so popup blockers were born :wink:

1 Like

Yes, there are many improvements that can be made.

Here is the starting code:

<div class=body>
  <a id="terms" name="explain" style="" onclick="window.open('Yourpage.html','terms','height=550,width=650,top=0,left=0,status=no,addressbar=yes,menubar=no,scrollbars=yes')">click here</a>
</div>

First, the style should be moved out to a separate CSS file.

#terms {
  font-size: 12px;
  color: blue;
  text-decoration: underline;
  cursor: pointer;
<div class=body>
  <a id="terms" name="explain" onclick="window.open('Yourpage.html','terms','height=550,width=650,top=0,left=0,status=no,addressbar=yes,menubar=no,scrollbars=yes')">click here</a>
</div>

Double quotes are recommended on all HTML attributes:

<div class="body">

The inline onclick event should be moved out to a separate JavaScript file:

<div class="body">
  <a id="terms" name="explain">click here</a>
</div>
document.querySelector("#terms").addEventListener("click", function () { 
  window.open('Yourpage.html', 'terms', 'height=550,width=650,top=0,left=0,status=no,addressbar=yes,menubar=no,scrollbars=yes');
});

That long list of features …

My computer’s been hijacked by updates, so this last piece I’m typing out on my tablet, and more will have to wait.

That code works but I don’t any difference then my code which is a lot shorter. Please explain the benefit on using your code.

Thanks

Unlike your “shorter” code that has problems and is difficult to troubleshoot, Paul’s “longer” code is easier to troubleshoot and will not cause problems once finalized.

2 Likes

That’s actually not real windows but regular HTML elements that are absolutely (or sometimes fixed) positioned on the page; a basic example might look like this:

<a href="#" data-open-modal>click here</a>

<div class="modal-overlay">
  <div class="modal-container">
    <div class="modal-header">
      Lorem ipsum
      <a href="#" class="modal-close">&times;</a>
    </div>
    <div class="modal-content">
      Lorem ipsum dolor sit amet, consectetur adipisicing elit. Voluptatem repellat, modi totam. Recusandae a culpa dolor, placeat veritatis sed qui dignissimos, non optio provident voluptatem, sunt dolores. Perspiciatis, esse natus.
    </div>
  </div>
</div>

And the CSS to make it look like a window:

.modal-overlay {
  display: flex;
  justify-content: center;
  align-items: center;
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  background-color: rgba(0, 0, 0, .5);
}

.modal-container {
  flex-basis: 50%;
  padding: 1rem;
  background-color: #fff;
  border-radius: 3px;
}

.modal-header {
  display: flex;
  font-weight: bold;
}

.modal-close {
  margin-left: auto;
  color: inherit;
  text-decoration: none;
  margin-top: -.5rem;
  font-size: 2rem;
}

Of course it should be hidden initially though… so mutatis mutandis:

.modal-overlay {
  display: none;
  /* ... */
}

.modal-overlay.active {
  display: flex;
}

You then need some JS to show it when clicking a certain link, and hide it when clicking the close button or the overlay:

var openModal = document.querySelector('[data-open-modal]')
var closeModal = document.querySelector('.modal-close')
var modalOverlay = document.querySelector('.modal-overlay')

var handleOpenModal = function (event) {
  event.preventDefault()
  modalOverlay.classList.add('active')
}

var handleCloseModal = function (event) {
  if (event.target !== event.currentTarget) {
    // Only hide the modal when clicking elements the handler
    // got actually attached to, not others from which the
    // event bubbles up to the current target (e.g. from the 
    // modal content)
    return;
  }

  event.preventDefault()
  modalOverlay.classList.remove('active')
}

openModal.addEventListener('click', handleOpenModal)
closeModal.addEventListener('click', handleCloseModal)
modalOverlay.addEventListener('click', handleCloseModal)

The animation part can be done with a CSS transition: opacity (say); however transitions won’t work when simultaneously changing the display property, and conversely we have to wait until the fading out animation finished until we can change it back to display: none. The solution is splitting that in two different classes (again mutatis mutandis):

.modal-overlay {
  display: none;
  opacity: 0;
  transition: opacity .2s ease;
}

.modal-overlay.active {
  display: flex;
}

.modal-overlay.visible {
  opacity: 1;
}

And the JS needs to be adjusted to add / remove the corresponding classes at the appropriate times:

var handleShowModal = function (event) {
  modalOverlay.classList.add('visible')
}

var handleHideModal = function (event) {
  modalOverlay.classList.remove('active')
}

var handleOpenModal = function (event) {
  event.preventDefault()
  modalOverlay.classList.add('active')
  
  // Wait a tick to kickoff the animation
  window.setTimeout(handleShowModal)
}

var handleCloseModal = function (event) {
  if (event.target !== event.currentTarget) {
    return;
  }

  event.preventDefault()
  modalOverlay.classList.remove('visible')
  
  // Hide the modal when the fading out is finished
  modalOverlay.addEventListener(
    'transitionend',
    handleHideModal, 
    { once: true, passive: true }
  )
}

Here’s a fiddle putting it all together.

4 Likes

Yes, that makes sense. Thanks for the example. I appreciate it.

1 Like

You’re right, your code is a lot shorter. There is nothing that I would do to make your code any shorter than it currently is.

1 Like

That’s primarily because shortness of code is normally a poor metric to use. Clarity of understanding and ease of extension tend to be the metrics preferred around here.

2 Likes

Love the code, thanks.

Can you have more than one div to a page? I was having an issue reading only the first one.

Also, can the code be modified where you set it to a certain size and then it scrolls if needed?

Thanks

You’d give each modal an ID and reference it in the link via a data-* attribute (e.g. data-open-modal="#modal-1") or simply by the hash of its href attribute. Then loop over all links that have that data attribute and initialise the modals as shown above.

However I’d encourage you to try understanding the current code first; if you have questions or trouble implementing the additional functionality I’m of course happy to help. :-) (In the latter case just post your attempt that doesn’t work so we can help you with the debugging.)

Sure, just add this CSS:

.modal-content {
  max-height: 300px;
  overflow: auto;
}
1 Like

Scroll added to css works fine, thanks. Will attempt the multiple link reference. Sound pretty straight forward.

So if I understand modals correctly, it’s hidden from view and only appears when the link is clicked. If you view source, you can see the information, but not in preview print.

I used an include file with the content div for the information, and when I had it in the open window method I was using, I could log that someone clicked on the link. I lose that function since it’s already on the page. Is there a way to treat the modal method in terms of tracking it the same way as before?

Thank you.

That depends on whether it’s opened when printing the page; but you can override this with @media print rules.

I think the most common solution would be including a tracking pixel in the modal, say in the active class like so:

.modal-overlay.active {
  display: flex;
  background-image: url('track-open-modal.png');
}

That background image only gets loaded when the element is actually visible, and this way allows you to track when a user opened the modal (including IP etc.). Another way would be to create an img element with JS inside the handleOpenModal() function.

1 Like

With using modal and since it is on the page but hidden, do the search engines also pick up any keywords or text?

Also, so I don’t have to change my method of tracking which would be extensive, is there an open window similar to my way per my original post that has the same nice clean look as with the modal method?

Thanks for your guidance; I very much appreciate it and learning newer ways.

1 Like

Well for one it’s in the actual markup from the start, so they can see it without executing any JS at all. And then search engines are even able to index completely JS-driven SPAs, so that shouldn’t matter really. I’m not a SEO expert though, in case of doubt you might start a new thread in the marketing category. :-)

No, all you can do is things like hiding the menu bar. But how exactly did you log that the link got clicked? If it’s just a regular access log or PHP function, you might send an AJAX request to that endpoint instead to achieve the same result; just instead of the window content, you’d only send back a success message (if at all).

When clicked it opens the page and the coding on the page puts an entry into the database using ASP and SQL.

<a href="#" data-open-modal>click here</a>

<div class="modal-overlay">
  <div class="modal-container">
    <div class="modal-header">
      Lorem ipsum
      <a href="#" class="modal-close">&times;</a>
    </div>
    <div class="modal-content">
      Lorem ipsum dolor sit amet, consectetur adipisicing elit. Voluptatem repellat, modi totam. Recusandae a culpa dolor, placeat veritatis sed qui dignissimos, non optio provident voluptatem, sunt dolores. Perspiciatis, esse natus.
    </div>
  </div>
</div>

What’s the best way to handle the Div tags for modal in a table cell?

Can they be outside the table and all you need is the a href inside the cell?

OK well I can’t help you with ASP I’m afraid, but generally you’d take the code that stores the user access to the database and create an endpoint that does only that; say my-site.com/track-me.aspx. Then you can then send an XHR to that endpoint like so (also check the AJAX link from my previous reply):

var xhr = new XMLHttpRequest()

xhr.open('GET', '/track-me.aspx')
xhr.send()

On the server side this request is basically the same as if you’d do

window.open('/track-me.aspx')

… just on the client side you don’t actually open a window with the response.

Yes, I’d put them as direct children of the body for the absolute positioning. The links that opens the modals can be anywhere.

PS:

Thinking about it, you might display the page inside the modal as an iframe… although that would probably create some unnecessary overhead and delay for the user. Anyway to have the iframe only load when the modal gets opened, you’d have to set its src with JS then… here’s an adjusted fiddle.

1 Like