<?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>Forem: 🤓 Tomek Nieżurawski</title>
    <description>The latest articles on Forem by 🤓 Tomek Nieżurawski (@tomekdev_).</description>
    <link>https://forem.com/tomekdev_</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%2F492851%2Fa2b3bcde-770b-4b16-952f-e7b7ae99c486.jpg</url>
      <title>Forem: 🤓 Tomek Nieżurawski</title>
      <link>https://forem.com/tomekdev_</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/tomekdev_"/>
    <language>en</language>
    <item>
      <title>Anchors for headings in MDX</title>
      <dc:creator>🤓 Tomek Nieżurawski</dc:creator>
      <pubDate>Tue, 09 Feb 2021 20:47:38 +0000</pubDate>
      <link>https://forem.com/tomekdev_/anchors-for-headings-in-mdx-21cd</link>
      <guid>https://forem.com/tomekdev_/anchors-for-headings-in-mdx-21cd</guid>
      <description>&lt;p&gt;&lt;em&gt;This post was originally published on &lt;a href="https://tomekdev.com/posts/anchors-for-headings-in-mdx"&gt;https://tomekdev.com/posts/anchors-for-headings-in-mdx&lt;/a&gt;. What you see as GIF here is interactive there.&lt;/em&gt; ✌️&lt;/p&gt;




&lt;p&gt;How to add anchors to headings in MDX? It's surprisingly easy to do. I assume you are already familiar with MDX so somewhere in your code you should have a blog page layout component that uses &lt;code&gt;&amp;lt;MDXProvider&amp;gt;&lt;/code&gt;, like that:&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MDXProvider&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;children&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;MDXProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;MDX consists of components itself. So if there is a code like &lt;code&gt;this&lt;/code&gt; then the interpreter changes the inner value (children) into the same content but wrapped with &lt;code&gt;&amp;lt;code&amp;gt;&amp;lt;/code&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The same applies to all the headings, lists, paragraphs, etc. Our job is to override the headings. We can do it by passing &lt;code&gt;components&lt;/code&gt; hash and specifying a replacement.&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;import&lt;/span&gt; &lt;span class="nx"&gt;H2&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./MyCustomMDX/H2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;H3&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./MyCustomMDX/H3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;H4&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./MyCustomMDX/H4&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// ...&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MDXProvider&lt;/span&gt;
  &lt;span class="na"&gt;components&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;H2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;h3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;H3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;h4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;H4&lt;/span&gt;&lt;span class="p"&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;gt;&lt;/span&gt;
  &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;MDXProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Please notice that we are not going to add an anchor to the &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; tag. It doesn't make sense in my opinion. &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; is like a summary of the whole page. The URL that links to it is the direct link to the post. Anchors should be used to specific parts of a post (to a section).&lt;/p&gt;

&lt;h2&gt;
  
  
  Override heading component
&lt;/h2&gt;

&lt;p&gt;The override for &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt; that shows an anchor when the mouse is over the text could look like this:&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="c1"&gt;// ./MyCustomMDX/H2.js&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getAnchor&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="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&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;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;[^&lt;/span&gt;&lt;span class="sr"&gt;a-z0-9&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;,&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;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;[]&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;-&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;H2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;anchor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getAnchor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;children&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;link&lt;/span&gt; &lt;span class="o"&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;anchor&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;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;h2&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;anchor&lt;/span&gt;&lt;span class="si"&gt;}&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;a&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"anchor-link"&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;a&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;children&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;h2&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;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;H2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Below you'll see the demo. Please notice the hover state. On the left you should see &lt;code&gt;§&lt;/code&gt; sign that is also a link, representing our anchor:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UncAIziF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/z81fc678d70qyi6i2v6t.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UncAIziF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/z81fc678d70qyi6i2v6t.gif" alt="Anchor demo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's explain a few bits. The way we use headings in Markdown is by using &lt;code&gt;#&lt;/code&gt; sign, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## I'm h2 with an anchor&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Everything that goes after &lt;code&gt;##&lt;/code&gt; is passed as a child to the &lt;code&gt;H2&lt;/code&gt; component.&lt;/p&gt;

&lt;p&gt;So the next interesting bit is done in the &lt;code&gt;getAnchor&lt;/code&gt; function. Take a look at lines 3 to 8. This is what happens:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;line 5 - we convert the input to lower case → "i'm h2 with an anchor"&lt;/li&gt;
&lt;li&gt;line 6 - we remove all non-alphanumeric characters → "im h2 with an anchor"&lt;/li&gt;
&lt;li&gt;line 7 - we replace spaces with a hyphen → "im-h2-with-an-anchor"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;... and voilà. We have a URL-friendly anchor 🎉&lt;/p&gt;

&lt;h2&gt;
  
  
  The styling
&lt;/h2&gt;

&lt;p&gt;Another important thing here is the CSS. We want to show the anchor only on hover and somewhere next to the heading itself:&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;h2&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;relative&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.anchor-link&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#666&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;opacity&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="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;absolute&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;translate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;-1em&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;-2px&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="nc"&gt;.anchor-link&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;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;Of course, you can go crazy with your anchors ;) That one is very basic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recommendation
&lt;/h2&gt;

&lt;p&gt;One thing that is easy to overlook here (in my example) is using a character like &lt;code&gt;§&lt;/code&gt; inside of &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt; tag. In this approach, &lt;strong&gt;the sign will become a part of the document outline&lt;/strong&gt;. Which is not something we want. It's better to use an icon in SVG format but I didn't want to complicate the example.&lt;/p&gt;

