3
\$\begingroup\$

I created a simple modal that when a user scrolls down a blog post, a modal pops up. If the user wants to sign up for newsletter, then a form pops up. The only external library I used was body-scroll-lock that helps mitigate some issues with modals/forms on iOS.

I'm curious about the need to remove event listeners and other pitfalls that I may be overlooking. Should I be using more es6 type conventions? The code is just before the </body> tag. Here it is in action: https://develop--tanyamark-prod.netlify.com/blog/do-you-eat-when-youre-hungry-stop-when-youre-full/

// Wait at least 2s to so CTA
var wait = window.setTimeout(showCta, 2000);

function showCta() {
    // Only show CTA on post pages.
    if (document.querySelector('.post-single') === null) {
        return;
    }

    var screenWidth = window.innerWidth ||
                      document.documentElement.clientWidth ||
                      document.body.clientWidth;

    var bodyTag = document.getElementsByTagName('body')[0];
    var blogCta = document.getElementById("blog-cta");
    var openFormButton = document.getElementById("open-cta");
    var closeButtonUnsubmitted = document.getElementById("close-cta");
    var submittedCloseButton = document.getElementById("submitted-close");

    // Wait to show cta until user scrolls down page.
    bodyTag.onscroll = function () {
        if ( window.pageYOffset > (document.body.clientHeight / 4) ) {
            blogCta.classList.remove("hide");
        }
    };

    var openForm = function(e) {
        if (screenWidth < 901) {
            blogCta.classList.add("mobile-blog-cta");
            bodyScrollLock.disableBodyScroll(blogCta);            
        }

        // Show the form.
        document.getElementById("cta-ck-form").style.display = 'block';

        // Remove click event from button.
        openFormButton.removeEventListener('click', openForm);

        // Hide openFormButton
        openFormButton.style.display = 'none';
    };

    var removeCTA = function() {
        blogCta.classList.remove("mobile-blog-cta");

        if (screenWidth < 901) {
            bodyScrollLock.clearAllBodyScrollLocks();
        }

        // Set inline so it doesn't show more than once.
        blogCta.style.display = 'none';
    };

    // Register events
    openFormButton.addEventListener('click', openForm);
    closeButtonUnsubmitted.addEventListener('click', removeCTA);
    submittedCloseButton.addEventListener('click', removeCTA);
}

/partials/_cta.html (The form itself is a convert kit embed)

<div id="blog-cta" class="blog-cta hide">
    <div class="cta-content">
        <p id="cta-message">Hi, It's Tanya. Like what you're reading? Get tips once a week on <em>nourishing your whole self.</em></p>
        <div id="open-cta" class="button pink">Yes, please!</div>
        <div id="cta-ck-form" class="ck_form_container ck_inline" data-ck-version="6">
            <div class="ck_form ck_naked">
                <div class="ck_form_fields">
                    <div id="ck_success_msg" style="display:none;">
                        <p>Success! Check your email to confirm your subscription.</p>
                        <button id="submitted-close">Close</button>
                    </div>
                    <!--  Form starts here  -->
                    <form id="ck_subscribe_form" class="ck_subscribe_form" action="https://app.convertkit.com/landing_pages/309440/subscribe" data-remote="true">
                        <input type="hidden" value="{&quot;form_style&quot;:&quot;naked&quot;}" id="ck_form_options">
                        <input type="hidden" name="id" value="309440" id="landing_page_id">
                        <input type="hidden" name="ck_form_recaptcha" value="" id="ck_form_recaptcha">
                        <div class="ck_errorArea">
                            <div id="ck_error_msg" style="display:none">
                                <p>There was an error submitting your subscription. Please try again.</p>
                            </div>
                        </div>
                        <div class="ck_control_group ck_email_field_group">
                            <label id="ck-test" class="ck_label" for="ck_emailField" style="display: none">Email Address</label>
                            <input type="text" name="first_name" class="ck_first_name" id="ck_firstNameField" placeholder="First Name" required="required">
                            <input type="email" name="email" class="ck_email_address" id="ck_emailField" placeholder="Email Address" required>
                        </div>
                        <div class="ck_control_group ck_captcha2_h_field_group ck-captcha2-h" style="position: absolute !important;left: -999em !important;">
                            <input type="text" name="captcha2_h" class="ck-captcha2-h" id="ck_captcha2_h" placeholder="We use this field to detect spam bots. If you fill this in, you will be marked as a spammer.">
                        </div>
                        <button class="subscribe_button ck_subscribe_button btn fields" id="ck_subscribe_button">
                            Subscribe
                        </button>
                    </form>
                </div>
            </div>
        </div>
    </div>
    <div class="container-author-pic">
        <div class="incoming-message"><span>1</span></div>
        <img class="article-author-pic" src="/img/tanya-cup-prof.jpg" alt=""/>
        <div class="mobile-header">Tanya</div>
        <div id="close-cta">X</div>
    </div>
