<?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: JS Bits Bill</title>
    <description>The latest articles on DEV Community by JS Bits Bill (@js_bits_bill).</description>
    <link>https://dev.to/js_bits_bill</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%2F226642%2F12db3c79-aafb-40ea-9dab-b98bce5eb6af.jpg</url>
      <title>DEV Community: JS Bits Bill</title>
      <link>https://dev.to/js_bits_bill</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/js_bits_bill"/>
    <language>en</language>
    <item>
      <title>Ad-Free YouTube With a Custom Player</title>
      <dc:creator>JS Bits Bill</dc:creator>
      <pubDate>Thu, 02 Apr 2026 03:03:36 +0000</pubDate>
      <link>https://dev.to/js_bits_bill/ad-free-youtube-with-a-custom-player-3e7h</link>
      <guid>https://dev.to/js_bits_bill/ad-free-youtube-with-a-custom-player-3e7h</guid>
      <description>&lt;p&gt;As enshittification marches on, more ads, more dark patterns, more UI designed to serve the platform instead of the user, I've found myself writing more and more userscripts to just take back control of my own browser.&lt;/p&gt;

&lt;p&gt;The web is full of it these days. Search results that bury the actual answer under AI summaries and SEO slop, cookie banners engineered to trick you into opting in, UI patterns designed to get you to click something you never intended to. I've just started writing small scripts to deal with it, nothing fancy, just enough JS to sand off the rough edges of whatever site is annoying me that week.&lt;/p&gt;

&lt;p&gt;YouTube has been one of the worst offenders. Pre-roll ads, mid-roll interruptions, recommended video overlays hijacking your screen the second a video ends. But it turns out YouTube's own embed URL has a lesser-known cousin that makes most of this go away: &lt;code&gt;youtube-nocookie.com&lt;/code&gt;. It's their own domain, built for privacy-respecting embeds and as a side effect, &lt;strong&gt;it serves no ads&lt;/strong&gt;. 🎉&lt;/p&gt;

&lt;p&gt;The script intercepts any &lt;code&gt;youtube.com/watch?v=VIDEO_ID&lt;/code&gt; link and reconstructs it as a &lt;code&gt;yout-ube.com/watch?v=VIDEO_ID&lt;/code&gt; URL, opening it in a new tab. &lt;code&gt;yout-ube.com&lt;/code&gt; is a third-party pass-through that rewrites the request and loads it via &lt;code&gt;youtube-nocookie.com/embed&lt;/code&gt; with the right HTTP Referer context intact. That Referer is what matters — if you navigate directly to a nocookie embed URL or just hit refresh, YouTube throws an Error 153 and kills playback entirely. The &lt;code&gt;yout-ube.com&lt;/code&gt; hop is what keeps everything happy.&lt;/p&gt;

&lt;p&gt;From there a second script runs on the nocookie domain to enhance the player. You get the full video, zero ads. Just the video. It sounds simple because it should have always been this way.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzf7v6fhvxztwwk9wt7hw.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzf7v6fhvxztwwk9wt7hw.webp" alt="YouTube No Cookie Player" width="800" height="433"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The custom player on youtube-nocookie.com — comments panel open, like/dislike ratio bar, clean controls, zero ads.&lt;/em&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  What It Does
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Speed hold&lt;/strong&gt;: hold the mouse button over the video to speed it up. Upper half = 2x, lower half = 3x. Release to snap back to 1x. No UI, no buttons, just muscle memory.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Double-click fullscreen&lt;/strong&gt;: YouTube's overlay swallows the native &lt;code&gt;dblclick&lt;/code&gt; event so I track clicks manually. Two clicks within 300ms over the video area toggles fullscreen.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Comments panel&lt;/strong&gt;: a collapsible panel at the bottom of the player that pulls comments via the YouTube Data API v3. Top or New sort, like counts, timestamps, and a like/dislike ratio bar.&lt;/p&gt;


&lt;h2&gt;
  
  
  UI Cleanup
&lt;/h2&gt;

&lt;p&gt;The nocookie player still renders some unwanted elements, a "watch on YouTube" button, a fullscreen recommendations overlay, the loop icon. All of it gets nuked with CSS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;player-fullscreen-action-menu&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
&lt;span class="nc"&gt;.ytp-pause-overlay-container&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
&lt;span class="nc"&gt;.watch-on-youtube-button-wrapper&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
&lt;span class="nc"&gt;.ytFullscreenVideoRecommendationsHost&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt; &lt;span class="cp"&gt;!important&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Volume, CC, and settings buttons get relocated to a custom bottom bar to keep things tidy.&lt;/p&gt;

&lt;p&gt;The web is still a hackable place. The browser is still yours. A little JS goes a long way. 🛠️&lt;/p&gt;




&lt;h2&gt;
  
  
  Set It Up Yourself
&lt;/h2&gt;

&lt;p&gt;I put together a short video walkthrough of the full setup if you'd rather just follow along: &lt;a href="https://streamable.com/ry74kw" rel="noopener noreferrer"&gt;https://streamable.com/ry74kw&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Full written instructions including both scripts and the API key setup are over on my &lt;a href="https://gist.github.com/JSBitsYo/97eded7d320ac3521533763eb8357aaa" rel="noopener noreferrer"&gt;GitHub Gist&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>youtube</category>
      <category>javascript</category>
      <category>extensions</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Adding Emoji Search to Google Messages for Web</title>
      <dc:creator>JS Bits Bill</dc:creator>
      <pubDate>Sun, 25 Jan 2026 22:44:59 +0000</pubDate>
      <link>https://dev.to/js_bits_bill/adding-emoji-search-to-google-messages-for-web-7f5</link>
      <guid>https://dev.to/js_bits_bill/adding-emoji-search-to-google-messages-for-web-7f5</guid>
      <description>&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;If you've ever used &lt;a href="https://messages.google.com/web" rel="noopener noreferrer"&gt;Google Messages for Web&lt;/a&gt;, you know the pain: you want to send a particular emoji, but instead of searching for it, you're stuck scrolling through endless categories hoping to find the right one. It's 2026, this SO shouldn't be a thing!&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Messages for Web Emoji Search&lt;/strong&gt; adds keyboard-friendly emoji search directly into the UI where you can type what you want and get instant results. IMO, this is way easier than browsing annoying "categories" or having to endlessly scroll just to find the clown emoji.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpcas4jw2ba3pu0bnqf26.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpcas4jw2ba3pu0bnqf26.png" alt="Messages for Web Emoji Search" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How It Works