&lt;p&gt;If the simple sign is what you want then you should render &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; tag before or after the &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>mdx</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Highlight text in JavaScript</title>
      <dc:creator>🤓 Tomek Nieżurawski</dc:creator>
      <pubDate>Sat, 09 Jan 2021 07:07:05 +0000</pubDate>
      <link>https://forem.com/tomekdev_/highlight-text-in-javascript-45jf</link>
      <guid>https://forem.com/tomekdev_/highlight-text-in-javascript-45jf</guid>
      <description>&lt;p&gt;&lt;em&gt;This post was originally published on &lt;a href="https://tomekdev.com/posts/highlight-text-in-javascript" rel="noopener noreferrer"&gt;https://tomekdev.com/posts/highlight-text-in-javascript&lt;/a&gt;. What you see as GIF here is interactive there.&lt;/em&gt; ✌️&lt;/p&gt;




&lt;p&gt;In the previous post about &lt;a href="https://tomekdev.com/posts/search-with-typo-tolerance" rel="noopener noreferrer"&gt;search with typo tolerance&lt;/a&gt;, I added a few interactive elements to demonstrate the idea of how we can improve search functionality on the page by being more tolerant to typos. You might be curious how I made highlighting of matching text within results. So here it is.&lt;/p&gt;

&lt;p&gt;It's not super complicated but I'll give you a very nice hint you might not know :) &lt;strong&gt;Here is the demo&lt;/strong&gt;. Look at the GIF below (or visit my website to play with that) and observe how words are highlighted:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fonev5gjchf5az3gn5eav.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fonev5gjchf5az3gn5eav.gif" alt="Highlighting text in JS"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The trick is to replace all occurrences of searched text with the same text but wrapped with a &lt;code&gt;&amp;lt;mark&amp;gt;&lt;/code&gt; this time. We will also add a &lt;code&gt;highlight&lt;/code&gt; CSS class to that &lt;code&gt;&amp;lt;mark&amp;gt;&lt;/code&gt; so we will be able to style it accordingly. &lt;strong&gt;You don't need any JS library for that.&lt;/strong&gt; Here is the code that does the job:&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;$box&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;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;box&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;$search&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;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;search&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;$search&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;input&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;event&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;searchText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&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="nx"&gt;value&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;regex&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;RegExp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;searchText&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gi&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;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;$box&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;&amp;lt;mark class="highlight"&amp;gt;|&amp;lt;&lt;/span&gt;&lt;span class="se"&gt;\/&lt;/span&gt;&lt;span class="sr"&gt;mark&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;/gim&lt;/span&gt;&lt;span class="p"&gt;,&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;newText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;regex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;mark class="highlight"&amp;gt;$&amp;amp;&amp;lt;/mark&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;$box&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="nx"&gt;newText&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;Let's assume the &lt;code&gt;$box&lt;/code&gt; is the element that contains text (it could be a whole page) and the &lt;code&gt;$search&lt;/code&gt; is the input. In line 8 we get the current HTML in the &lt;code&gt;$box&lt;/code&gt; and remove all current highlights in the following line. We do that to clean-up after ourselves. We don't want to keep old searches (or partial searches) on the screen. You can &lt;a href="https://codepen.io/tniezurawski/pen/wvzyVEE" rel="noopener noreferrer"&gt;play with that on codepen&lt;/a&gt; so you'll see the HTML structure and CSS styles (where only the .highlight is important).&lt;/p&gt;

&lt;p&gt;The hint I've mentioned before you could potentially miss is &lt;code&gt;$&amp;amp;&lt;/code&gt; in the second argument of the &lt;code&gt;replace&lt;/code&gt; method. This is &lt;em&gt;a special replacement pattern&lt;/em&gt; that tells the replacer method to &lt;em&gt;insert the matched substring&lt;/em&gt; there.&lt;/p&gt;

&lt;p&gt;Why we won't simply use something like this? So inserting the searched text?&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="c1"&gt;// ...&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;searchText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&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="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;regex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="s2"&gt;`&amp;lt;mark class="highlight"&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;searchText&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/mark&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;By doing that &lt;strong&gt;we will get into trouble with the case of the letters&lt;/strong&gt;. Most search/find functionality is case insensitive so we don't want to mess with that. Consider the example below, where I simply wrap the searched text with a &lt;code&gt;&amp;lt;mark&amp;gt;&lt;/code&gt; with that text inside:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fm9k91wrbshq7p7gkwg9a.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fm9k91wrbshq7p7gkwg9a.gif" alt="Bad highlighting at work"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;It's strange, isn't it? &lt;strong&gt;Fortunately, we don't have to be super clever&lt;/strong&gt; to keep the case of the matched text. We just need to use &lt;code&gt;$&amp;amp;&lt;/code&gt; with the &lt;code&gt;replace&lt;/code&gt; method.&lt;/p&gt;

&lt;h2&gt;
  
  
  React implementation
&lt;/h2&gt;

&lt;p&gt;React seems to be the most popular &lt;del&gt;framework&lt;/del&gt; library that people use these days. But no matter what front-end framework you use, you'll probably pass &lt;code&gt;text&lt;/code&gt; as an argument to a component with search-and-highlight functionality. It could be also a label of searchable items on a list.&lt;/p&gt;