</div>

/partials/_cta.css (Using postcss-cssnext plugin)

.blog-cta {
  display: flex;
  flex-direction: row;
  position: fixed;
  bottom: 80px;
  right: 30px;
  z-index: 820;
  animation: grow .5s ease-in-out;

  @media all and (max-width: 600px) {
    right: 0;
    margin: 15px;
  }

}

@keyframes grow {
  0% {
    display: none;
    opacity: 0;
    transform: scale(0);
  }
  100% {
    opacity: 1;
    transform: scale(1);
  }
}

.cta-content {
  position: relative;
  display: flex;
  flex-direction: column;
  max-width: 300px;
  background-color: white;
  box-shadow: 0 0 30px rgba(42, 63, 253, .4);
  margin-right: 15px;
}

.cta-content::after {
  position: absolute;
  display: block;
  content: "";
  width: 0;
  height: 0;
  left: 100%;
  top: 45px;
  border-top: 8px solid transparent;
  border-bottom: 8px solid transparent;
  border-left: 10px solid #fff;

  @media all and (max-width: 600px) {
    top: 30px;
  }
}

#cta-message {  
  color: #1c3f55;
  font-size: 17px;
  line-height: 22px;
  padding: 12px;
  margin: 0;
}

#open-cta {
  cursor: pointer;
}

.mobile-header {
  /* Will show on mobile  */
  display: none;
}

.incoming-message {
  width: 20px;
  height: 20px;
  background-color: red;
  border-radius: 24px;
  color: white;
  font-size: 14px;
  position: absolute;
  display: flex;
  align-items: center;
  justify-content: center;
}

#close-cta {
  display: inline-flex;
  justify-content: center;
  align-items: center;
  position: absolute;
  top: -15px;
  right: -15px;
  font-family: var(--sans-serif-stack);
  color: #a2a1a1;
  font-size: 14px;
  cursor: pointer;
  height: 16px;
  width: 16px;
  padding: 5px;
  border-radius: 16px;
  background: #f1f1f5;
}

#close-cta:hover {
  color: black;
  transition: color .2s ease-in-out;
  transition: font-size .2s ease-in-out;
}

/********************/
/* Convert Kit Form */
/********************/

#cta-ck-form {
  display: none;
  animation: grow .3s ease-in-out;
}

.ck_form, .ck_form * {
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
}

.ck_errorArea {
    display: none;
    /* temporary */
}

.ck_form input[type="text"]:focus,
.ck_form input[type="email"]:focus {
    outline: none;
    border-color: #aaa;
}

.ck_converted_content {
    display: none;
    padding: 5%;
    background: #fff;
}

.ck_form.ck_naked.width400 .ck_subscribe_button,
.ck_form.ck_naked.width400 input[type="text"],
.ck_form.ck_naked.width400 input[type="email"] {
    width: 100%;
    float: none;
    margin-top: 5px;
}

.ck_slide_up, .ck_modal,
.ck_slide_up .ck_naked,
.ck_modal .ck_naked {
    min-width: 400px;
}

.page .ck_form.ck_naked {
    margin: 50px auto;
    max-width: 700px;
}

.ck_slide_up.ck_form_v6, .ck_modal.ck_form_v6,
.ck_slide_up.ck_form_v6 .ck_naked, .ck_modal.ck_form_v6 .ck_naked {
    min-width: 0 !important;
}

.ck_form_v6 #ck_success_msg {
    padding: 0px 10px;
}

@media all and (max-width: 403px) {
    .ck_form_v6.ck_modal .ck_naked {
        padding-top: 30px;
    }
}

@media all and (max-width: 499px) {
    .ck_form_v6.ck_modal .ck_naked+.ck_close_link {
        color: #fff;
        top: 10px;
    }
}

