<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: ktr92</title>
    <description>The latest articles on DEV Community by ktr92 (@ktrblog).</description>
    <link>https://dev.to/ktrblog</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1071691%2Fce6726d1-9394-457f-b235-ca1d8cb0ef94.png</url>
      <title>DEV Community: ktr92</title>
      <link>https://dev.to/ktrblog</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ktrblog"/>
    <language>en</language>
    <item>
      <title>VanillaJS Lazy Load images/video/embed/youtube</title>
      <dc:creator>ktr92</dc:creator>
      <pubDate>Mon, 27 May 2024 18:18:59 +0000</pubDate>
      <link>https://dev.to/ktrblog/vanillajs-lazy-load-imagesvideoembedyoutube-3583</link>
      <guid>https://dev.to/ktrblog/vanillajs-lazy-load-imagesvideoembedyoutube-3583</guid>
      <description>&lt;p&gt;DEMO - &lt;a href="https://codepen.io/ktr92/pen/qBGqRgZ"&gt;https://codepen.io/ktr92/pen/qBGqRgZ&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;html example&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;img data-src='https://placehold.co/600x400'&amp;gt;
&amp;lt;iframe width="560" height="315" data-src="https://www.youtube.com/embed/NpEaa2P7qZI?si=4Rq1E37zRobyhGRI" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;JS&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function lazyLoadSrc(selector) {
  const callback = (entries, observer) =&amp;gt; {
    entries.forEach(entry =&amp;gt; {
      const source = entry.target
      if (entry.intersectionRatio &amp;gt; 0) {
        if (!source.getAttribute('src')) {
            source.setAttribute('src', source.dataset.src)
            observer.unobserve(source)
        }
      }
    })
  }
  const target = document.querySelectorAll(selector)
  const options = {
    threshold: 0.4
  }
  let obs = new IntersectionObserver(callback, options)
  target.forEach(item =&amp;gt; {
    obs.observe(item)
  }) 
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// usage
document.addEventListener('DOMContentLoaded', function() {
  lazyLoadSrc('img');
  lazyLoadSrc('iframe');
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
    <item>
      <title>[Vue3 Tailwind] auth form</title>
      <dc:creator>ktr92</dc:creator>
      <pubDate>Tue, 14 May 2024 08:09:31 +0000</pubDate>
      <link>https://dev.to/ktrblog/vue3-tailwind-auth-form-5cl8</link>
      <guid>https://dev.to/ktrblog/vue3-tailwind-auth-form-5cl8</guid>
      <description>&lt;ul&gt;
&lt;li&gt;validation&lt;/li&gt;
&lt;li&gt;routes protecting&lt;/li&gt;
&lt;li&gt;status messages&lt;/li&gt;
&lt;li&gt;server-load imitation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://auth-app-nine-silk.vercel.app/"&gt;https://auth-app-nine-silk.vercel.app/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>vue</category>
      <category>tailwindcss</category>
    </item>
    <item>
      <title>[html js css] Vanilla JS slider with responsivity, swipe, arrows, dots</title>
      <dc:creator>ktr92</dc:creator>
      <pubDate>Sat, 02 Mar 2024 11:13:55 +0000</pubDate>
      <link>https://dev.to/ktrblog/html-js-css-vanilla-js-responsive-slider-5coo</link>
      <guid>https://dev.to/ktrblog/html-js-css-vanilla-js-responsive-slider-5coo</guid>
      <description>&lt;p&gt;demo - &lt;a href="https://codepen.io/ktr92/pen/gOybmwO"&gt;https://codepen.io/ktr92/pen/gOybmwO&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HTML&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div class="myslider" data-myslider-container='sliderID'&amp;gt;
      &amp;lt;div class="myslider__arrows"  data-myslider-arrows='sliderID'&amp;gt;
        &amp;lt;div class="myslider__arrow myslider__left" data-myslider-prev='sliderID'&amp;gt;prev&amp;lt;/div&amp;gt;
        &amp;lt;div class="myslider__arrow myslider__right" data-myslider-next='sliderID'&amp;gt;next&amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;div class="myslider__slider" data-myslider-slider='sliderID'&amp;gt;
        &amp;lt;div class="myslider__slide" data-myslider-slide='sliderID'&amp;gt;1&amp;lt;/div&amp;gt;
        &amp;lt;div class="myslider__slide" data-myslider-slide='sliderID'&amp;gt;2&amp;lt;/div&amp;gt;
        &amp;lt;div class="myslider__slide" data-myslider-slide='sliderID'&amp;gt;3&amp;lt;/div&amp;gt;
        &amp;lt;div class="myslider__slide" data-myslider-slide='sliderID'&amp;gt;4&amp;lt;/div&amp;gt;
        &amp;lt;div class="myslider__slide" data-myslider-slide='sliderID'&amp;gt;5&amp;lt;/div&amp;gt;
        &amp;lt;div class="myslider__slide" data-myslider-slide='sliderID'&amp;gt;6&amp;lt;/div&amp;gt;
        &amp;lt;div class="myslider__slide" data-myslider-slide='sliderID'&amp;gt;7&amp;lt;/div&amp;gt;
        &amp;lt;div class="myslider__slide" data-myslider-slide='sliderID'&amp;gt;8&amp;lt;/div&amp;gt;
        &amp;lt;div class="myslider__slide" data-myslider-slide='sliderID'&amp;gt;9&amp;lt;/div&amp;gt;     
      &amp;lt;/div&amp;gt;
      &amp;lt;div class="myslider__dots" data-myslider-dots='sliderID'&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;CSS&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[data-myslider-container] {
  width: 100%;
  overflow: hidden;
  position: relative;
}
[data-myslider-slider] {
  display: flex;
  position: relative;
  transition: left 0.5s;
  overflow-x: hidden;
  scroll-behavior: smooth;
  left: 0;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;JS&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Myslider {
  constructor(selector, settings) {
    this.settings = settings
    this.slidesVisible = settings.slides ?? 1
    this.screen = window.screen.width
    this.$el = document.querySelector(selector) 
    this.sliderID = this.$el.dataset.mysliderContainer
    this.$slider = this.$el.querySelector(`[data-myslider-slider='${this.sliderID}']`)
    this.$next = document.querySelector(`[data-myslider-next='${this.sliderID}']`)
    this.$prev = document.querySelector(`[data-myslider-prev='${this.sliderID}']`)
    this.$dots = document.querySelector(`[data-myslider-dots='${this.sliderID}']`)
    this.dotsItems = null
    this.activeId = 0
    this.slideWIdth =  this.$el.offsetWidth / this.slidesVisible
    this.slides = this.$slider.querySelectorAll(`[data-myslider-slide='${this.sliderID}']`)
    this.slidesCount =  this.slides.length
    this.sectionCount = Math.ceil(this.slidesCount / this.slidesVisible)
    this.position = this.$slider.style.left
    this.responsive = settings.responsive ?? null
    this.sliderInit()
  }


  sliderInit() {
    this.sizeInit()
    if (this.$next &amp;amp;&amp;amp; this.$prev) {
      this.arrowsInit()
    }
    if (this.$dots) {
      this.dotsInit()
    }
    if (this.responsive &amp;amp;&amp;amp; this.responsive.length &amp;gt; 0) {
      this.responsive.unshift({width: this.screen, slides: this.settings.slides ?? 1})
    }
    this.initSwipe()

    window.addEventListener('resize', () =&amp;gt; {
      this.activateSlide(0)
      this.sizeInit()
    })
  }

  arrowsInit() {
    this.$next.addEventListener('click', () =&amp;gt; {
      this.activateSlide(this.activeId + 1)
    });

    this.$prev.addEventListener('click', () =&amp;gt; {
      this.activateSlide(this.activeId - 1)
    });
  }

  sizeInit() {
    if (this.responsive &amp;amp;&amp;amp; this.responsive.length) {
      this.responsive.forEach((size, index) =&amp;gt; {
        if (size.width &amp;gt; window.innerWidth) {
          this.screen = size.width
          this.slidesVisible = size.slides
        }
      })
    }

    this.slideWIdth = this.$el.offsetWidth / this.slidesVisible

    let index = 0
    this.$slider.style.width = this.slideWIdth * this.slidesCount + 'px'
    this.slides.forEach($slide =&amp;gt; {
      $slide.style.width =  this.slideWIdth + 'px'
      $slide.dataset.mysliderid = index
      index++
    })
  }

  dotsInit() {

    for (let i = 0; i &amp;lt; this.sectionCount; i++) {
      this.$dots.insertAdjacentHTML('beforeend', `&amp;lt;div class="myslider__dots__button" data-mysliderdot="${i * (this.slidesVisible)}" data-myslider-dotid='${this.sliderID}'&amp;gt;&amp;lt;/div&amp;gt;`)
    }
    const dots = document.querySelectorAll(`[data-myslider-dotid='${this.sliderID}']`)
    dots[0].classList.add('active')

    dots.forEach(el =&amp;gt; {
      el.addEventListener('click', (e) =&amp;gt; {
        const id = +e.target.dataset.mysliderdot
        if (id &amp;lt; this.slidesCount - (this.slidesVisible - 1)) {
          this.activateSlide(id)

        } else {
          this.activateSlide(this.slidesCount - this.slidesVisible)

        }
      })
    })

    this.dotsItems = dots
  }

  activateDot(dots, id) {
    const activeDot = document.querySelector(`[data-mysliderdot="${id}"][data-myslider-dotid='${this.sliderID}']`)
    if (activeDot) {
      dots.forEach(dot =&amp;gt; {
        dot.classList.remove('active')
      })
      activeDot.classList.add('active')
    }
  } 



  activateSlide(n) {
    if (n &amp;lt; 0) {
      this.position = this.slideWIdth * (this.slidesCount - this.slidesVisible)
      this.$slider.style.left = -this.position + 'px'
      this.activeId = this.slidesCount - this.slidesVisible
     } else {
      if (n &amp;lt; this.slidesCount - (this.slidesVisible - 1)) {
        this.position = this.slideWIdth * n
        this.$slider.style.left = -this.position + 'px'
        this.activeId = n
       } else {
        this.$slider.style.left = 0
        this.activeId = 0
       }
     }

     this.activateDot(this.dotsItems, this.activeId)

  }

  initSwipe() {
       let initialX = null;
       let initialY = null;    

       const startTouch = (e) =&amp;gt; {
         initialX = e.touches[0].clientX;
         initialY = e.touches[0].clientY;
       };     

       const moveTouch = (e) =&amp;gt; {
         if (initialX === null) {
           return;
         } 

         if (initialY === null) {
           return;
         }  

         let currentX = e.touches[0].clientX;
         let currentY = e.touches[0].clientY;    
         let diffX = initialX - currentX;
         let diffY = initialY - currentY;

         if (Math.abs(diffX) &amp;gt; Math.abs(diffY)) {
           if (diffX &amp;gt; 0) {
            this.activateSlide(this.activeId + 1)
           } else {
            this.activateSlide(this.activeId - 1)
           }  
         } 

         initialX = null;
         initialY = null;

         e.preventDefault();
       };

       this.$slider.addEventListener("touchstart", startTouch, false);
       this.$slider.addEventListener("touchmove", moveTouch, false);
  }

}


})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;USAGE&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const slider = new Myslider("[data-myslider-container='sliderID']", {
  slides: 3,
  responsive: [
    {
      width: 992,
      slides: 2
    },
    {
      width: 480,
      slides: 1
    }
  ]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>javascript</category>
    </item>
    <item>
      <title>[html js] Tabs content toggle</title>
      <dc:creator>ktr92</dc:creator>
      <pubDate>Fri, 09 Feb 2024 11:36:10 +0000</pubDate>
      <link>https://dev.to/ktrblog/html-js-tabs-content-toggle-39nc</link>
      <guid>https://dev.to/ktrblog/html-js-tabs-content-toggle-39nc</guid>
      <description>&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div data-tabs="tabs"&amp;gt;
    &amp;lt;div class="tabs__nav" data-headertabs="tabs_id"&amp;gt;
        &amp;lt;ul&amp;gt;
            &amp;lt;li class="active"&amp;gt;1&amp;lt;/li&amp;gt;
            &amp;lt;li class=""&amp;gt;2&amp;lt;/li&amp;gt;
        &amp;lt;/ul&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;div class="tabs__wrapper" data-tabswrapper="tabs_id"&amp;gt;
        &amp;lt;div class="tabs__content active" data-contenttabs="tabs_id"&amp;gt;
            1
        &amp;lt;/div&amp;gt;
        &amp;lt;div class="tabs__content " data-contenttabs="tabs_id"&amp;gt;
            2
        &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;document.querySelector('[data-headertabs]').addEventListener('click', function(e) {
    const el = e.target
    if (el.tagName === 'LI') {
        if (!el.classList.contains('active')) {
            let index = Array.from(el.parentNode.children).indexOf(el)

            document.querySelectorAll('[data-headertabs] li').forEach(item =&amp;gt; {
                item.classList.remove('active')
            })
            el.classList.add('active')

            document.querySelectorAll('[data-contenttabs]').forEach(item =&amp;gt; {
                item.classList.remove('active')
            })
            const items = Array.from(document.querySelector('[data-tabswrapper]').children)
            items[index].classList.add('active')
        }
    }
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[data-contenttabs] {
  display: none; 
}

[data-contenttabs].active {
  display: block; 
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>javascript</category>
    </item>
    <item>
      <title>[jquery] The most simple universal accordion</title>
      <dc:creator>ktr92</dc:creator>
      <pubDate>Tue, 05 Sep 2023 09:06:17 +0000</pubDate>
      <link>https://dev.to/ktrblog/jquery-the-most-simple-universal-accordion-2296</link>
      <guid>https://dev.to/ktrblog/jquery-the-most-simple-universal-accordion-2296</guid>
      <description>&lt;p&gt;DEMO - &lt;a href="https://codepen.io/ktr92/pen/zYyoYeW"&gt;https://codepen.io/ktr92/pen/zYyoYeW&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;HTML&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div class='accordion_title' data-accordiontitle='accordion1'&amp;gt;
  Title 1
&amp;lt;/div&amp;gt;
&amp;lt;div class='accordion_content' data-accordioncontent='accordion1'&amp;gt;
  Content 1
&amp;lt;/div&amp;gt;

&amp;lt;div class='accordion_title' data-accordiontitle='accordion2'&amp;gt;
  Title 2
&amp;lt;/div&amp;gt;
&amp;lt;div class='accordion_content' data-accordioncontent='accordion2'&amp;gt;
  Content 2
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;CSS&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[data-accordioncontent] {
  display: none;
}

[data-accordiontitle] {
  position: relative;
  display: block; 
  cursor: pointer;
}
[data-accordiontitle]:after {
  content: "+";
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  right: 10px;
  display: inline-block;
  vertical-align: middle;
  width: 30px;
  height: 30px;
  text-align: center;
  color: #fff;
  line-height: 30px;
  font-size: 20px;
  font-weight: 700;
  margin-right: 5px;
  background-color: #c9c9c9;
  border-radius: 50%;
  -webkit-transition: all 0.2s ease-out;
  transition: all 0.2s ease-out;
}
[data-accordiontitle].active:after {
  content: "-";
}

[data-accordioncontent] {
  padding: 20px;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;JS&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$("[data-accordiontitle]").on("click", function () {
  let accordion = $(this).data("accordiontitle");
  $(`[data-accordioncontent="${accordion}"`).slideToggle();
  $(this).toggleClass("active");
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>jquery</category>
      <category>css</category>
      <category>html</category>
    </item>
    <item>
      <title>[vue3 ts tailwind] Simple reusable Button component example</title>
      <dc:creator>ktr92</dc:creator>
      <pubDate>Tue, 09 May 2023 08:19:08 +0000</pubDate>
      <link>https://dev.to/ktrblog/vue3-ts-tailwind-simple-reusable-button-component-example-not-packaged-31m5</link>
      <guid>https://dev.to/ktrblog/vue3-ts-tailwind-simple-reusable-button-component-example-not-packaged-31m5</guid>
      <description>&lt;p&gt;&lt;code&gt;/components/UI/Button.vue&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;button
    @click.prevent="onClick"
    :disabled="props.disabled"
    :class="classes"
    class="
      text-white
      bg-green
      hover:bg-blue-800
      focus:ring-4
      focus:outline-none
      font-medium
      px-5
      py-4
      text-md text-center
      cursor-pointer
      whitespace-nowrap
    "
  &amp;gt;
    &amp;lt;slot&amp;gt;&amp;lt;/slot&amp;gt;
  &amp;lt;/button&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script setup lang="ts"&amp;gt;
const props = defineProps({
  disabled: {
    type: Boolean,
    default: false,
  },
  size: {
    type: String,
    default: "md",
  },
  liquid: {
    type: Boolean,
    default: false,
  },
  rounded: {
    type: Boolean,
    default: false,
  },
})

const emits = defineEmits(["onclick"])

enum ButtonSizes {
  "xs" = "px-[10px] py-[6px]",
  "sm" = "px-[15px] py-[10px]",
  "md" = "py-3 px-3",
  "lg" = "px-12 py-3",
}

enum TextSizes {
  "xs" = "text-xs",
  "sm" = "text-sm",
  "md" = "text-md",
  "lg" = "text-lg",
}

const paddingClasses = computed(() =&amp;gt; {
  return ButtonSizes[props.size as keyof typeof ButtonSizes]
})

const textClass = computed(() =&amp;gt; {
  return TextSizes[props.size as keyof typeof ButtonSizes]
})
const widthClass = computed(() =&amp;gt; {
  return props.liquid ? "w-full" : "w-min"
})
const roundedClass = computed(() =&amp;gt; {
  return props.rounded ? "rounded-md" : ""
})

const classes = computed(
  () =&amp;gt;
    `${paddingClasses.value} ${textClass.value} ${widthClass.value} ${roundedClass.value}`
)

const onClick = (event: Event) =&amp;gt; {
  emits("onclick", event)
}
&amp;lt;/script&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Usage:
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;UIButton
  @onclick="$emit('dosomething')"
  size="lg"
  :liquid="false"
  :rounded="true"
 &amp;gt;
   Do something
&amp;lt;/UIButton&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>vue</category>
      <category>typescript</category>
      <category>tailwindcss</category>
    </item>
    <item>
      <title>[vue3] Why is the length of a reactive Array always undefined?</title>
      <dc:creator>ktr92</dc:creator>
      <pubDate>Sun, 07 May 2023 18:32:21 +0000</pubDate>
      <link>https://dev.to/ktrblog/vue3-why-is-the-length-of-a-reactive-array-always-undefined-30m9</link>
      <guid>https://dev.to/ktrblog/vue3-why-is-the-length-of-a-reactive-array-always-undefined-30m9</guid>
      <description>&lt;p&gt;I once spent a lot of time due to my superficial knowledge of Vue reactivity. I saw it very clearly and simply, but I never really thought about how it works.&lt;/p&gt;

&lt;p&gt;For example, we have an empty &lt;strong&gt;array of strings&lt;/strong&gt; that will be filled after user actions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const inputData = ref&amp;lt;string[]&amp;gt;([])
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;You'll always use ref() for primitives, but ref() is good for objects that need to be reassigned, like an array.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After the user's action and filling the array, we need to show him some information in the template, but before that it was hidden. So we add a computed property to keep track of the length of the array.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const inputLength = computed(() =&amp;gt; {
  return inputData.value.length
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;template v-if="inputLength "&amp;gt;
 some information
&amp;lt;/template&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt;&lt;br&gt;
At first glance this seems correct (to me), but it doesn't work because since we're using &lt;code&gt;ref&lt;/code&gt;, our &lt;code&gt;inputData&lt;/code&gt; is not an array of strings, but a &lt;strong&gt;ref object&lt;/strong&gt; that has one property &lt;strong&gt;value&lt;/strong&gt;. And &lt;code&gt;inputData.value&lt;/code&gt; is also not an array of strings, but a &lt;strong&gt;proxy object&lt;/strong&gt;.&lt;br&gt;
So our inputLength computed property is always &lt;em&gt;undefined&lt;/em&gt;.&lt;br&gt;
For a long time I could not understand what was wrong here.&lt;/p&gt;

&lt;p&gt;All we need to do is use &lt;code&gt;Object.keys&lt;/code&gt; and get the number of keys of the proxy object.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const inputLength = computed(() =&amp;gt; {
  return Object.keys(inputData.value).length
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>vue</category>
    </item>
    <item>
      <title>[html scss] Reusable SCSS mixin for screen-scalable responsive design</title>
      <dc:creator>ktr92</dc:creator>
      <pubDate>Fri, 28 Apr 2023 20:13:05 +0000</pubDate>
      <link>https://dev.to/ktrblog/html-scss-reusable-scss-mixin-for-screen-scalable-responsive-design-28d1</link>
      <guid>https://dev.to/ktrblog/html-scss-reusable-scss-mixin-for-screen-scalable-responsive-design-28d1</guid>
      <description>&lt;p&gt;There is a design in Figma (or Photoshop) with 3 layouts for each page (desktop 1920, tablet 834 and mobile 320).&lt;br&gt;
We have to do pixel-perfect HTML coding by represented layouts for respective screen sizes, and  scalable responsive design for intermediate screen sizes, which keep the design while next layout breakpoint. &lt;br&gt;
That is, our result must be the same as our design on 1920px, and keep this view until 834px reducing proportionally.&lt;/p&gt;

&lt;p&gt;This task can be done in several ways, but I want to get the styles directly from Figma into &lt;code&gt;px&lt;/code&gt; without manual conversions. But screen-scaling design must be made on &lt;code&gt;vw&lt;/code&gt;...&lt;/p&gt;

&lt;p&gt;There is a solution. The idea is very simple. Really you don't have to ponder about scaling design. It might be solved by simple SCSS function which will be calculate scaling automatically. &lt;/p&gt;

&lt;p&gt;First, we need to declare 3 functions for converting  pixels measure to &lt;code&gt;vw&lt;/code&gt; measure (for desktop, tablet, and mobile). &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🔥 codepen &lt;a href="https://codepen.io/ktr92/pen/gOBxbZb"&gt;https://codepen.io/ktr92/pen/gOBxbZb&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SCSS&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@function get_vw_large($value) {
    $vw-viewport-large: 1920; // there is design breakpoint for desktop screen view
    $vw-context: $vw-viewport-large * 0.01 * 1px;
    @return $value/ $vw-context * 1vw;
    @return $value;
}

@function get_vw_medium($value) {
    $vw-viewport-medium: 834; // there is design breakpoint for tablet screen view
    $vw-context: $vw-viewport-medium * 0.01 * 1px;
    @return $value/ $vw-context * 1vw;
    @return $value;
}

@function get_vw_small($value) {
    $vw-viewport-small: 834; // there is design breakpoint for mobile screen view
    $vw-context: $vw-viewport-small * 0.01 * 1px;
    @return $value/ $vw-context * 1vw;
    @return $value;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we can use it!&lt;/p&gt;

&lt;p&gt;Throughout the project we need wrap all PIXEL-based styles on a function.&lt;br&gt;
For example, we have a block with the following styles (from Figma desing):&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CSS:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.block{ 
  font-size: 18px;
  line-height: 23px;
  margin-bottom: 2px;
  padding: 20px;
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It must be rewritten in the following way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.block {
  font-size: get_vw_large(28px);
  line-height: get_vw_large(33px);
  margin-bottom: get_vw_large(42px);
  padding: get_vw_large(20px);
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So it will be converted to &lt;code&gt;vw&lt;/code&gt; value and we will see the following styles in a browser:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    font-size: 0.9375vw;
    line-height: 1.19792vw;
    margin-bottom: 0.10417vw;
    padding: 1.0416666667vw;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🔥We can use any breakpoints for @media queries, but our result will be perfect on the each design breakpoint (1920, 834, 320). For tablet breakpoint it must be rewritten in the following way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@media (max-width: 1023px) {
  .block {
    font-size: get_vw_medium(18px);
    line-height: get_vw_medium(23px);
    margin-bottom: get_vw_medium(20px);
    padding: get_vw_medium(20px);
  }
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the mobile breakpoint it has the following styles (from Figma desing):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.block{ 
  font-size: 14px;
  line-height: 18px;
  margin-bottom: 20px;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It must be rewritten in the following way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
@media (max-width: 480px) {
  .block {
    font-size: get_vw_small(13px);
    line-height: get_vw_small(18px);
    margin-bottom: get_vw_small(20px);
    padding: get_vw_small(20px);
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>css</category>
      <category>scss</category>
      <category>mobile</category>
    </item>
    <item>
      <title>[html css jquery] Mobile menu + button change from burger to close + close on backdrop click</title>
      <dc:creator>ktr92</dc:creator>
      <pubDate>Fri, 28 Apr 2023 14:00:38 +0000</pubDate>
      <link>https://dev.to/ktrblog/html-css-jquery-mobile-menu-button-change-from-burger-to-close-close-on-backdrop-click-2ac7</link>
      <guid>https://dev.to/ktrblog/html-css-jquery-mobile-menu-button-change-from-burger-to-close-close-on-backdrop-click-2ac7</guid>
      <description>&lt;p&gt;Here is the basis for creating a menu with a hamburger button that changes to close when the menu is open. In addition, there is a background on top of the content. You can close the menu by clicking on the background.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;codepen example&lt;/strong&gt;: &lt;a href="https://codepen.io/ktr92/pen/gOBRyKO"&gt;https://codepen.io/ktr92/pen/gOBRyKO&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HTML&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div class="jsbackdrop"&amp;gt;&amp;lt;/div&amp;gt;

&amp;lt;div class="container"&amp;gt;
  &amp;lt;header class="header"&amp;gt;
    &amp;lt;div class="flex items-center space-between w-full"&amp;gt;
      &amp;lt;div class="headercontent"&amp;gt;HEADER&amp;lt;/div&amp;gt;
      &amp;lt;a href="#" class="menubtn" data-menutoggle="mainmenu"&amp;gt;
        &amp;lt;span&amp;gt;&amp;lt;/span&amp;gt;
        &amp;lt;span&amp;gt;&amp;lt;/span&amp;gt;
        &amp;lt;span&amp;gt;&amp;lt;/span&amp;gt;
      &amp;lt;/a&amp;gt;
    &amp;lt;/div&amp;gt;

    &amp;lt;div class="mainmenu" data-menu="mainmenu"&amp;gt;
      &amp;lt;div class="mainmenu__wrapper"&amp;gt;
        &amp;lt;div class="mainmenu__items"&amp;gt;
          &amp;lt;ul&amp;gt;
            &amp;lt;li class="active"&amp;gt;&amp;lt;a href="#"&amp;gt;Home&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
            &amp;lt;li&amp;gt;&amp;lt;a href="#"&amp;gt;Page 1&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
            &amp;lt;li&amp;gt;&amp;lt;a href="#"&amp;gt;Page 2&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
            &amp;lt;li&amp;gt;&amp;lt;a href="#"&amp;gt;Page 3&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
            &amp;lt;li&amp;gt;&amp;lt;a href="#"&amp;gt;Page 4&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
            &amp;lt;li&amp;gt;&amp;lt;a href="#"&amp;gt;Page 5&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
          &amp;lt;/ul&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/header&amp;gt;
  &amp;lt;main&amp;gt;
    content body
  &amp;lt;/main&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;CSS&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[data-menutoggle] {
  display: block;
  margin-left: 15px;
}

[data-menutoggle] span {
  width: 32px;
  height: 3px;
  margin-bottom: 5px;
  display: block;
  background: #324064;
  transform-origin: 4px 0px;
  transition: transform 0.3s cubic-bezier(0.77, 0.2, 0.05, 1),
    background 0.5s cubic-bezier(0.77, 0.2, 0.05, 1), opacity 0.55s ease;

  &amp;amp;:last-child {
    margin-bottom: 0;
  }
}

[data-menutoggle] span:first-child {
  transform-origin: 0% 0%;
}

[data-menutoggle] span:last-child {
  transform-origin: 0% 100%;
}

[data-menutoggle].active span:first-child {
  opacity: 1;
  transform: translate(0, 18px) rotate(-45deg);
}

[data-menutoggle].active span:last-child {
  transform: translate(0, -21px) rotate(45deg);
}

[data-menutoggle].active span:nth-child(2) {
  opacity: 0;
}
[data-menu] {
  display: none;
}
[data-menu].active {
  display: block;
}

.jsbackdrop {
  background: rgba(52, 60, 75, 0.5);
  display: none;
  position: fixed;
  z-index: 9;
  height: 100%;
  min-height: 100vh;
  left: 0;
  top: 0;
  width: 100%;
}

.jsbackdrop.active {
  display: block;
}
.mainmenu {
  width: 100%;
  position: absolute;
  background: #fff;
  z-index: 99;
  left: 0;
  padding: 10px;
  top: 100%;
}
.mainmenu li {
  list-style: none;
  margin-bottom: 5px;
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;JS[jquery]&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$("[data-menutoggle]").on("click", function (e) {
  e.preventDefault();
  let menu = $(this).data("menutoggle");
  $(`[data-menu=${menu}]`).toggleClass("active");
  $(this).toggleClass("active");
  $(".jsbackdrop").toggleClass("active");
});
$(".jsbackdrop").on("click", function (e) {
  $(this).removeClass("active");
  $("[data-menu]").removeClass("active");
  $("[data-menutoggle]").removeClass("active");
});

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
    <item>
      <title>[html css js] Show/hide password input value</title>
      <dc:creator>ktr92</dc:creator>
      <pubDate>Wed, 26 Apr 2023 20:17:46 +0000</pubDate>
      <link>https://dev.to/ktrblog/html-css-js-showhide-password-input-value-18b6</link>
      <guid>https://dev.to/ktrblog/html-css-js-showhide-password-input-value-18b6</guid>
      <description>&lt;p&gt;&lt;strong&gt;Codepen demo: &lt;a href="https://codepen.io/ktr92/pen/vYVmbam"&gt;https://codepen.io/ktr92/pen/vYVmbam&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution example:
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;HTML&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div class="inputpassword" data-toggleblock="password"&amp;gt;
  &amp;lt;input type="password"&amp;gt;
  &amp;lt;img src="https://ktr92.github.io/nft/dist/img/Invisible.svg" alt="" data-togglebutton="password" class="password_invisible"&amp;gt;
  &amp;lt;img src="https://ktr92.github.io/nft/dist/img/Eye2.svg" alt="" data-togglebutton="password" class="password_visible"&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;CSS&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.inputpassword {
  position: relative;
  width: 320px;
}

.password_visible {
  display: none;
}

.inputpassword.active .password_invisible {
  display: none;
}

.inputpassword.active .password_visible {
  display: block;
}

.inputpassword img {
  position: absolute;
  right: 0;
  top: 50%;
  cursor: pointer;
  transform: translateY(-50%);
}

input {
  background: #f3f5f8;
  padding: 20px;
  border-top-right-radius: 10px;
  border-top-left-radius: 10px;
  border: none;
  border-bottom: 4px solid #d9dde3;
  display: block;
  width: 100%;
  font-style: normal;
  font-weight: 500;
  font-size: 20px;
  line-height: 1;
  resize: none;
  color: #212531;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;JS&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;document.querySelectorAll('[data-togglebutton="password"]').forEach((item) =&amp;gt; {
  item.addEventListener("click", (event) =&amp;gt; {
    let inp = item.closest("[data-toggleblock]").querySelector("input");
    if (inp.type === "password") {
      inp.type = "text";
      item.closest("[data-toggleblock]").classList.add("active");
    } else {
      inp.type = "password";
      item.closest("[data-toggleblock]").classList.remove("active");
    }
  });
});

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>html</category>
      <category>css</category>
      <category>javascript</category>
    </item>
    <item>
      <title>[html css jquery] Reusable script for dropdown elements</title>
      <dc:creator>ktr92</dc:creator>
      <pubDate>Wed, 26 Apr 2023 20:04:04 +0000</pubDate>
      <link>https://dev.to/ktrblog/html-css-jquery-reusable-jquery-script-for-dropdown-elements-1kfi</link>
      <guid>https://dev.to/ktrblog/html-css-jquery-reusable-jquery-script-for-dropdown-elements-1kfi</guid>
      <description>&lt;p&gt;Here is reusable jquery script for dropdown elements. You can keep every dropdown open at the same time or hide all other dropdowns when you open one.&lt;/p&gt;

&lt;p&gt;You can add a new dropdown element declaratively via html. You need to add the attribute &lt;code&gt;data-toggleclick="some-id"&lt;/code&gt; for a button and &lt;code&gt;data-toggleblock="some-id"&lt;/code&gt; for a dropdown block.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;codepen demo: &lt;a href="https://codepen.io/ktr92/pen/LYgyqZE"&gt;https://codepen.io/ktr92/pen/LYgyqZE&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution example
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;HTML&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div&amp;gt;
  &amp;lt;div class="wrapper"&amp;gt;
    &amp;lt;button data-toggleclick="block1"&amp;gt;Open block 1&amp;lt;/button&amp;gt;
    &amp;lt;div data-toggleblock="block1"&amp;gt;
      Block 1 
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;div class="wrapper"&amp;gt;
    &amp;lt;button data-toggleclick="block2" &amp;gt;Open block 2&amp;lt;/button&amp;gt;
    &amp;lt;div data-toggleblock="block2"&amp;gt;
      Block 2
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;CSS&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[data-toggleblock] {
  display: none;
}

[data-toggleblock].active {
  display: block;
}

.container {
  width: 320px;
}

.wrapper {
  height: 100px;
  position: relative;
  width: 320px;
}
[data-toggleblock] {
  padding: 10px;
  border: 1px solid #000;
  margin-bottom: 30px;
  position: absolute;
  top: 50px;
  width: 100%;
  z-index: 1;
}
[data-toggleclick] {
  background: #ccc;
  padding: 10px 10px;
  border: none;
  display: block;
  width: 100%;
  font-size: 20px;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;JS (jquery)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// show element by click on button 
$('[data-toggleclick]').each(function() {
  $(this).on('click', function(e) {
        $(this).toggleClass('active')
        e.preventDefault()
        let dropdown = $(this).data('toggleclick')
        // if you want to hide all other dropdowns
        // $('[data-toggleblock].active').not($(`[data-toggle=${dropdown}]`)).removeClass('active')
        // $('[data-toggleclick].active').not($(`[data-toggleclick=${dropdown}]`)).removeClass('active')
        $(`[data-toggleblock=${dropdown}]`).toggleClass('active')
  })
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
    <item>
      <title>[html css jquery] How to hide element by click outside</title>
      <dc:creator>ktr92</dc:creator>
      <pubDate>Wed, 26 Apr 2023 19:10:52 +0000</pubDate>
      <link>https://dev.to/ktrblog/html-css-js-how-to-hide-element-by-click-outside-8bk</link>
      <guid>https://dev.to/ktrblog/html-css-js-how-to-hide-element-by-click-outside-8bk</guid>
      <description>&lt;p&gt;There is an element which we need to close by click outside of it. We can do it using simple reusable function.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;codepen demo&lt;/strong&gt;: &lt;a href="https://codepen.io/ktr92/pen/LYgyGaY"&gt;https://codepen.io/ktr92/pen/LYgyGaY&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution example
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;HTML&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div&amp;gt;
  &amp;lt;button data-toggleclick="block1"&amp;gt;Open block 1&amp;lt;/button&amp;gt;
  &amp;lt;div data-toggleblock="block1" class="active"&amp;gt;
     Click outside to close
  &amp;lt;/div&amp;gt;
  &amp;lt;div&amp;gt;
    &amp;lt;br&amp;gt;&amp;lt;br&amp;gt;
  &amp;lt;button data-toggleclick="block2" &amp;gt;Open block 2&amp;lt;/button&amp;gt;
    &amp;lt;div data-toggleblock="block2"  class="active"&amp;gt;
      Click outside to close
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;CSS&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[data-toggleblock] {
  display: none;
}

[data-toggleblock].active {
  display: block;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;JS (jquery)&lt;/strong&gt;&lt;br&gt;
We need a second argument (our element's open button) to prevent the element from opening and closing at the same time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function closeByClickOutside(element, button, callback) {
    $(document).click(function(event) {
        if (!$(event.target).closest(`${element},${button}`).length) {
            $(button).removeClass('active')
            $(element).removeClass('active')
            // or  
            //$(element).hide()
        }
    });

    $(document).keyup(function(e) {
        if (e.key === "Escape") { // escape key maps to keycode `27`
            $(button).removeClass('active')
            $(element).removeClass('active')
            // or  
            //$(element).hide()
        }
    });

    if (callback instanceof Function) { callback(); }
  }

// usage
closeByClickOutside('[block_selector]', '[button_selector]')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>html</category>
      <category>css</category>
      <category>jquery</category>
    </item>
  </channel>
</rss>