&lt;/h2&gt;

&lt;p&gt;The extension uses a &lt;code&gt;MutationObserver&lt;/code&gt; to watch for when the emoji picker appears and injects a search input at the top:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;observer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MutationObserver&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;mutations&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mutation&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;mutations&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;mutation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addedNodes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nodeType&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ELEMENT_NODE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pickerClass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;emoji-picker-content-wrapper&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;picker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pickerClass&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt;
          &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;?.(&lt;/span&gt;&lt;span class="s2"&gt;`.&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;pickerClass&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;picker&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;injectIntoEmojiPicker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;picker&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;observe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;childList&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;subtree&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once detected, it injects a custom search interface with autocomplete that filters through a database of emojis by name &lt;strong&gt;and&lt;/strong&gt; keywords. Looking for "skull"? You'll get 💀 Skull, ☠️ Skull and Crossbones, 🏴‍☠️ Pirate Flag, and more.&lt;/p&gt;

&lt;p&gt;When you select an emoji, it gets inserted directly into your message input at the cursor position, just like the native picker.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try It Out
&lt;/h2&gt;

&lt;p&gt;The extension is live on the Chrome Web Store and the code is open source:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Chrome Extension&lt;/strong&gt;: &lt;a href="https://chromewebstore.google.com/detail/messages-for-web-emoji-se/ihgbgoclaogjailgdkpejeebemeibjnm" rel="noopener noreferrer"&gt;https://chromewebstore.google.com/detail/messages-for-web-emoji-se/ihgbgoclaogjailgdkpejeebemeibjnm&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub&lt;/strong&gt;: &lt;a href="https://github.com/doctafaustus/messages-for-web-emoji-search" rel="noopener noreferrer"&gt;https://github.com/doctafaustus/messages-for-web-emoji-search&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The extension is still in beta, but feel free to give it a spin 🙃.&lt;/p&gt;

</description>
      <category>extensions</category>
      <category>gripe</category>
      <category>productivity</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Simplify Shadow DOM with setHTMLUnsafe</title>
      <dc:creator>JS Bits Bill</dc:creator>
      <pubDate>Fri, 03 May 2024 21:52:06 +0000</pubDate>
      <link>https://dev.to/js_bits_bill/simplify-shadow-dom-with-sethtmlunsafe-1fne</link>
      <guid>https://dev.to/js_bits_bill/simplify-shadow-dom-with-sethtmlunsafe-1fne</guid>
      <description>&lt;p&gt;It's typical for Web developers to create encapsulated DOM elements in order to isolate both styles and functionality within a component. To achieve this, the &lt;code&gt;element.attachShadow&lt;/code&gt; method is used to create a shadow DOM: a hidden subtree attached to an element. While powerful, it can be somewhat verbose and complex to set up:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sectionElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;section&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;shadowTemplate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;template&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;shadowTemplate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
  &amp;lt;style&amp;gt;
    /* Shadow styles applied only within the shadow DOM */
    h2 { color: blue; }
  &amp;lt;/style&amp;gt;
  &amp;lt;h2&amp;gt;Shadow Content&amp;lt;/h2&amp;gt;
`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;shadowTemplate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;shadowRootMode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;open&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;shadowHost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;shadowRoot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;shadowHost&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;attachShadow&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;open&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;shadowRoot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;shadowTemplate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cloneNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nx"&gt;sectionElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;shadowHost&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;sectionElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insertAdjacentHTML&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;beforeend&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`
  &amp;lt;h2&amp;gt;Light Content&amp;lt;/h2&amp;gt;
`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This produces the following rendered HTML:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzy91xhq6vt9469s73n17.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzy91xhq6vt9469s73n17.png" alt=" " width="640" height="276"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice how we must create the shadow DOM using the &lt;code&gt;.attachShadow&lt;/code&gt; method first and &lt;b&gt;then&lt;/b&gt; we can access the shadow root and use &lt;code&gt;.innerHTML&lt;/code&gt; to populate the content.&lt;/p&gt;

&lt;p&gt;Also note how &lt;code&gt;.innerHTML&lt;/code&gt; cannot be used to directly create this output. This method is not designed to understand shadow elements within the template. Further, it also prevents this content from rendering due to a browser security restriction. If user-generated content is inserted with &lt;code&gt;.innerHTML&lt;/code&gt;, it could contain malicious scripts that execute within your page. Shadow DOM creates a separate DOM tree that prevents styles and scripts from leaking into the main page.&lt;/p&gt;

&lt;p&gt;However, if we understand and accept the security implications, we can take advantage of the new &lt;code&gt;setHTMLUnsafe&lt;/code&gt; method to directly set HTML content, including shadow DOM declarations, bypassing the need for separate shadow DOM attachment methods like &lt;code&gt;.attachShadow&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;section&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;setHTMLUnsafe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`
  &amp;lt;div&amp;gt;
    &amp;lt;template shadowrootmode="open"&amp;gt;
      &amp;lt;style&amp;gt;
        /* Shadow styles applied only within the shadow DOM */
        h2 { color: blue; }
      &amp;lt;/style&amp;gt;
      &amp;lt;h2&amp;gt;Shadow Content&amp;lt;/h2&amp;gt;
    &amp;lt;/template&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;h2&amp;gt;Light Content&amp;lt;/h2&amp;gt;
`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With &lt;code&gt;setHTMLUnsafe&lt;/code&gt;, you don't need to manage separate template elements, shadow hosts, or shadow roots manually. This can reduce the complexity of your codebase and make it easier to maintain, especially in larger projects where encapsulation of DOM elements is a common practice.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;setHTMLUnsafe&lt;/code&gt; is available now in Chrome 124 (and supported in Edge, Safari, and Firefox).&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Journey into the Minification Abyss: The Peculiar '0' Placeholder</title>
      <dc:creator>JS Bits Bill</dc:creator>
      <pubDate>Mon, 12 Jun 2023 15:21:48 +0000</pubDate>
      <link>https://dev.to/js_bits_bill/journey-into-the-minification-abyss-the-peculiar-0-placeholder-70j</link>
      <guid>https://dev.to/js_bits_bill/journey-into-the-minification-abyss-the-peculiar-0-placeholder-70j</guid>
      <description>&lt;p&gt;In transpiled code, you'll often notice a pattern that looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;p&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;dangerouslySetInnerHTML&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;__html&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sanitize&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;desc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// What's the 0?&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;__self&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;__source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;lineNumber&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;328&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;columnNumber&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;13&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the line &lt;code&gt;__html: (0, $.sanitize)(n.desc)&lt;/code&gt;, we see 2 curious things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Why do the parens in &lt;code&gt;(0, $.sanitize)&lt;/code&gt; have two expressions?&lt;/li&gt;
&lt;li&gt;Why is there a seemingly useless number &lt;code&gt;0&lt;/code&gt; present?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's explain:&lt;br&gt;
&lt;code&gt;(0, $.sanitize)(n.desc)&lt;/code&gt; simply calls &lt;code&gt;$.sanitize&lt;/code&gt; with &lt;code&gt;n.desc&lt;/code&gt; as an argument. In other words, this is the same as:   &lt;code&gt;$.sanitize(n.desc)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Inside the parenthesis, the comma operator evaluates all expressions in sequence but only returns the value of the &lt;b&gt;last&lt;/b&gt; expression.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;b&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// returns 4&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So by adding the &lt;code&gt;0&lt;/code&gt; before the comma &lt;code&gt;,&lt;/code&gt; in &lt;code&gt;(0, $.sanitize)(n.desc)&lt;/code&gt; the transpiler is using the comma operator to create an expression where the value &lt;code&gt;0&lt;/code&gt; is discarded (so it could technically be any other expression without side effects), but the function &lt;code&gt;$.sanitize&lt;/code&gt; is still executed. This ensures that the &lt;code&gt;$.sanitize&lt;/code&gt; function is treated as a &lt;b&gt;standalone expression&lt;/b&gt; and evaluated before the function call &lt;code&gt;(...)(...)&lt;/code&gt; is made. &lt;/p&gt;

&lt;p&gt;This pattern shows a specific transformation in the bundled output by ensuring the &lt;code&gt;fn&lt;/code&gt; in &lt;code&gt;(0, fn)(arg)&lt;/code&gt; is invoked with a &lt;code&gt;this&lt;/code&gt; value of &lt;code&gt;undefined&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use strict&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;spellbook&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Arcanum&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nf"&gt;enchant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;weapon&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Enchanting &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;weapon&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Will log "this" as {title: 'Arcanum', enchant: ƒ}&lt;/span&gt;
&lt;span class="nx"&gt;spellbook&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enchant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sword&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 

&lt;span class="c1"&gt;// Will log "this" as undefined&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;spellbook&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;enchant&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sword&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="cm"&gt;/* 
  Note that "this" will refer to the global object in
  non-strict mode or "undefined" in strict mode.
*/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This transformation ensures that exported functions are not called with a different &lt;code&gt;this&lt;/code&gt; context which will lead to incorrect function behavior. &lt;/p&gt;

&lt;p&gt;Even though not all functions will need to access &lt;code&gt;this&lt;/code&gt;, this transformation is applied regardless so the transpiler does not need to waste time analyzing wether or not the code accesses it.&lt;/p&gt;

&lt;p&gt;Instead of &lt;code&gt;(0, fn)(arg)&lt;/code&gt;, could we have called the function in this manner: &lt;code&gt;(fn)(arg)&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;No, because the the parentheses around &lt;code&gt;fn&lt;/code&gt; would be interpreted simply as a grouping operator rather than the comma operator, and it is the comma operator that triggers the behavior of calling the function without any specific context.&lt;/p&gt;

&lt;p&gt;I always believed the &lt;code&gt;0&lt;/code&gt; in these patterns was an index to another function in the code bundle, but it's not! It’s a transformation pattern used when exporting functions to ensure that they are not unintentionally bound to a different context. ✨&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Special thanks to user &lt;a href="https://dev.to/j4k0xb/comment/27b4b"&gt;j4k0xb&lt;/a&gt; and their very helpful explanation which prompted a better explanation on my part.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;b&gt;Yo!&lt;/b&gt; I post byte-sized tips like these often. Follow me if you crave more! 🍿 &lt;a href="https://jsbits-yo.com" rel="noopener noreferrer"&gt;JS Bits Blog&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
    </item>
    <item>
      <title>HTML &lt;portal&gt;: Chrome's weird navigational element</title>
      <dc:creator>JS Bits Bill</dc:creator>
      <pubDate>Fri, 17 Jun 2022 15:21:55 +0000</pubDate>
      <link>https://dev.to/js_bits_bill/html-chromes-weird-navigational-element-5b38</link>
      <guid>https://dev.to/js_bits_bill/html-chromes-weird-navigational-element-5b38</guid>
      <description>&lt;h2&gt;
  
  
  What's a Portal?
&lt;/h2&gt;

&lt;p&gt;You might have never heard of the HTML &lt;code&gt;&amp;lt;portal&amp;gt;&lt;/code&gt; element. It's an experimental feature since Chrome 75 (June, 2019) and its proposal is in the draft stages. But what is it exactly? Essentially the &lt;code&gt;&amp;lt;portal&amp;gt;&lt;/code&gt; is like a souped-up &lt;code&gt;&amp;lt;iframe&amp;gt;&lt;/code&gt; and includes the ability to seamlessly navigate into embedded content. &lt;/p&gt;

&lt;p&gt;Similar to an &lt;code&gt;&amp;lt;iframe&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;portal&amp;gt;&lt;/code&gt; includes a &lt;code&gt;src&lt;/code&gt; attribute which is the URL of the page you want to embed and the embedded content will look identical to an &lt;code&gt;&amp;lt;iframe&amp;gt;&lt;/code&gt;. The &lt;code&gt;&amp;lt;portal&amp;gt;&lt;/code&gt; is clickable but is not interactable since its purpose is to provide a smooth navigation into a prerended page - similar to the way most SPAs navigate. This differs from iframes which cannot immediately be navigated to without another request to the source. Clicking on a portal will navigate you right into all that content that's already loaded and rendered as the child inset of the parent document.&lt;/p&gt;

&lt;p&gt;What's cool about portals is that they can be cross-origin, meaning you can create a portal to a different domain from where you're embedded it. &lt;/p&gt;

&lt;h2&gt;
  
  
  How To Use
&lt;/h2&gt;

&lt;p&gt;So since portals are an experimental, we need to enable 2 flags in Chrome at &lt;code&gt;about://flags/#enable-portals&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🚩 Enable Portals&lt;/li&gt;
&lt;li&gt;🚩 Enable cross-origin Portals&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Chrome will prompt you to relaunch your Browser and after doing so, you should see the &lt;code&gt;HTMLPortalElement&lt;/code&gt; function available in your console:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fweb-dev.imgix.net%2Fimage%2Fadmin%2FaUrrqhzMxaEX865Fk5zX.png%3Fauto%3Dformat%26w%3D1252" class="article-body-image-wrapper"&gt;&lt;img width="800" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fweb-dev.imgix.net%2Fimage%2Fadmin%2FaUrrqhzMxaEX865Fk5zX.png%3Fauto%3Dformat%26w%3D1252" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So now let's create a basic portal! It's as easy as adding this HTML to your web page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;portal&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://theoatmeal.com"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/portal&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can add styles to this element to adjust height, width, etc. but in its raw form you'll see the webpage from The Oatmeal embedded. When you click the portal, you navigate instantly to the source page and should not notice the normal "blink" you'd otherwise get from visiting a new Web page. &lt;/p&gt;

&lt;h2&gt;
  
  
  Let's Get Fancy
&lt;/h2&gt;

&lt;p&gt;Here's a use case where we'll create a list of popular webcomics. Each block of content will show a preview image of the comic and when the user hovers over it our code will render a portal in place that can be clicked to navigate directly to the the webcomic's page:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fdoctafaustus%2Fhtml-portal%2Fblob%2Fpreview-gif%2Fchrome_1sXGgQBBtJ.gif%3Fraw%3Dtrue" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fdoctafaustus%2Fhtml-portal%2Fblob%2Fpreview-gif%2Fchrome_1sXGgQBBtJ.gif%3Fraw%3Dtrue" width="444" height="467"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First, the HTML:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;Best Webcomics&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;ol&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h3&amp;gt;&lt;/span&gt;The Oatmeal&lt;span class="nt"&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; 
      &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"comic-container"&lt;/span&gt;
      &lt;span class="na"&gt;data-src=&lt;/span&gt;&lt;span class="s"&gt;"https://theoatmeal.com/comics/forbidden_love"&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/forbidden_love_big.png"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"spinner"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/spinner.gif"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;portal&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/portal&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;

  &lt;span class="c"&gt;&amp;lt;!-- Repeat lis for other webcomics --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ol&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice we're using an empty &lt;code&gt;src&lt;/code&gt; for the portal. To avoid unnecessary loading, we'll set the source in JavaScript only when the user hovers over &lt;code&gt;.comic-container&lt;/code&gt; via the &lt;code&gt;mouseenter&lt;/code&gt; event. As the source is being loaded, we'll show the spinner overlay so there's user feedback to show something is loading. Once fully loaded (by listening to the &lt;code&gt;load&lt;/code&gt; event), we can display the portal over the existing image.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;blocks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.comic-container&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;blocks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;block&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;block&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mouseenter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;block&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hover&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;portal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;block&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;portal&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;block&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;portal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// Add "mouseleave" listener to reset classes&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;portals&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;portal&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;portals&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;portal&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;portal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;load&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;portal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;closest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.comic-container&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;matches&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.hover&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;portal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;show-portal&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; 
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From there, the user can click the portal and be instantly transported to the source page!&lt;/p&gt;

&lt;p&gt;The default click behavior on a portal can also be prevented if you wanted to create a fancy animation the on click event and then call &lt;code&gt;portal.activate()&lt;/code&gt; to activate the portal programmatically.&lt;/p&gt;

&lt;p&gt;See full code here: &lt;a href="https://github.com/doctafaustus/html-portal" rel="noopener noreferrer"&gt;https://github.com/doctafaustus/html-portal&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing Thoughts
&lt;/h2&gt;

&lt;p&gt;While portals give us a new way to preview and prerender pages, it's unclear if they'll ever be standard in browsers. My first thoughts about security were assuaged by reading that portals do not allow user interaction to channel through to the "portaled" document. Additionally, the embedded content will not have direct access to the host document. However, portals would still introduce yet another opportunity to create clever browser exploits, so a sound content security policy (CSP) would be recommended.&lt;/p&gt;

&lt;p&gt;Nevertheless, they're still pretty cool!&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqp3516kt8kpz9yj4vq9q.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqp3516kt8kpz9yj4vq9q.jpg" alt=" " width="540" height="407"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;b&gt;Yo!&lt;/b&gt; I post byte-sized tips like these often. Follow me if you crave more! 🍿&lt;/p&gt;

&lt;p&gt;I'm on &lt;a href="https://twitter.com/JS_Bits_Bill" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;, &lt;a href="https://www.tiktok.com/@js_bits" rel="noopener noreferrer"&gt;TikTok&lt;/a&gt; and I have a new &lt;a href="https://www.udemy.com/course/js-bits-bug-bash/" rel="noopener noreferrer"&gt;debugging course&lt;/a&gt; out now!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>dom</category>
      <category>html</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Coding a Hank Hill Hotkey</title>
      <dc:creator>JS Bits Bill</dc:creator>
      <pubDate>Mon, 14 Feb 2022 16:49:32 +0000</pubDate>
      <link>https://dev.to/js_bits_bill/coding-a-hank-hill-hotkey-23h9</link>
      <guid>https://dev.to/js_bits_bill/coding-a-hank-hill-hotkey-23h9</guid>
      <description>&lt;p&gt;Today we'll be coding a hotkey easter-egg for your website that will display a random Hank Hill image in your viewport. This will prove to be an essential feature that will &lt;strong&gt;delight your visitors, optimize the user experience, and improve your conversation rate&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;First we add a basic CSS style to scale and position the eventual images:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;head&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insertAdjacentHTML&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;beforeend&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`
  &amp;lt;style&amp;gt;
    .hh {
      position: fixed;
      z-index: 999;
      transform: scale(1.65);
    }
  &amp;lt;/style&amp;gt;
`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next we add a &lt;code&gt;keydown&lt;/code&gt; listener on the document, taking care to exit our callback early if the key was pressed inside an &lt;code&gt;input&lt;/code&gt; or &lt;code&gt;form&lt;/code&gt; element so we don't hijack real typing inside these elements:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;keydown&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleHotkey&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleHotkey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;matches&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;input, textarea&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we'll map the &lt;code&gt;h&lt;/code&gt; key to a &lt;code&gt;displayHank&lt;/code&gt; function and detect if this key was pressed by checking the &lt;code&gt;code&lt;/code&gt; property value on the event:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleHotkey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;matches&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;input, textarea&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;commands&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;KeyH&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;displayHank&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;enteredCommand&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;commands&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; 
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;enteredCommand&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;enteredCommand&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our &lt;code&gt;displayHank&lt;/code&gt; function will grab a random image source from an array and insert it into the DOM with a random position obtained via the &lt;code&gt;getRandomPosition&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;displayHank&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;images&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;9H8k4mF/200w-1.gif&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;09T2y3p/giphy-4.gif&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;k3VYFZk/giphy-5.gif&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;images&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;randomIndex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;images&lt;/span&gt;&lt;span class="p"&gt;)];&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getRandomPosition&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insertAdjacentHTML&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;beforeend&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`
    &amp;lt;img 
      class="hh"
      style="top: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;px; left: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;px"
      src="https://i.ibb.co/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"
    &amp;gt;
  `&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;randomIndex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now if we hit the &lt;code&gt;h&lt;/code&gt; key, we'll see all these Hank Hill images pop up. Perfect! &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdzynqn10l%2Fimage%2Fupload%2Fv1644726465%2FMsc%2FLYRwIB9H4h_q48rs3.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdzynqn10l%2Fimage%2Fupload%2Fv1644726465%2FMsc%2FLYRwIB9H4h_q48rs3.webp" width="800" height="731"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's missing one thing, though... let's map another hotkey to play some soundbites:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleHotkey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;matches&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;input, textarea&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;commands&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;KeyH&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;displayHank&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;KeyS&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;playSound&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;enteredCommand&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;commands&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; 
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;enteredCommand&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;enteredCommand&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;playSound&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;baseURI&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://res.cloudinary.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/dzynqn10l/video/upload/v1644093214/Msc/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sounds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bwaaah_ckyvbs.mp3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dang-it-bobby_d8hvry_jh4civ.mp3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jpeg_hwasj2.mp3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;audio&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Audio&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;baseURI&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;sounds&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;randomIndex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sounds&lt;/span&gt;&lt;span class="p"&gt;)]}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;audio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;play&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now if the user hits the &lt;code&gt;s&lt;/code&gt; key, they'll hear a clip of Hank saying one of these phrases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Bwaaah!&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;God dammit, Bobby.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Do I look like I know what a JPEG is? I just want a picture of a god-dang hotdog.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Spam these keys quickly for some real fun! 🤠&lt;/p&gt;

&lt;p&gt;Full script is here: &lt;a href="https://github.com/doctafaustus/hank-hill-js" rel="noopener noreferrer"&gt;https://github.com/doctafaustus/hank-hill-js&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;&lt;b&gt;Yo!&lt;/b&gt; I post byte-sized tips like these often. Follow me if you crave more! 🍿&lt;/p&gt;

&lt;p&gt;I'm on &lt;a href="https://twitter.com/JS_Bits_Bill" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;, &lt;a href="https://www.tiktok.com/@js_bits" rel="noopener noreferrer"&gt;TikTok&lt;/a&gt; and I have a new &lt;a href="https://www.udemy.com/course/js-bits-bug-bash/" rel="noopener noreferrer"&gt;debugging course&lt;/a&gt; out now!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>tutorial</category>
      <category>webdev</category>
      <category>humor</category>
    </item>
    <item>
      <title>HTML &lt;dialog&gt;</title>
      <dc:creator>JS Bits Bill</dc:creator>
      <pubDate>Thu, 18 Nov 2021 16:19:12 +0000</pubDate>
      <link>https://dev.to/js_bits_bill/html-5201</link>
      <guid>https://dev.to/js_bits_bill/html-5201</guid>
      <description>&lt;p&gt;HTML's &lt;code&gt;&amp;lt;dialog&amp;gt;&lt;/code&gt; element is a built-in tag to represent a dialog box or modal. It's not just a newer semantic element, it also includes an API and its own special CSS.&lt;/p&gt;

&lt;h3&gt;
  
  
  Here's a video using &lt;code&gt;&amp;lt;dialog&amp;gt;&lt;/code&gt; in action:
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=7SQgGxLr5z0" rel="noopener noreferrer"&gt;&lt;br&gt;
  &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdzynqn10l%2Fimage%2Fupload%2Fv1637190457%2FMsc%2Fhtml-dialog-cover_1_v0owrg.jpg" width="800" height="450"&gt;&lt;br&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  How to use it
&lt;/h3&gt;

&lt;p&gt;To start, we add our &lt;code&gt;&amp;lt;dialog&amp;gt;&lt;/code&gt; HTML:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;dialog&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Modal Heading&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;This is the content for the modal.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dialog&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This won't yet display any visible content, until we call the dialog's &lt;code&gt;.showModal()&lt;/code&gt; method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dialog&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dialog&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// When we want to open...&lt;/span&gt;
&lt;span class="nx"&gt;dialog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;showModal&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdzynqn10l%2Fimage%2Fupload%2Fv1637171628%2FJS%2520Bits%2Fmodal-dev-to_mertzi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdzynqn10l%2Fimage%2Fupload%2Fv1637171628%2FJS%2520Bits%2Fmodal-dev-to_mertzi.png" width="730" height="548"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Calling this method will programmatically add the &lt;code&gt;open&lt;/code&gt; attribute to the element, indicating its state and visibility:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;dialog&lt;/span&gt; &lt;span class="na"&gt;open&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Modal Heading&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;This is the content for the modal.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dialog&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will also add a &lt;code&gt;::backdrop&lt;/code&gt; pseudo-element element with these default styles to dim the content behind the dialog:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;dialog&lt;/span&gt;&lt;span class="nd"&gt;::backdrop&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;fixed&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we add a close button, we can hook up an event handler to call the built-in &lt;code&gt;.close()&lt;/code&gt; method to un-show the dialog and remove the backdrop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;dialog&lt;/span&gt; &lt;span class="na"&gt;open&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Modal Heading&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;This is the content for the modal.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"close"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Close&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dialog&amp;gt;&lt;/span&gt;

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

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dialog&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dialog&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;btn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#close&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;btn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;dialog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;dialog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;close&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Runs after dialog is closed&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;The modal was closed!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdzynqn10l%2Fimage%2Fupload%2Fv1637171969%2FJS%2520Bits%2Fbrowser_empty_ockj2t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdzynqn10l%2Fimage%2Fupload%2Fv1637171969%2FJS%2520Bits%2Fbrowser_empty_ockj2t.png" width="730" height="548"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The document also includes the &lt;code&gt;close&lt;/code&gt; event which can be leverage to run a custom callback once &lt;code&gt;.close()&lt;/code&gt; is called.&lt;/p&gt;

&lt;p&gt;As of 11/21, support is available mainly for Edge, Chrome, and Safari Technology Preview with greater support emerging soon! 🙂&lt;/p&gt;




&lt;p&gt;&lt;b&gt;Yo!&lt;/b&gt; I post byte-sized tips like these often. Follow me if you crave more! 🍿&lt;/p&gt;

&lt;p&gt;I'm on &lt;a href="https://twitter.com/JS_Bits_Bill" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;, &lt;a href="https://www.tiktok.com/@js_bits" rel="noopener noreferrer"&gt;TikTok&lt;/a&gt; and I have a new &lt;a href="https://jsbits-yo.com/bug-bash/" rel="noopener noreferrer"&gt;debugging course&lt;/a&gt; dropping soon!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>html</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Easy console.log() inside one liner functions</title>
      <dc:creator>JS Bits Bill</dc:creator>
      <pubDate>Wed, 10 Nov 2021 21:24:48 +0000</pubDate>
      <link>https://dev.to/js_bits_bill/easy-consolelog-inside-one-liner-functions-2mja</link>
      <guid>https://dev.to/js_bits_bill/easy-consolelog-inside-one-liner-functions-2mja</guid>
      <description>&lt;p&gt;Let's say we want to log &lt;code&gt;obj&lt;/code&gt; inside this &lt;code&gt;.map()&lt;/code&gt; function here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;arr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;val&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;val&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;val&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Well, dang! Now we have to convert this to a multi-line function, right?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead we can use the logical OR (&lt;code&gt;||&lt;/code&gt;) operator with &lt;code&gt;console.log()&lt;/code&gt; to short-circuit evaluate the return statement:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works because &lt;code&gt;console.log()&lt;/code&gt; evaluates to &lt;code&gt;undefined&lt;/code&gt; so our OR (&lt;code&gt;||&lt;/code&gt;) opertator will evalutate the next operand which is the return portion of the function and will return the same result as the original example!&lt;/p&gt;

&lt;p&gt;This is especially usefull with JSX where we commonly render components with implicit return statements:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Short-circuit Logging&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Huzzah! 😃&lt;/p&gt;




&lt;p&gt;&lt;b&gt;Yo!&lt;/b&gt; I post byte-sized tips like these often. Follow me if you crave more! 🍿&lt;/p&gt;

&lt;p&gt;I'm on &lt;a href="https://twitter.com/JS_Bits_Bill" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;, &lt;a href="https://www.tiktok.com/@js_bits" rel="noopener noreferrer"&gt;TikTok&lt;/a&gt; and I have a new &lt;a href="https://jsbits-yo.com/bug-bash/" rel="noopener noreferrer"&gt;debugging course&lt;/a&gt; dropping soon!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>codenewbie</category>
    </item>
    <item>
      <title>What JavaScript looked like in 1996</title>
      <dc:creator>JS Bits Bill</dc:creator>
      <pubDate>Thu, 04 Nov 2021 21:55:50 +0000</pubDate>
      <link>https://dev.to/js_bits_bill/what-javascript-looked-like-in-1996-3o9</link>
      <guid>https://dev.to/js_bits_bill/what-javascript-looked-like-in-1996-3o9</guid>
      <description>&lt;p&gt;Check out this very early JavaScript guide book I got from eBay. It was released in 1996 and is only the beta edition back when JS was just born! 👶 Definitely a piece of history.&lt;/p&gt;




&lt;p&gt;&lt;b&gt;Yo!&lt;/b&gt; I post byte-sized tips like these often. Follow me if you crave more! 🍿&lt;/p&gt;

&lt;p&gt;I'm on &lt;a href="https://www.tiktok.com/@js_bits" rel="noopener noreferrer"&gt;TikTok&lt;/a&gt;, &lt;a href="https://twitter.com/JS_Bits_Bill" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; and I have a new &lt;a href="https://jsbits-yo.com/bug-bash/" rel="noopener noreferrer"&gt;debugging course&lt;/a&gt; dropping soon!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Creating a Text-To-Speech program in Vanilla JS</title>
      <dc:creator>JS Bits Bill</dc:creator>
      <pubDate>Fri, 29 Oct 2021 15:01:23 +0000</pubDate>
      <link>https://dev.to/js_bits_bill/creating-a-text-to-speech-program-in-vanilla-js-586l</link>
      <guid>https://dev.to/js_bits_bill/creating-a-text-to-speech-program-in-vanilla-js-586l</guid>
      <description>&lt;p&gt;If you haven't been too traumatized from using a Microsoft browser, you might have discovered Edge's built-in "Read Aloud" feature which will speak the highlighted text out loud right in your browser:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdzynqn10l%2Fimage%2Fupload%2Fv1635438522%2FJS%2520Bits%2Fedge-text-to-speech_y88jdn.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdzynqn10l%2Fimage%2Fupload%2Fv1635438522%2FJS%2520Bits%2Fedge-text-to-speech_y88jdn.jpg" width="800" height="769"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As of now, Chrome has no such feature so we're going to build it ourselves! Here's the code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSelection&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;utterance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SpeechSynthesisUtterance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;utterance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;voice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getFemaleVoice&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;speechSynthesis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;utterance&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Optional - select one of several voices&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getFemaleVoice&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;voiceIndex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;speechSynthesis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getVoices&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="nx"&gt;voiceIndex&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So essentially we just pass in the string from &lt;code&gt;window.getSelection().toString()&lt;/code&gt; to a new instance of &lt;code&gt;SpeechSynthesisUtterance&lt;/code&gt; and call the &lt;code&gt;.speak()&lt;/code&gt; method and that's it!&lt;/p&gt;

&lt;p&gt;But we need a way to trigger our &lt;code&gt;speak()&lt;/code&gt; function. You could create a Chrome extension to add this functionality to the context menu but I've chosen to use DevTool's "Snippets" just to keep it simple. Snippets are your own custom saved scripts you can paste into your browser and run at will. They're super handy for utility functions like cookie getter/setters, JS libraries like Lodash or jQuery, custom UI modifications, etc. &lt;/p&gt;

&lt;p&gt;Once you create a snippet, you can run the code either by clicking "Run Snippet" or pressing Command/Control + Enter. You can also run them directly from the DevTools Command Menu. &lt;/p&gt;

&lt;p&gt;Snippets are located in the &lt;b&gt;Sources&lt;/b&gt; tab and then on the sidebar click "Snippets":&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdzynqn10l%2Fimage%2Fupload%2Fv1635440825%2FJS%2520Bits%2Fsnippet_tnq2qw.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdzynqn10l%2Fimage%2Fupload%2Fv1635440825%2FJS%2520Bits%2Fsnippet_tnq2qw.jpg" width="591" height="326"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We just need a bit more overhead to account for the asynchronous loading of &lt;code&gt;speechSynthesis.getVoices()&lt;/code&gt; so that our desired voice has loaded before the speech audio runs. The final code looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;voiceLoaded&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;speechSynthesis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;voiceschanged&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSelection&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;utterance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SpeechSynthesisUtterance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;utterance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;voice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getFemaleVoice&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;speechSynthesis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;utterance&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getFemaleVoice&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;voiceIndex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;speechSynthesis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getVoices&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="nx"&gt;voiceIndex&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;voiceLoaded&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;speechSynthesis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getVoices&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdzynqn10l%2Fimage%2Fupload%2Fv1635441350%2FJS%2520Bits%2Ftext-to-speech-final_d0pssc.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdzynqn10l%2Fimage%2Fupload%2Fv1635441350%2FJS%2520Bits%2Ftext-to-speech-final_d0pssc.jpg" width="800" height="469"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And now we can do the laundry and have our article read to us at the same time! 🔊&lt;/p&gt;




&lt;p&gt;&lt;b&gt;Yo!&lt;/b&gt; I post byte-sized tips like these often. Follow me if you crave more! 🍿&lt;/p&gt;

&lt;p&gt;I'm on &lt;a href="https://twitter.com/JS_Bits_Bill" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;, &lt;a href="https://www.tiktok.com/@js_bits" rel="noopener noreferrer"&gt;TikTok&lt;/a&gt; and I have a new &lt;a href="https://jsbits-yo.com/bug-bash/" rel="noopener noreferrer"&gt;debugging course&lt;/a&gt; dropping soon!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Customize any website with your own CSS</title>
      <dc:creator>JS Bits Bill</dc:creator>
      <pubDate>Thu, 21 Oct 2021 23:18:22 +0000</pubDate>
      <link>https://dev.to/js_bits_bill/customize-any-website-with-your-own-css-2bll</link>
      <guid>https://dev.to/js_bits_bill/customize-any-website-with-your-own-css-2bll</guid>
      <description>&lt;p&gt;How to hide those distracting PrimeGaming notifications!&lt;/p&gt;

&lt;p&gt;If you have digital OCD like me then these little red alerts drive you crazy 🤪&lt;/p&gt;




&lt;p&gt;&lt;b&gt;Yo!&lt;/b&gt; I post byte-sized tips like these often. Follow me if you crave more! 🍿&lt;/p&gt;

&lt;p&gt;I'm on &lt;a href="https://www.tiktok.com/@js_bits" rel="noopener noreferrer"&gt;TikTok&lt;/a&gt;, &lt;a href="https://twitter.com/JS_Bits_Bill" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; and I have a new &lt;a href="https://jsbits-yo.com/bug-bash/" rel="noopener noreferrer"&gt;debugging course&lt;/a&gt; dropping soon!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>css</category>
    </item>
    <item>
      <title>3 Uncommon but useful HTML elements</title>
      <dc:creator>JS Bits Bill</dc:creator>
      <pubDate>Wed, 20 Oct 2021 14:55:46 +0000</pubDate>
      <link>https://dev.to/js_bits_bill/3-uncommon-but-useful-html-elements-jdi</link>
      <guid>https://dev.to/js_bits_bill/3-uncommon-but-useful-html-elements-jdi</guid>
      <description>&lt;h2&gt;1) &lt;code&gt;&amp;lt;abbr&amp;gt;&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The &lt;b&gt;abbreviation&lt;/b&gt; &lt;code&gt;&amp;lt;abbr&amp;gt;&lt;/code&gt; element is used to represent an acronym or abbreviation. If you include a &lt;code&gt;title&lt;/code&gt; attribute, the text will be display as a tooltip on hover!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;
  The &lt;span class="nt"&gt;&amp;lt;abbr&lt;/span&gt; &lt;span class="na"&gt;title=&lt;/span&gt;&lt;span class="s"&gt;"Product Detail Page"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;PDP&lt;span class="nt"&gt;&amp;lt;/abbr&amp;gt;&lt;/span&gt; provides
  information on a specific product.
&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdzynqn10l%2Fimage%2Fupload%2Fv1634687036%2FJS%2520Bits%2Fabbr_tag_oimzss.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdzynqn10l%2Fimage%2Fupload%2Fv1634687036%2FJS%2520Bits%2Fabbr_tag_oimzss.jpg" width="411" height="139"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;2) &lt;code&gt;&amp;lt;progress&amp;gt;&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;&amp;lt;progress&amp;gt;&lt;/code&gt; element will display a progress bar indicator that can be easily controlled with it's &lt;code&gt;value&lt;/code&gt; attribute. The JavaScript in this example will incrementally fill our progress bar every 100ms as shown here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"progress"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Progress:&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;progress&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"progress"&lt;/span&gt; &lt;span class="na"&gt;max=&lt;/span&gt;&lt;span class="s"&gt;"100"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/progress&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;progress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#progress&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;setProgress&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;setProgress&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;setProgress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdzynqn10l%2Fimage%2Fupload%2Fv1634687087%2FJS%2520Bits%2Fprogress_tag_jaqggk.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdzynqn10l%2Fimage%2Fupload%2Fv1634687087%2FJS%2520Bits%2Fprogress_tag_jaqggk.gif" width="411" height="140"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;3) &lt;code&gt;&amp;lt;wbr&amp;gt;&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The word break opportunity &lt;code&gt;&amp;lt;wbr&amp;gt;&lt;/code&gt; element will allow you to specify exactly where a line of text should break when there is overflow. For example, if we have a super long line of text like this URL, we can tell the browser where the text should break if it doesn't fit on one line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;
http://is.this.just.real.life.com/is&lt;span class="nt"&gt;&amp;lt;wbr&amp;gt;&lt;/span&gt;/this/just/fantasy/caught/in/a/landslide/no/espace/from/reality
&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdzynqn10l%2Fimage%2Fupload%2Fv1634687008%2FJS%2520Bits%2Fwbr_z3gckm.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdzynqn10l%2Fimage%2Fupload%2Fv1634687008%2FJS%2520Bits%2Fwbr_z3gckm.jpg" width="411" height="139"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;b&gt;Yo!&lt;/b&gt; I post byte-sized tips like these often. Follow me if you crave more! 🍿&lt;/p&gt;

&lt;p&gt;I'm on &lt;a href="https://www.tiktok.com/@js_bits" rel="noopener noreferrer"&gt;TikTok&lt;/a&gt;, &lt;a href="https://twitter.com/JS_Bits_Bill" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; and I have a new &lt;a href="https://jsbits-yo.com/bug-bash/" rel="noopener noreferrer"&gt;debugging course&lt;/a&gt; dropping soon!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>codenewbie</category>
      <category>html</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