&lt;p&gt;That simplifies things a bit because we don't have to get a raw text from DOM elements. And we don't have to clean up after ourselves. We can focus on the wrapping part and leave the rendering to the rendering engine:&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;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HighlightText&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&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="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;searchText&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&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="nx"&gt;search&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&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="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&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="nf"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;searchText&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;event&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="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;_getText&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;searchText&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;searchText&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="nf"&gt;_getTextWithHighlights&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;searchText&lt;/span&gt;&lt;span class="p"&gt;)&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="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;_getTextWithHighlights&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;searchText&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;regex&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;RegExp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;searchText&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gi&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;newText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;regex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;mark class="highlight"&amp;gt;$&amp;amp;&amp;lt;/mark&amp;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;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt; &lt;span class="na"&gt;dangerouslySetInnerHTML&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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="nx"&gt;newText&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;gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;render&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;cite&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="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;props&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;searchText&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&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;textToShow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_getText&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;searchText&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="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"container"&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="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"search-container"&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;label&lt;/span&gt; &lt;span class="na"&gt;htmlFor&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"search"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Search within quoted text&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;label&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;input&lt;/span&gt;
            &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"search"&lt;/span&gt;
            &lt;span class="na"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Type `web` for example"&lt;/span&gt;
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"search"&lt;/span&gt;
            &lt;span class="na"&gt;autoComplete&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"off"&lt;/span&gt;
            &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;searchText&lt;/span&gt;&lt;span class="si"&gt;}&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;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;blockquote&lt;/span&gt; &lt;span class="na"&gt;cite&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;cite&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;textToShow&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;blockquote&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;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(&lt;a href="https://codesandbox.io/s/zealous-blackburn-54310?file" rel="noopener noreferrer"&gt;link to sandbox&lt;/a&gt; if you'd like to play with that)&lt;/p&gt;

&lt;p&gt;The most important lines in this implementation are lines 20 and 21. The first one is the heart of highlighting implementation and the second makes sure to set &lt;em&gt;dangerous HTML&lt;/em&gt; content within an element.&lt;/p&gt;

&lt;h3&gt;
  
  
  What's so dangerous about the wrapped searched text?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Every framework has to sanitize raw HTML&lt;/strong&gt; if you plan to display it on the screen. Here we are sure that the content is ok. It's provided by the user but not displayed anywhere else than their computer so it's safe by definition.&lt;/p&gt;

&lt;p&gt;Search for "html safe &lt;em&gt;+ framework name&lt;/em&gt;" to find a way to force the rendering engine to display a wrapped element.&lt;/p&gt;

&lt;p&gt;Good luck!&lt;/p&gt;




&lt;p&gt;EDIT: In the original post, I was wrapping highlighted text with &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt;. Thanks to the comment below I have changed that to &lt;code&gt;&amp;lt;mark&amp;gt;&lt;/code&gt; that is semantically better 🙌&lt;/p&gt;

</description>
      <category>html</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Search with typo tolerance</title>
      <dc:creator>🤓 Tomek Nieżurawski</dc:creator>
      <pubDate>Sat, 02 Jan 2021 12:06:43 +0000</pubDate>
      <link>https://forem.com/tomekdev_/search-with-typo-tolerance-5gnj</link>
      <guid>https://forem.com/tomekdev_/search-with-typo-tolerance-5gnj</guid>
      <description>&lt;p&gt;&lt;em&gt;This post was originally published on &lt;a href="https://tomekdev.com/posts/search-with-typo-tolerance" rel="noopener noreferrer"&gt;https://tomekdev.com/posts/search-with-typo-tolerance&lt;/a&gt;. What you see as GIF here is interactive there.&lt;/em&gt; ✌️&lt;/p&gt;




&lt;p&gt;Everyone makes mistakes. That's why undo/redo is a must-have for interfaces where you work on something. That's why we add extra padding around clickable elements for touch screens so it's easier to catch touches. That's why Google tries to show some results even if what you typed is far from perfect.&lt;/p&gt;

&lt;p&gt;Users absolutely love that and they can't imagine software without &lt;code&gt;ctrl+z&lt;/code&gt; and looking at a "No results" page when they mistyped something. It seems that the bar is high... but still, a &lt;strong&gt;lot of software does only what is convenient for developers&lt;/strong&gt; when it comes to searching and showing results.&lt;/p&gt;

&lt;h2&gt;
  
  
  Examining the problem
&lt;/h2&gt;

&lt;p&gt;Below we have a simple search that's going to work like filtering on the list. The list is short so it's going to be easy to understand what's happening. In other words, we already have all elements on the screen but searching is going to help us in finding &lt;em&gt;that thing&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Please look at the list and watch as I am typing something there, misspelling something, or typing something completely different. &lt;a href="https://tomekdev.com/posts/search-with-typo-tolerance" rel="noopener noreferrer"&gt;You can play with it on my page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6hgq1qefjd2qxkdlol39.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6hgq1qefjd2qxkdlol39.gif" alt="Searching with %LIKE% queries"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;What we've just used here is a simple "contain" query. Or if you are familiar with SQL - we perform &lt;code&gt;%LIKE%&lt;/code&gt; here. Is it bad? Well, it's okay. Better than strict comparison for sure. But it's not super friendly &lt;strong&gt;because you have to be right&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The hearth of this method is highlighted in the code below. We filter the list by checking if any fruit name contains the searched text. There is &lt;strong&gt;a bit of user-friendliness&lt;/strong&gt; here - the search is case insensitive which is the desired behavior in most text searches done by users:&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;FRUITS&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;Apple&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;Banana&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;Blueberry&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;Cherries&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="cm"&gt;/* etc... */&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;searchHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&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;searchText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&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="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&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;filteredFruits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;FRUITS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;fruit&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;return&lt;/span&gt; &lt;span class="nx"&gt;fruit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;searchText&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// HERE&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// render the list of `filteredFruits`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Introducing a tolerance
&lt;/h2&gt;

&lt;p&gt;What about tolerating small mistakes aka typos? Let's try again. I'm searching for fruits on the list but misspell them this time. Maybe aple instead of apple?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzjryhq22xrfpr48kn3cb.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzjryhq22xrfpr48kn3cb.gif" alt="Searching with typo tolerance"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Aple, I mean Apple is still on the list, right? Same with bananna, blubery, cheries, peer, and so on. I must admit, the algorithm is not auto-search friendly. The experience is much better with the &lt;code&gt;[Search]&lt;/code&gt; button because you won't see false friends here while typing. But it's so much better for understanding how it works...&lt;/p&gt;

&lt;p&gt;Let's try &lt;code&gt;pee&lt;/code&gt; 🤭 for example. You should see Apple and Pear on the list. Both are pretty close matches according to the algorithm we are using:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ffvm0x4eh3yig4oozdqeo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ffvm0x4eh3yig4oozdqeo.png" alt="Searching for "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The algorithm
&lt;/h2&gt;

&lt;p&gt;The algorithm used here is called &lt;em&gt;Levenshtein distance&lt;/em&gt;. I'm going to quote Wikipedia on this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;[...] the Levenshtein distance between two words is the minimum number of single-character edits (insertions, deletions or substitutions) required to change one word into the other.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's both a huge advantage and a problem sometimes. The shorter the names of searchable items are the worse for the algorithm. Very short words like Pear, are favored when typing because the number of edits needed to "having a match" will be relatively short comparing to a very long word that needs a lot of insertions.&lt;/p&gt;

&lt;p&gt;As stated in the definition, in the very heart of this algorithm &lt;strong&gt;we calculate the distance&lt;/strong&gt;. Then we decide if the distance is something we accept - &lt;strong&gt;so what's the minimum of edits that we accept?&lt;/strong&gt; Let's visualize that and see how far words are from your searched text:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvf19x5j9jl87cv9ay8n8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvf19x5j9jl87cv9ay8n8.png" alt="Apple and Pear are quite close to "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Back to our embarrassing &lt;code&gt;pee&lt;/code&gt; example 🤭. What you should see on the screen is Apple (3) and Pear (2). How the distance is measured? Please look below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fmgb4wctlcqrq4nhlzl38.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fmgb4wctlcqrq4nhlzl38.png" alt="Illustration on how the distance is measured"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the case of Apple we need to perform 3 operations to get there from "pee": add &lt;code&gt;A&lt;/code&gt; and &lt;code&gt;p&lt;/code&gt; and change the first &lt;code&gt;e&lt;/code&gt; into &lt;code&gt;l&lt;/code&gt;. When it comes to Pear, there are only 2 operations that have to be taken: change the second &lt;code&gt;e&lt;/code&gt; into &lt;code&gt;a&lt;/code&gt; and add &lt;code&gt;r&lt;/code&gt; at the end. As you see it's easier to get Pear from the given input.&lt;/p&gt;

&lt;p&gt;So far we were just keeping the order of items as it was (alphabetical here). But in fact, Pear is closer to what we need than Apple and that option should land as first on the list.&lt;/p&gt;

&lt;p&gt;Fear not, we are just going to sort it! Take a look:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2at8xg5hyebvt7yml6rm.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2at8xg5hyebvt7yml6rm.gif" alt="Search results ordered by distance"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;So how it works? In a nutshell, we've just changed the searching/filtering algorithm (see highlighted lines).&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;FRUITS&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;Apple&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;Banana&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;Blueberry&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;Cherries&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="cm"&gt;/* etc... */&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;MIN_DISTANCE&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;searchHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&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;searchText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&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="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&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;filteredFruits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;FRUITS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;fruit&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;// HIGHLIGHT STARTS&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;distance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;levenshtein&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fruit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nx"&gt;searchText&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;distance&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;MIN_DISTANCE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// HIGHLIGHT ENDS&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// render the list of `filteredFruits`&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;levenshtein&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// The Levenshtein's algorithm calculating the distance&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We compare distance by using Mr. Levenshtein's method and if the distance is higher than the minimal distance we accept we decide to filter these entries out.&lt;/p&gt;

&lt;p&gt;When it comes to the algorithm itself, you may want to implement it on your own based on the definition on Wikipedia. But if there is anything I know about computing, is that there are methods way faster than what comes to your mind first, when you look at the mathematical equation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It's better to just use what is already there on the Internet.&lt;/strong&gt; Here's &lt;a href="https://github.com/gustf/js-levenshtein/blob/master/index.js" rel="noopener noreferrer"&gt;the implementation I used&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Perfect tolerance (distance)
&lt;/h2&gt;

&lt;p&gt;I couldn't find any equation for that but my best guess is that &lt;strong&gt;the minimum tolerance (distance)&lt;/strong&gt; that you should accept should be &lt;strong&gt;a bit smaller than the shortest word&lt;/strong&gt; in your dataset. Otherwise, there is a possibility that this word will appear too often.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hybrid approach
&lt;/h2&gt;

&lt;p&gt;If you haven't noticed yet, I use a combination of &lt;code&gt;%LIKE%&lt;/code&gt; match and Levenshtein's method. So we fall back to the latter method only if we don't have typical matches. That's handy because the "exact" match is probably what users want. They probably don't care about other variants of a searched text that could be considered as a "fixed" typo if they have exactly what they were looking for.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is that a perfect method?
&lt;/h2&gt;

&lt;p&gt;Well, it's not. Like most solutions, &lt;strong&gt;it doesn't have to be perfect&lt;/strong&gt;. If it adds more value than can bring confusion (because of false friends in results sometimes) then it's useful.&lt;/p&gt;

&lt;p&gt;Levenshtein's method is one of many for a given subject. If you'd like to see more experiments like that, let me know.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus: Does Google do the same?
&lt;/h2&gt;

&lt;p&gt;Nope. Their &lt;em&gt;"Did you mean?"&lt;/em&gt; functionality in search is very different from this. As far as I know, they based it on us (the users) who correct queries when we can't find anything useful because of typos. This way, with the unbelievable amount of data they possess, they can teach the algorithm what's the best guess for given "typos". It's far more sophisticated but it can be super-efficient for long queries.&lt;/p&gt;

&lt;p&gt;Anyway, for our &lt;strong&gt;front-end needs&lt;/strong&gt; and as a first attempt to helping users with typos in search I think we are &lt;strong&gt;good enough&lt;/strong&gt; with the Levenshtein method. &lt;strong&gt;What do you think?&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>ux</category>
      <category>javascript</category>
      <category>algorithms</category>
    </item>
    <item>
      <title>Useful setup that I always use when starting a new project</title>
      <dc:creator>🤓 Tomek Nieżurawski</dc:creator>
      <pubDate>Mon, 16 Nov 2020 09:23:04 +0000</pubDate>
      <link>https://forem.com/tomekdev_/useful-setup-that-i-always-use-when-starting-a-new-project-4hi1</link>
      <guid>https://forem.com/tomekdev_/useful-setup-that-i-always-use-when-starting-a-new-project-4hi1</guid>
      <description>&lt;p&gt;&lt;em&gt;This post was originally published on &lt;a href="https://tomekdev.com/posts/powerful-start"&gt;https://tomekdev.com/posts/powerful-start&lt;/a&gt;. Go there for slightly nicer code snippets.&lt;/em&gt; ✌️&lt;/p&gt;




&lt;p&gt;I'm not a huge fan of "the art of the start" articles because, after all, &lt;strong&gt;starting in a non-optimal way is worth more than not starting at all&lt;/strong&gt; with a head full of knowledge that wasn't applied.&lt;/p&gt;

&lt;p&gt;With that said, I still have a list of useful stuff that was proven to be working extremely well. The setup is meant to remove some worries from your head and focus on the product/project.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Use version control - git
&lt;/h2&gt;

&lt;p&gt;We start with an obvious one. Even if you don't work on software, use version control, and commit regularly. It will pay off when you make mistakes (everyone does them). When it comes to my projects, I always have to add &lt;code&gt;.idea&lt;/code&gt; to &lt;code&gt;.gitignore&lt;/code&gt; because I'm using WebStorm 🙄&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Use .editorconfig
&lt;/h2&gt;

&lt;p&gt;Tabs vs spaces? Inconsistent indent between different files or between team members? There is a &lt;a href="https://editorconfig.org/"&gt;well-established solution&lt;/a&gt; for that. Even if you are the only person working on the project, do yourself a favor and share &lt;code&gt;.editorconfig&lt;/code&gt; between your projects. Most IDEs will read that file and keep the format of files the way you want.&lt;/p&gt;

&lt;p&gt;My personal preference is to apply a consistent style to ALL types of files by setting a small indent, trimming whitespaces, and inserting a new line at the end of the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;root = true

[*]
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
indent_size = 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Add linters
&lt;/h2&gt;

&lt;p&gt;Linters everywhere! Really.&lt;/p&gt;

&lt;p&gt;Linter is a tool (script) that checks if you keep a certain "style" in your files. That is enforced by following the rules. Some rules will try to keep you out of trouble, where the community knows that certain construction can harm you. And some others will enforce visual style. That's good as well because it ends useless discussions about the style of code, removes inconsistency and frustration within the team.&lt;/p&gt;

&lt;p&gt;A lot of rules comes with autofixable feature that can modify the code for you. Not only pointing what's wrong.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Linters that I use:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://eslint.org/"&gt;ESLint&lt;/a&gt; - for JavaScript&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/remarkjs/remark-lint"&gt;Markdown linter&lt;/a&gt; - for &lt;code&gt;.md&lt;/code&gt; files&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://stylelint.io/"&gt;Stylelint&lt;/a&gt; - for CSS&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/azeemba/eslint-plugin-json"&gt;eslint-plugin-json&lt;/a&gt; - technically it's still ESLint but worth mentioning if you happen to work w &lt;code&gt;.json&lt;/code&gt; files (like translations or configuration files)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Remember to update your linter dependencies regularly and check their release notes for new rules!&lt;/p&gt;




&lt;p&gt;Note:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://palantir.github.io/tslint/"&gt;TSLint&lt;/a&gt; would be something worth mentioning as well (to analyze TypeScript syntax) but it was deprecated in 2019 if someone didn't notice. The proper way of using it now is &lt;a href="https://github.com/typescript-eslint/typescript-eslint"&gt;typescript-eslint&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Add Prettier
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://prettier.io/"&gt;Prettier&lt;/a&gt; is an opinionated code formatter. Linters do affect the way your code looks but prettier is much more in terms of styling the code. It offers support for multiple languages. The reason to use it is similar to linters - &lt;strong&gt;the code should look like written by a single person&lt;/strong&gt;. Consistency is worth aiming for because it makes it easier to read the files.&lt;/p&gt;

&lt;p&gt;Believe or not but developers read and think about code more than they actually write.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Automate it!
&lt;/h2&gt;

&lt;p&gt;Having linters and prettier running in Continues Integration is a must. If the rules are violated then the build should fail. The bigger the project is the longer it takes to analyze the whole codebase. &lt;strong&gt;I am a big fan of linting only the files that were changed&lt;/strong&gt;. So I am using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/typicode/husky"&gt;Husky&lt;/a&gt; - to manage git hooks,&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/okonet/lint-staged"&gt;Lint staged&lt;/a&gt; - to run linters only against files that were changed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How does it work? Husky reacts on git hook before committing files. Lint staged runs linters. Here is an example from&lt;code&gt;package.json&lt;/code&gt; of one of my projects:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"husky": {
  "hooks": {
    "pre-commit": "lint-staged"
  }
},
"lint-staged": {
  "*.js": [
    "prettier --write",
    "eslint --cache --fix"
  ],
  "*.css": "stylelint \"src/**/*.css\" --fix"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In one of the projects I'm working on, linting JS files take &lt;strong&gt;more than 50 seconds&lt;/strong&gt; when run against the whole project. Running it only against files that were modified within a commit takes close to nothing. Here is how it looks when I commit something to my blog:&lt;/p&gt;

&lt;p&gt;&lt;a href="///static/4f5d970a68c7e51c9b46b627d47a549f/b3931/lint-staged.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--asgt319v--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://tomekdev.com/static/4f5d970a68c7e51c9b46b627d47a549f/d9199/lint-staged.png" alt="Lint staged at work" title="Lint staged at work"&gt;&lt;/a&gt;Lint staged at work&lt;/p&gt;

&lt;p&gt;I understand some people like to experiment and don't always have clean commits that will pass linting. Fortunately, you can bypass the checks by adding &lt;code&gt;--no-verify&lt;/code&gt; argument. So for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git commit -m "Blog Post 005: Powerful start" --no-verify
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  6. Setup CI to deploy quickly
&lt;/h2&gt;

&lt;p&gt;That's another thing worth investing time in the beginning. &lt;strong&gt;The easier it is to deploy the better.&lt;/strong&gt; Of course, set the pipeline and deploy only when tests are passing and linters are satisfied. I'm not giving any recipe this time because it differs between projects. If you use a service like &lt;a href="https://www.netlify.com/"&gt;Netlify&lt;/a&gt; then it should be super easy to do it. If you use something else invest the time to set up the process.&lt;/p&gt;

&lt;p&gt;For open-source projects, I use &lt;a href="https://travis-ci.org/"&gt;Travis CI&lt;/a&gt; and for commercial (indie) projects I use&lt;a href="https://circleci.com/"&gt;CircleCI&lt;/a&gt;. I think Travis is completely free for opensource and Circle has a quite generous free plan (&lt;a href="https://circleci.com/pricing/"&gt;2,500 credits/week&lt;/a&gt;) that will be enough for a side-project.&lt;/p&gt;

&lt;p&gt;In some cases, I have used GitHub Actions, like when I had to deploy a single static file to S3.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Dependabot
&lt;/h2&gt;

&lt;p&gt;Updating your dependencies is important because you get security fixes and regular bugs fix. But who has time to remember about it? No-one. So it's better to automate that process. If you happen to have tests in place with decent coverage then ideally you should be able to just merge Pull Requests created by &lt;a href="https://dependabot.com/"&gt;Dependabot&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The tool was acquired by GitHub in May 2019 and since then it is offered free of charge.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;That's it. A few tools, a few configuration files, maybe two services to keep your project great and ready for fast deployment. &lt;strong&gt;I found myself adding these ingredients to every project I work on&lt;/strong&gt; : server-side (in nodejs), React, Ember, Angular, standalone library, &lt;a href="https://checknlearn.com"&gt;Chrome extension&lt;/a&gt;, React Native application, and so on. As you see, it's not bounded to any technology so it's hard to come up with a starter pack.&lt;/p&gt;

&lt;p&gt;You can set the sails now.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>javascript</category>
      <category>tools</category>
      <category>startup</category>
    </item>
    <item>
      <title>Effective titles and more</title>
      <dc:creator>🤓 Tomek Nieżurawski</dc:creator>
      <pubDate>Sat, 07 Nov 2020 07:31:45 +0000</pubDate>
      <link>https://forem.com/tomekdev_/effective-titles-and-more-3mp</link>
      <guid>https://forem.com/tomekdev_/effective-titles-and-more-3mp</guid>
      <description>&lt;p&gt;&lt;em&gt;This post was originally published on &lt;a href="https://tomekdev.com/posts/effective-titles-and-more" rel="noopener noreferrer"&gt;https://tomekdev.com/posts/effective-titles-and-more&lt;/a&gt;. What you see as a GIF here is interactive there.&lt;/em&gt; ✌️&lt;/p&gt;




&lt;p&gt;This is not an SEO guide on how to write effective titles or (maybe I should say) how to create clickbait.&lt;br&gt;&lt;br&gt;
No. We are going to talk about the technicals. If you want my writing advice on that I'd say a cliché:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;title should be short and descriptive&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Did mine do a good job? I don't know, but if you are here reading this, maybe it did.&lt;/p&gt;
&lt;h2&gt;
  
  
  Site name
&lt;/h2&gt;

&lt;p&gt;I believe you should put the site name into the page's title because that's going to land as a name of a bookmark if someone happens to add your page to bookmarks (do people still do that?):&lt;/p&gt;

&lt;p&gt;&lt;a href="/static/566e3234699a72be22b41c2fc28dc94e/91e7e/add-to-bookmark.png"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftomekdev.com%2Fstatic%2F566e3234699a72be22b41c2fc28dc94e%2F91e7e%2Fadd-to-bookmark.png" title="Bookmark added with a clear indication of a site" alt="Bookmark added with a clear indication of a site"&gt;&lt;/a&gt;Bookmark added with a clear indication of a site&lt;/p&gt;

&lt;p&gt;And will help in fast identification. I see that useful also in the History tool of your browser of choice:&lt;/p&gt;

&lt;p&gt;&lt;a href="/static/ff93a31b8d3c7877cb44caa1a6baad7b/5dded/history-list.png"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftomekdev.com%2Fstatic%2Fff93a31b8d3c7877cb44caa1a6baad7b%2Fd9199%2Fhistory-list.png" title="The site name is prominent on a History list" alt="The site name is prominent on a History list"&gt;&lt;/a&gt;The site name is prominent on a History list&lt;/p&gt;

&lt;p&gt;Now, should you put the site name before or after the title for the content of the page?&lt;br&gt;&lt;br&gt;
Well, I believe &lt;strong&gt;after&lt;/strong&gt; is the way to go. Again, easy identification comes into play. If everything starts with "Tomek Dev" then you have to omit it to understand what's this page about. Take a look at this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tomek Dev - Effective titles&lt;/li&gt;
&lt;li&gt;Tomek Dev - If there is an input, there should be a form&lt;/li&gt;
&lt;li&gt;Tomek Dev - Content Curation is going to be a job and how Content Marketing killed the web&lt;/li&gt;
&lt;li&gt;Tomek Dev - Dynamic partiallyActive Link in Gatsby&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Doesn't look that bad when I have it on a list, right? Right. But consider the real estate of a browser's toolbar:&lt;/p&gt;

&lt;p&gt;&lt;a href="/static/ea32f3e18777995abed8310e9fe81169/5d6a0/tabs-before.png"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftomekdev.com%2Fstatic%2Fea32f3e18777995abed8310e9fe81169%2Fd9199%2Ftabs-before.png" title="Tabs are packed. Redundant information doesn't help here" alt="Tabs are packed. Redundant information doesn't help here"&gt;&lt;/a&gt;Tabs are packed. Redundant information doesn't help here&lt;/p&gt;

&lt;p&gt;There is no lot of place but it can be even less if you use a lot of tabs. Having a title of your content first and the site name second will help in identification. The content title is more important for a user:&lt;/p&gt;

&lt;p&gt;&lt;a href="/static/032ba4d20661b8499822410ee2e3b5e4/5d6a0/tabs-after.png"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftomekdev.com%2Fstatic%2F032ba4d20661b8499822410ee2e3b5e4%2Fd9199%2Ftabs-after.png" title="Tabs are still packed but more valuable information gets first" alt="Tabs are still packed but more valuable information gets first"&gt;&lt;/a&gt;Tabs are still packed but more valuable information gets first&lt;/p&gt;
&lt;h3&gt;
  
  
  What separator to use
&lt;/h3&gt;

&lt;p&gt;I'm using a pipe - &lt;code&gt;|&lt;/code&gt; because my dad is a plumber and I spend a lot of my life in the terminal. What else could I use? 😉&lt;br&gt;&lt;br&gt;
Jokes aside, that could be a branding thing. Go crazy if that's your thing:&lt;/p&gt;

&lt;p&gt;&lt;a href="/static/d91c24d55bd34a87e80670460a70aafa/5d6a0/tabs-crazy.png"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftomekdev.com%2Fstatic%2Fd91c24d55bd34a87e80670460a70aafa%2Fd9199%2Ftabs-crazy.png" title="Here ♣ separates content title and the site name" alt="Here ♣ separates content title and the site name"&gt;&lt;/a&gt;Here ♣ separates content title and the site name&lt;/p&gt;

&lt;p&gt;&lt;a href="/static/6a3e3421252ed05c271cb19f2a3e5a69/0bdcb/tabs-crazy-2.png"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftomekdev.com%2Fstatic%2F6a3e3421252ed05c271cb19f2a3e5a69%2Fd9199%2Ftabs-crazy-2.png" title="Legal advice page with § as a separator? Why not" alt="Legal advice page with § as a separator? Why not"&gt;&lt;/a&gt;Legal advice page with § as a separator? Why not&lt;/p&gt;

&lt;p&gt;After all, the worst you can do is to have a single title for your entire application. &lt;strong&gt;Don't do that&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
Even if your app is just a tool, think for a while if you don't have some logical modules there. Because know what? 👇&lt;/p&gt;
&lt;h2&gt;
  
  
  Title can be changed dynamically
&lt;/h2&gt;

&lt;p&gt;That's good news (not only) for Single Page Applications. Use it to &lt;strong&gt;bring users' attention&lt;/strong&gt; to something. Consider Facebook for example:&lt;/p&gt;

&lt;p&gt;&lt;a href="/static/820c15f5fd745cc2185b558d9e89a878/5d6a0/tabs-facebook.png"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftomekdev.com%2Fstatic%2F820c15f5fd745cc2185b558d9e89a878%2Fd9199%2Ftabs-facebook.png" title="🤔 Something happened, right?" alt="🤔 Something happened, right?"&gt;&lt;/a&gt;🤔 Something happened, right?&lt;/p&gt;

&lt;p&gt;They encourage you to read the message you've just received. All you have to do to change the title of a page is setting it this way:&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;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;A new title! | Tomek Dev&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is a small GIF presenting how it works:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ft2gv3b92qw5rrbwgo4fy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ft2gv3b92qw5rrbwgo4fy.gif" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Of course, if a user is already on our page we should not distract them with a flashing title. Maybe change it only if the tab is not active?&lt;/p&gt;

&lt;p&gt;Consider this example, you work on a Video Editing application and people export their movie. The file has to be prepared and it takes time. You can show the progress on the title if they go to a different tab and announce a success. It could look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnjb3xz3udhr37785vkyv.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnjb3xz3udhr37785vkyv.gif" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First things first. How to detect the change of tab's visibility? (I've just used the right keywords there).&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;visibilitychange&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;function &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="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hidden&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;code&gt;document.hidden&lt;/code&gt; will tell you what's the status and you can modify the behavior accordingly to your needs. When it comes to the example above it was done this way:&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;originalTitle&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="nx"&gt;title&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;isTabHidden&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&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;percentage&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;changeTitle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;title&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;isTabHidden&lt;/span&gt;&lt;span class="p"&gt;)&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;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;title&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="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;originalTitle&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;interval&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setInterval&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;percentage&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&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;percentage&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&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="nf"&gt;changeTitle&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;percentage&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;% Preparing video | Tomek Dev`&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="nf"&gt;changeTitle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;⚬ Your file is ready! | Tomek Dev&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;clearInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;interval&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="mi"&gt;100&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="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;visibilitychange&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;isTabHidden&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="nx"&gt;hidden&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;It's obviously a trick to show how it could work. In this place, you'd put your code that updates the percentage value. That can come from a backend endpoint that is preparing the video. No matter if that's a WebSocket or regular XHR request.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Did you notice how progress slows down when I go to a different tab? It's because I'm faking the export progress via &lt;em&gt;setInterval&lt;/em&gt;. The tab is in the background so Chrome executes the timing function (&lt;em&gt;setTimeout&lt;/em&gt;/&lt;em&gt;setInterval&lt;/em&gt;) once per second at maximum.&lt;/p&gt;




&lt;p&gt;Eagle-eyed folks may notice that &lt;code&gt;visibilitychange&lt;/code&gt; listener is not needed in that example. We can use &lt;code&gt;document.hidden&lt;/code&gt; directly in our &lt;code&gt;changeTitle&lt;/code&gt; function. I added it here only to show that such a listener exists ;) It might be useful in some implementations.&lt;/p&gt;

&lt;p&gt;And do you know who (probably) uses that event? &lt;strong&gt;Github&lt;/strong&gt;. Open two tabs, leave an unsaved comment in a PR, and go to another tab. You should see this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5mymrie6koedq3l71hhl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5mymrie6koedq3l71hhl.png" alt="github-draft-comment"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Dynamic === fun
&lt;/h2&gt;

&lt;p&gt;Let me give you a few more examples of how you can make your title cool.&lt;/p&gt;

&lt;p&gt;These days, you should see a speaker icon 🔊 if the audio is played in a tab. But it wasn't always like that. You can animate an audio playing in various ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Let's show a listener&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F22zwdb046nediqf6h64y.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F22zwdb046nediqf6h64y.gif" alt="listener"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Or a dancer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Flacxjrws3n794dxz37dv.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Flacxjrws3n794dxz37dv.gif" alt="dancer"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Equalizer?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1gmyw5ipcb6oz78wbvoy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1gmyw5ipcb6oz78wbvoy.gif" alt="equalizer"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Song title floating&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fgbr36xxiexemjjnfcqr2.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fgbr36xxiexemjjnfcqr2.gif" alt="Yeah, I left some work there. Thanks for reminding me!"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  But be careful
&lt;/h3&gt;

&lt;p&gt;Of course, like with every superpower, there is one thing you need to remember. &lt;strong&gt;Don't overuse it.&lt;/strong&gt; Effects like this could be a very nice addition to your page. It can extend the experience and make it better. But it can also be annoying. Like a close button running away from your cursor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Maybe we've just scratched the surface of what we can do with &lt;code&gt;&amp;lt;title&amp;gt;&lt;/code&gt; but here are some takeaways for you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use a short descriptive title.&lt;/li&gt;
&lt;li&gt;Put your site name after the title describing the page's content.&lt;/li&gt;
&lt;li&gt;Add a separator between the title's parts. You can go crazy.&lt;/li&gt;
&lt;li&gt;Use the title's dynamic nature to extend the user experience.&lt;/li&gt;
&lt;li&gt;Bring users' attention to a tab if something important happened.&lt;/li&gt;
&lt;li&gt;Don't overuse dynamic techniques to avoid annoying users.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The real estate of the browser's top bar is yours now.&lt;/p&gt;

</description>
      <category>ux</category>
      <category>beginners</category>
      <category>html</category>
      <category>javascript</category>
    </item>
    <item>
      <title>If there is an input, there should be a form</title>
      <dc:creator>🤓 Tomek Nieżurawski</dc:creator>
      <pubDate>Sat, 17 Oct 2020 15:53:58 +0000</pubDate>
      <link>https://forem.com/tomekdev_/if-there-is-an-input-there-should-be-a-form-523l</link>
      <guid>https://forem.com/tomekdev_/if-there-is-an-input-there-should-be-a-form-523l</guid>
      <description>&lt;p&gt;&lt;em&gt;This post was originally published on &lt;a href="https://tomekdev.com/posts/input-and-form" rel="noopener noreferrer"&gt;https://tomekdev.com/posts/input-and-form&lt;/a&gt;. Go there to read a bit more interactive and style richer version&lt;/em&gt; ✌️&lt;/p&gt;




&lt;p&gt;I often see in Single Page apps a situation where someone uses just an &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt; field. Sometimes in the accompaniment of &lt;code&gt;&amp;lt;label&amp;gt;&lt;/code&gt; if you happen to work with a pro 🌟. It feels that when we gained control of inputs with two-way binding and we started handling &lt;code&gt;onclick&lt;/code&gt; events on buttons with our fancy frameworks, we forgot the old way of doing things.&lt;/p&gt;

&lt;h2&gt;
  
  
  The old way, and the right way
&lt;/h2&gt;

&lt;p&gt;The headline of this section may suggest that the old way and the right way are two different things. Where in fact, it's the opposite. If you come back with your memory before the frameworks (or ajax) era you see that people were using a &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt; element when dealing with inputs and buttons.&lt;/p&gt;

&lt;p&gt;In the past we were extensively using &lt;code&gt;&amp;lt;form method=""&amp;gt;&lt;/code&gt; to process the input. &lt;strong&gt;I encourage you to still use a form element&lt;/strong&gt;. It comes with benefits.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common mistake
&lt;/h2&gt;

&lt;p&gt;I use the keyboard to navigate and interact with pages. That speeds up everything. So for me one of the biggest pitfalls of using &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt; without a &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt; is that the input is not auto-submittable, so to say.&lt;/p&gt;

&lt;p&gt;When you hit &lt;code&gt;ENTER&lt;/code&gt; in the field that is inside the form then the form is submitted. That's very convenient for solo-input interfaces like a modal below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyi4bd1qj4ecnp2eqq327.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyi4bd1qj4ecnp2eqq327.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You don't have to touch your mouse or touchpad and click &lt;code&gt;Save&lt;/code&gt; button 🎉. That would be a waste of time!&lt;/p&gt;

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

&lt;p&gt;It's a common mistake to bind your action to a &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; where in fact all you have to do is wrap your&lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt; with a &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt; and assign &lt;code&gt;submit&lt;/code&gt; event to a form:&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;form&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"my-form"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"example"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Submit&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&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;form&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;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-form&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;form&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;submit&lt;/span&gt;&lt;span class="dl"&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;handleSubmit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Submit clicked&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&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;Don't forget to prevent default behavior from firing and run your custom behavior. It could be running validation and actually sending the data.&lt;/p&gt;

&lt;p&gt;One more thing that you should consider is always specifying button's type. It's &lt;code&gt;submit&lt;/code&gt; by default in most browsers but Internet Explorer is different in this case and has &lt;code&gt;button&lt;/code&gt; as a default type.&lt;/p&gt;

</description>
      <category>ux</category>
      <category>a11y</category>
    </item>
  </channel>
</rss>