.ck_form_v6.ck_slide_up .ck_naked+.ck_close_link {
    right: 10px;
    top: -5px;
}

@media all and (min-width: 600px) {
    .ck_form_v6.ck_slide_up .ck_naked+.ck_close_link {
        right: 35px;
    }
}

/************************/
/* ConvertKit overrides */
/************************/

.blog-cta .ck_form.ck_naked p {
  font-size: 17px;
  line-height: 20px;
}

.blog-cta .ck_form.ck_naked .ck_form_fields {
    padding: 12px;
}

.blog-cta .ck_form.ck_naked input[type="text"],
.blog-cta .ck_form.ck_naked input[type="email"] {
    padding: 10px 8px;
    border: 1px solid #d6d6d6;
    height: 40px;
    font-size: 18px;
}

.blog-cta .ck_form.ck_naked .ck_subscribe_button,
.blog-cta #ck_success_msg button {
    color: #fff;
    font-size: 18px;
    background: #db65cb;
    cursor: pointer;
    border: none;
    height: 44px;
    margin-top: 10px
}

.blog-cta #ck_success_msg button {
  padding: 0 20px;
  display: block;
  margin: 0 auto;
}

/*************************/
/* Mobile + Small Screen */
/*************************/

.mobile-blog-cta.blog-cta {
  bottom: initial;
  flex-direction: column-reverse;
  justify-content: flex-end;
  align-items: center;
  margin: 0;
  background: #f6f6f6;
  position: fixed;
  top: 0;
  height: 100vh;
  width: 100%;
  right: 0;
  animation: anim .5s ease-in-out;

  @media (max-height: 370px), (max-width: 320px) {
    height: 100vh;
  }
}

@keyframes anim {
  0% {
    transform: scale(0);
  }
  100% {
    opacity: 1;
    transform: scale(1);
  }
}

.mobile-blog-cta .cta-content {
  margin: 10px 10px;
  max-width: 600px;
  background-color: white;
  padding: 30px;
  box-shadow: 0 2px 20px 0 rgba(0,0,0,.15);

  @media (max-height: 370px), (max-width: 320px) {
    background-color: initial;
    padding: 0;
    box-shadow: initial;
  }
}

.mobile-blog-cta .cta-content #cta-message {
  padding-top: 0;
}

.mobile-blog-cta .cta-content::after {
  display: none;
}

.mobile-blog-cta .container-author-pic {
  width: 100%;
  height: 30px;
  background: #fff;
  padding: 10px 0;
  margin-bottom: 30px;
  box-shadow: 0 0 20px rgba(0,0,0,.5);
  display: flex;
  justify-content: space-around;
  align-items: center;
}

.mobile-blog-cta .article-author-pic {
  margin-top: 30px;
  border: #fff 5px solid;
}

.mobile-blog-cta .mobile-header{
  display: inline-block;
  line-height: 50px;
  font-weight: 600;
}

.mobile-blog-cta .incoming-message {
  display: none;
}

.mobile-blog-cta #close-cta {
  position: relative;
  font-size: 20px;
  color: initial;
  top: initial;
  right: initial;
  height: 22px;
  width: 22px;
}

.mobile-blog-cta #ck_firstNameField, .mobile-blog-cta #ck_emailField {
  width: 100%;
  margin-bottom: 10px;
}

.mobile-blog-cta .ck_form.ck_naked .ck_subscribe_button,
.mobile-blog-cta #ck_success_msg button {
  width: 100%;
}
\$\endgroup\$
6
  • \$\begingroup\$ Where's the HTML? \$\endgroup\$ Jan 20, 2019 at 19:37
  • 1
    \$\begingroup\$ Anything that's code. \$\endgroup\$ Jan 20, 2019 at 19:40
  • 2
    \$\begingroup\$ Ok, btw, you can embed code in your post, as opposed to linking it. \$\endgroup\$ Jan 20, 2019 at 19:42
  • 1
    \$\begingroup\$ Added the html and css. I linked to the live site only to demonstrate the feel/flow of the modal. And, I should add, of course, feed back on html/css is always nice as well. \$\endgroup\$
    – Mox
    Jan 20, 2019 at 19:47
  • 1
    \$\begingroup\$ Where is bodyScrollLock defined? \$\endgroup\$ Jan 20, 2019 at 23:46

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Browse other questions tagged or ask your own question.