<?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: kandz</title>
    <description>The latest articles on DEV Community by kandz (@kandz).</description>
    <link>https://dev.to/kandz</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4010024%2Fba5408f9-0a6c-4392-8632-b33b6c9bb4df.jpg</url>
      <title>DEV Community: kandz</title>
      <link>https://dev.to/kandz</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kandz"/>
    <language>en</language>
    <item>
      <title>Understanding CSS Flexbox Wrap</title>
      <dc:creator>kandz</dc:creator>
      <pubDate>Thu, 17 Sep 2026 07:33:00 +0000</pubDate>
      <link>https://dev.to/kandz/understanding-css-flexbox-wrap-1bh3</link>
      <guid>https://dev.to/kandz/understanding-css-flexbox-wrap-1bh3</guid>
      <description>&lt;p&gt;Flexbox is one of those things that seems simple until it doesn't work. You set &lt;code&gt;flex-wrap: wrap&lt;/code&gt; and expect items to wrap. Then they don't. Or they wrap but leave weird gaps. Or &lt;code&gt;wrap-reverse&lt;/code&gt; flips things in ways you didn't expect.&lt;/p&gt;

&lt;p&gt;Let's break down how &lt;code&gt;flex-wrap&lt;/code&gt; actually works.&lt;/p&gt;




&lt;h2&gt;
  
  
  What flex-wrap Does
&lt;/h2&gt;

&lt;p&gt;By default, flexbox tries to fit everything on a single line. &lt;code&gt;flex-wrap&lt;/code&gt; controls what happens when items exceed the container width.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The three values:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;th&gt;Behavior&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;nowrap&lt;/code&gt; (default)&lt;/td&gt;
&lt;td&gt;All items on one line. Overflow if needed.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;wrap&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Items break into multiple lines.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;wrap-reverse&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Same as wrap, but lines stack in reverse order.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Why Items Don't Wrap (Even with flex-wrap: wrap)
&lt;/h2&gt;

&lt;p&gt;The most common problem: you set &lt;code&gt;flex-wrap: wrap&lt;/code&gt; but items still overflow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The cause:&lt;/strong&gt; &lt;code&gt;min-width: auto&lt;/code&gt; on flex items.&lt;/p&gt;

&lt;p&gt;By default, flex items refuse to shrink below their content's natural width. A long word, an image, or a fixed-width element can force the item wider than its container.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt;&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="nc"&gt;.flex-item&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;min-width&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allows items to shrink so wrapping can occur.&lt;/p&gt;




&lt;h2&gt;
  
  
  The align-content Trap
&lt;/h2&gt;

&lt;p&gt;If you have a fixed height on the container and use &lt;code&gt;flex-wrap: wrap&lt;/code&gt;, you might see unexpected gaps between rows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The cause:&lt;/strong&gt; &lt;code&gt;align-content&lt;/code&gt; defaults to &lt;code&gt;stretch&lt;/code&gt;, which distributes lines evenly to fill the container's height.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt;&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="nc"&gt;.flex-container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;align-content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex-start&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;h2&gt;
  
  
  wrap-reverse Explained
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;wrap-reverse&lt;/code&gt; does exactly what it says: wraps in reverse. The cross-start and cross-end directions are swapped. This is useful for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bottom-up layouts&lt;/li&gt;
&lt;li&gt;Certain animation effects&lt;/li&gt;
&lt;li&gt;Right-to-left wrapping&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But it's confusing because the visual order doesn't match the DOM order.&lt;/p&gt;




&lt;h2&gt;
  
  
  Testing Flexbox Wrap Visually
&lt;/h2&gt;

&lt;p&gt;If you want to see how &lt;code&gt;wrap&lt;/code&gt;, &lt;code&gt;wrap-reverse&lt;/code&gt;, and alignment constraints distribute items without writing code, I built a free CSS Flexbox Wrap Simulator. It runs 100% client-side:&lt;/p&gt;

&lt;p&gt;👉 tools.kandz.me/flexbox-wrap&lt;/p&gt;




&lt;p&gt;What's your biggest flexbox frustration? Let me know in the comments.&lt;/p&gt;

</description>
      <category>css</category>
      <category>webdev</category>
      <category>frontend</category>
      <category>design</category>
    </item>
    <item>
      <title>Understanding SVG ViewBox Coordinates</title>
      <dc:creator>kandz</dc:creator>
      <pubDate>Sun, 13 Sep 2026 09:44:20 +0000</pubDate>
      <link>https://dev.to/kandz/understanding-svg-viewbox-coordinates-854</link>
      <guid>https://dev.to/kandz/understanding-svg-viewbox-coordinates-854</guid>
      <description>&lt;p&gt;Debugging SVG viewBox coordinates by hand is a nightmare.&lt;/p&gt;

&lt;p&gt;You open an SVG file. You need to know where a specific shape sits. You start counting pixels. You guess. You're wrong. You start over.&lt;/p&gt;

&lt;p&gt;Let's fix that.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is a ViewBox?
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;viewBox&lt;/code&gt; attribute defines the coordinate system for an SVG. It has four values:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;viewBox="min-x min-y width height"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example, &lt;code&gt;viewBox="0 0 100 100"&lt;/code&gt; means the SVG uses a 100x100 coordinate system starting from (0,0).&lt;/p&gt;




&lt;h2&gt;
  
  
  The Two Coordinate Systems
&lt;/h2&gt;

&lt;p&gt;SVG has two coordinate systems working together:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;External size&lt;/strong&gt; — controlled by width/height attributes or CSS&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Internal coordinate system&lt;/strong&gt; — defined by viewBox&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When you set &lt;code&gt;viewBox="0 0 100 100"&lt;/code&gt; on an SVG that's 200x200px, the 100x100 user unit area is stretched to fit the 200x200 viewport. Each user unit becomes 2 screen pixels.&lt;/p&gt;




&lt;h2&gt;
  
  
  Moving the ViewBox
&lt;/h2&gt;

&lt;p&gt;Changing the &lt;code&gt;min-x&lt;/code&gt; and &lt;code&gt;min-y&lt;/code&gt; values moves the viewBox within the canvas. As one Stack Overflow user explained:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Conceptualize the viewBox as defining a transparent window in an opaque layer above the SVG canvas. When altering the viewBox attribute, you move the 'window' to the right without affecting the canvas — so your graphics move left relative to the 'window'."&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Zooming with ViewBox
&lt;/h2&gt;

&lt;p&gt;The width and height values control zoom. If your viewport is 300px wide but your viewBox width is 600px, you're seeing 600px of canvas squeezed into 300px — that's zooming out.&lt;/p&gt;




&lt;h2&gt;
  
  
  The preserveAspectRatio Attribute
&lt;/h2&gt;

&lt;p&gt;When the viewBox aspect ratio doesn't match the viewport, &lt;code&gt;preserveAspectRatio&lt;/code&gt; controls how the content is scaled and positioned. The default is &lt;code&gt;xMidYMid meet&lt;/code&gt; which centers the content and ensures the entire viewBox is visible.&lt;/p&gt;




&lt;h2&gt;
  
  
  Finding Coordinates in Practice
&lt;/h2&gt;

&lt;p&gt;When you're editing an SVG, you often need to know the exact coordinates of a shape within the viewBox. The &lt;code&gt;&amp;lt;circle&amp;gt;&lt;/code&gt; has &lt;code&gt;cx&lt;/code&gt; and &lt;code&gt;cy&lt;/code&gt;. The &lt;code&gt;&amp;lt;path&amp;gt;&lt;/code&gt; has raw coordinate data. The &lt;code&gt;&amp;lt;rect&amp;gt;&lt;/code&gt; has &lt;code&gt;x&lt;/code&gt;, &lt;code&gt;y&lt;/code&gt;, &lt;code&gt;width&lt;/code&gt;, and &lt;code&gt;height&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Finding those values manually is tedious. And when transforms are involved, it gets worse.&lt;/p&gt;

&lt;p&gt;If you want to visualize viewBox boundaries and extract shape coordinates without guessing, I built a free tool that does exactly this:&lt;/p&gt;

&lt;p&gt;👉 tools.kandz.me/svg-viewbox-finder&lt;/p&gt;




&lt;p&gt;What's your experience with SVG viewBox? Do you find it intuitive or confusing? Let me know in the comments.&lt;/p&gt;

</description>
      <category>svg</category>
      <category>webdev</category>
      <category>frontend</category>
      <category>design</category>
    </item>
    <item>
      <title>Converting TSV to YAML: A Guide to Reliable Data Serialization</title>
      <dc:creator>kandz</dc:creator>
      <pubDate>Wed, 09 Sep 2026 08:41:51 +0000</pubDate>
      <link>https://dev.to/kandz/converting-tsv-to-yaml-a-guide-to-reliable-data-serialization-113j</link>
      <guid>https://dev.to/kandz/converting-tsv-to-yaml-a-guide-to-reliable-data-serialization-113j</guid>
      <description>&lt;p&gt;When working with configuration management systems like Ansible, Kubernetes, or Docker Compose, YAML is the standard. But data often starts in spreadsheets, CSV exports, or tab-separated values (TSV) from databases.&lt;/p&gt;

&lt;p&gt;Manually converting TSV to YAML is error-prone. A single misplaced tab, an unescaped colon, or a missing hyphen can break your entire configuration.&lt;/p&gt;

&lt;p&gt;In this guide, I'll walk through how to convert TSV data to YAML reliably.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Understanding TSV and YAML
&lt;/h2&gt;

&lt;p&gt;TSV (Tab-Separated Values) is a simple file format where each row is a record and columns are separated by tabs. It's commonly exported from Excel, Google Sheets, and SQL databases.&lt;/p&gt;

&lt;p&gt;YAML (YAML Ain't Markup Language) is a human-readable data serialization format. It uses indentation to represent hierarchy, making it ideal for configuration files.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The challenge:&lt;/strong&gt; TSV is flat. YAML is hierarchical. Converting between them requires mapping columns to nested structures.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. The Parsing Problem
&lt;/h2&gt;

&lt;p&gt;A naive TSV parser splits each line by tabs. But this breaks when data contains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Empty fields&lt;/li&gt;
&lt;li&gt;Values with tabs inside strings&lt;/li&gt;
&lt;li&gt;Lines with inconsistent column counts&lt;/li&gt;
&lt;li&gt;Quoted strings with embedded separators&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The correct approach:&lt;/strong&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;parseTSV&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;csvData&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;string&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;lines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;csvData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&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;result&lt;/span&gt; &lt;span class="o"&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;line&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;lines&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="k"&gt;continue&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;row&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;row&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;cell&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;cell&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&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;result&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;h2&gt;
  
  
  3. Converting TSV to YAML
&lt;/h2&gt;

&lt;p&gt;Once parsed, the transformation is straightforward:&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;convertToYAML&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tsvData&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;string&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;rows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parseTSV&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tsvData&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;rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&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="k"&gt;return&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;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;rows&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;records&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;yamlObj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;records&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;row&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;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
    &lt;span class="nx"&gt;headers&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;header&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&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;obj&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;header&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&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="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="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;YAML&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;yamlObj&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;h2&gt;
  
  
  4. Edge Cases to Handle
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Issue&lt;/th&gt;
&lt;th&gt;Solution&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Empty rows&lt;/td&gt;
&lt;td&gt;Skip them&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Inconsistent columns&lt;/td&gt;
&lt;td&gt;Fill missing values with empty strings&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Special characters&lt;/td&gt;
&lt;td&gt;Escape in YAML&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Large datasets&lt;/td&gt;
&lt;td&gt;Process in chunks to avoid memory issues&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  5. Common Use Cases
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Kubernetes ConfigMaps&lt;/strong&gt; – Converting spreadsheet data into ConfigMap YAML&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ansible Inventory&lt;/strong&gt; – Mapping host data to inventory YAML&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docker Compose&lt;/strong&gt; – Building compose files from service tables&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Database Seed Data&lt;/strong&gt; – Exporting data to YAML fixtures&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  6. Client-Side Processing
&lt;/h2&gt;

&lt;p&gt;All parsing and conversion runs locally in your browser. Your data never leaves your device. This is critical when working with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Configuration files containing secrets&lt;/li&gt;
&lt;li&gt;Production database exports&lt;/li&gt;
&lt;li&gt;Internal project data&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Interactive Tool
&lt;/h2&gt;

&lt;p&gt;If you regularly convert TSV to YAML, I built a free tool that handles all these cases automatically:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;TSV to YAML Converter&lt;/strong&gt; – &lt;a href="http://tools.kandz.me/tsv-to-yaml" rel="noopener noreferrer"&gt;http://tools.kandz.me/tsv-to-yaml&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;What's your use case for converting TSV to YAML? Drop it in the comments.&lt;/p&gt;

</description>
      <category>yaml</category>
      <category>json</category>
      <category>data</category>
      <category>programming</category>
    </item>
    <item>
      <title>Designing UI Depth: Mastering the Physics of CSS Glassmorphism</title>
      <dc:creator>kandz</dc:creator>
      <pubDate>Fri, 04 Sep 2026 07:44:38 +0000</pubDate>
      <link>https://dev.to/kandz/designing-ui-depth-mastering-the-physics-of-css-glassmorphism-50ic</link>
      <guid>https://dev.to/kandz/designing-ui-depth-mastering-the-physics-of-css-glassmorphism-50ic</guid>
      <description>&lt;p&gt;User interface paradigms continuously swing between flat minimalism and layered skeuomorphism. The rise of &lt;strong&gt;Glassmorphism&lt;/strong&gt; — which simulates a translucent, frosted-glass pane floating over high-contrast background vectors — has emerged as a major design trend. When designed correctly, glassmorphism creates a beautiful sense of visual hierarchy, layering, and specular depth.&lt;/p&gt;

&lt;p&gt;However, writing production-ready glassmorphic CSS rules is not as simple as lowering element opacity. It requires a precise coordination of background refractions, border reflections, and drop shadow depths.&lt;/p&gt;

&lt;p&gt;In this technical guide, we will deconstruct the underlying CSS physics of glassmorphic layers, address critical cross-browser rendering quirks, and look at how to prototype these styles in code.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Backdrop Blurring: Filter vs. Backdrop-Filter
&lt;/h2&gt;

&lt;p&gt;The foundational element of glassmorphism is refraction — the bending of light as it passes through glass. In CSS, developers often confuse the standard &lt;code&gt;filter&lt;/code&gt; property with &lt;code&gt;backdrop-filter&lt;/code&gt;.&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="c"&gt;/* This is NOT glassmorphism */&lt;/span&gt;
&lt;span class="nc"&gt;.broken-glass-container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;blur&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;12px&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;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.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;h3&gt;
  
  
  Why this fails:
&lt;/h3&gt;

&lt;p&gt;The standard &lt;code&gt;filter: blur()&lt;/code&gt; property applies graphical filter adjustments directly to the element itself and &lt;strong&gt;all of its nested DOM children&lt;/strong&gt;. This means any paragraph text, headers, or buttons inside the card will also be blurred, rendering your copy completely illegible.&lt;/p&gt;

&lt;p&gt;To achieve frosted glass refraction, you must use the modern &lt;code&gt;backdrop-filter&lt;/code&gt; property:&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="c"&gt;/* This is true glassmorphism */&lt;/span&gt;
&lt;span class="nc"&gt;.frosted-glass-card&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;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="py"&gt;backdrop-filter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;blur&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;12px&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;-webkit-backdrop-filter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;blur&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;12px&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c"&gt;/* Safari Vendor Prefix */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;backdrop-filter&lt;/code&gt; property applies the blurring effect strictly to the underlying graphical layers &lt;strong&gt;visible behind the element&lt;/strong&gt;, keeping the overlay content, typography, and interactive buttons razor-sharp.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Cross-Browser Note&lt;/strong&gt;: Always declare &lt;code&gt;-webkit-backdrop-filter&lt;/code&gt; alongside &lt;code&gt;backdrop-filter&lt;/code&gt;. iOS Safari and macOS Safari still require the vendor prefix to render backdrop filters correctly.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  2. Simulating Specular Reflection with Borders
&lt;/h2&gt;

&lt;p&gt;In physical spaces, glass is bounded by a specular reflection — a subtle, high-contrast gleam of light bouncing off the bevel or edge of the sheet. Without this specular highlight, glassmorphism cards look like flat, semi-opaque boxes with no physical boundaries.&lt;/p&gt;

&lt;p&gt;We can simulate this reflection in CSS by adding a thin, semi-transparent border using &lt;code&gt;rgba&lt;/code&gt; color stops:&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="nc"&gt;.frosted-glass-card&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;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="py"&gt;backdrop-filter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;blur&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;12px&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;-webkit-backdrop-filter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;blur&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;12px&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c"&gt;/* Specular Highlight Edge */&lt;/span&gt;
  &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="nb"&gt;solid&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;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.25&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;This 1px border establishes a clean, bright, translucent edge that separates the card from busy background graphics, regardless of whether the background is dark or light.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. The Role of Shadow and Contrast
&lt;/h2&gt;

&lt;p&gt;Glassmorphic elements only look convincing when there is something to distort behind them. If you place a frosted-glass card over a flat, solid-colored background, the backdrop blur has nothing to refract, and the element simply looks like a flat grey or white box.&lt;/p&gt;

&lt;p&gt;To make the refraction pop, you must design with &lt;strong&gt;contrast&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Place glass cards over bright, high-contrast, multi-colored gradients or organic geometric shapes.&lt;/li&gt;
&lt;li&gt;Implement a soft, diffuse &lt;code&gt;box-shadow&lt;/code&gt; on the card to create physical elevation:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.frosted-glass-card&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;8px&lt;/span&gt; &lt;span class="m"&gt;32px&lt;/span&gt; &lt;span class="m"&gt;0&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.15&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;h2&gt;
  
  
  4. Programmatic RGBA Hex Mapping
&lt;/h2&gt;

&lt;p&gt;When building design tools, allowing users to select solid colors via standard HTML &lt;code&gt;&amp;lt;input type="color"&amp;gt;&lt;/code&gt; pickers requires converting those hex values into raw &lt;code&gt;rgba()&lt;/code&gt; parameters programmatically in order to map custom opacity sliders.&lt;/p&gt;

&lt;p&gt;Here is a type-safe TypeScript implementation that handles the translation of 3-digit and 6-digit hex values securely:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * Safely converts hexadecimal strings and alpha opacity into compliant RGBA parameters
 * @param hex The raw color string (e.g. "#ffffff" or "#fff")
 * @param alpha The opacity modifier between 0 and 1
 */&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;hexToRgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;alpha&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&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;clean&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;hex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&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="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="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Expand 3-digit hex shorthands (e.g. "fff" -&amp;gt; "ffffff")&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;clean&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&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="nx"&gt;clean&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;clean&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&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="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;char&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;char&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;char&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;join&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;clean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;16&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="nf"&gt;isNaN&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="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`rgba(255, 255, 255, &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;alpha&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="c1"&gt;// Safe fallback&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;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="mi"&gt;255&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;g&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="mi"&gt;255&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;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`rgba(&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;r&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;g&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;b&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;alpha&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This converter ensures all properties run 100% locally in your browser's private memory sandbox [1]. Since no assets or styles are ever sent to an external server, your local design schemes and configurations remain completely secure [1].&lt;/p&gt;




&lt;h2&gt;
  
  
  Interactive Playground
&lt;/h2&gt;

&lt;p&gt;If you want to visually adjust backdrop blurs, slide opacities, customize borders, and copy production-ready CSS and HTML across different high-contrast canvas backdrops:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://tools.kandz.me/glassmorphism-card" rel="noopener noreferrer"&gt;CSS Glassmorphism Card Designer on Kandz.me&lt;/a&gt;&lt;/strong&gt; [1]&lt;/p&gt;

&lt;p&gt;What are your thoughts on glassmorphism? Do you find backdrop blurs performant on mobile web rendering engines? Let's discuss in the comments!&lt;/p&gt;

</description>
      <category>css</category>
      <category>webdev</category>
      <category>uidesign</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Deep Merging in JavaScript: How to Recursively Combine Objects Without Losing Nested Properties</title>
      <dc:creator>kandz</dc:creator>
      <pubDate>Mon, 31 Aug 2026 07:54:44 +0000</pubDate>
      <link>https://dev.to/kandz/deep-merging-in-javascript-how-to-recursively-combine-objects-without-losing-nested-properties-b2k</link>
      <guid>https://dev.to/kandz/deep-merging-in-javascript-how-to-recursively-combine-objects-without-losing-nested-properties-b2k</guid>
      <description>&lt;p&gt;In JavaScript and TypeScript application architecture, combining configurations, managing nested state states, or applying user overrides to default settings are standard requirements. &lt;/p&gt;

&lt;p&gt;However, many developers still fall into the trap of using shallow copy mechanisms like &lt;code&gt;Object.assign()&lt;/code&gt; or the object spread operator (&lt;code&gt;...&lt;/code&gt;). When applied to nested objects, these approaches can lead to silent data loss, state mutations, and hard-to-track runtime bugs.&lt;/p&gt;

&lt;p&gt;In this technical breakdown, we will analyze why shallow merging fails on nested structures, explore the mechanics of a recursive deep merge algorithm, and write a type-safe, non-&lt;code&gt;any&lt;/code&gt; deep merge utility in TypeScript.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. The Fallacy of Shallow Merging
&lt;/h2&gt;

&lt;p&gt;Shallow copying only copies the top-level properties of an object. If a property is a reference type (like a nested object or array), only the reference pointer is copied—not the actual nested data.&lt;/p&gt;

&lt;p&gt;Consider this common configuration scenario:&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;defaultSettings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;light&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;api&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5000&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;userOverrides&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;api&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10000&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 Shallow Merge Trap&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mergedSettings&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="nx"&gt;defaultSettings&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;userOverrides&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;mergedSettings&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="cm"&gt;/*
Output:
{
  theme: 'light',
  api: {
    timeout: 10000
  }
}
*/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why did this fail?
&lt;/h3&gt;

&lt;p&gt;Because the spread operator performed a shallow assignment, the nested &lt;code&gt;api&lt;/code&gt; property on &lt;code&gt;userOverrides&lt;/code&gt; completely &lt;strong&gt;overwrote&lt;/strong&gt; the original &lt;code&gt;api&lt;/code&gt; object on &lt;code&gt;defaultSettings&lt;/code&gt;. As a result, the critical &lt;code&gt;endpoint&lt;/code&gt; property was completely lost.&lt;/p&gt;

&lt;p&gt;To combine nested properties rather than overwriting them, we must perform a &lt;strong&gt;Recursive Deep Merge&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. The Mechanics of a Recursive Deep Merge Algorithm
&lt;/h2&gt;

&lt;p&gt;A true deep merge algorithm must recursively traverse the object trees. If both objects share a key, the algorithm must evaluate the types of their respective values:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Both values are objects&lt;/strong&gt;: Recursively call the merge function to combine their sub-properties.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Both values are arrays&lt;/strong&gt;: Decide whether to concatenate them, keep unique elements, or overwrite with the new array.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Value types differ (or are primitives)&lt;/strong&gt;: Resolve the conflict by either keeping the original value or overwriting it based on a designated collision policy.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  3. Writing a Type-Safe Deep Merge Utility in TypeScript
&lt;/h2&gt;

&lt;p&gt;To ensure strict compiler compliance under modern TypeScript standards, we must avoid the forbidden &lt;code&gt;any&lt;/code&gt; type and build a robust, structurally typed merging engine. &lt;/p&gt;

&lt;p&gt;Here is the clean, type-safe implementation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * Safe helper checking if an item is a non-null, non-array object
 */&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;isObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;object&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * Recursively deep-merges two object trees securely
 * @param a The base target object
 * @param b The incoming override object
 * @param arrayStrategy How to handle array collisions ('concat' | 'unique' | 'replace')
 * @param conflictStrategy How to resolve primitive conflicts ('overwrite-b' | 'keep-a')
 */&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;deepMerge&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="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;unknown&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;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;unknown&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;arrayStrategy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;concat&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;unique&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;replace&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;concat&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;conflictStrategy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;overwrite-b&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;keep-a&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;overwrite-b&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;unknown&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;result&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="nx"&gt;a&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;key&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keys&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;valA&lt;/span&gt; &lt;span class="o"&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;key&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;valB&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&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="nf"&gt;isObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;valA&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;isObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;valB&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Both are objects: recurse deeper&lt;/span&gt;
      &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;deepMerge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;valA&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;unknown&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;valB&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;unknown&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;arrayStrategy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;conflictStrategy&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;valA&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;valB&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Both are arrays: apply array merging strategy&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;arrayStrategy&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;concat&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;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&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="nx"&gt;valA&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;valB&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arrayStrategy&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;unique&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;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;([...&lt;/span&gt;&lt;span class="nx"&gt;valA&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;valB&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;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&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="nx"&gt;valB&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="c1"&gt;// replace&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="c1"&gt;// Primitive or mismatched types: apply conflict resolution&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;valA&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;conflictStrategy&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;keep-a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;valA&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;valB&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;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;valB&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&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;h3&gt;
  
  
  Why this structure is secure:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Strong Type Assertions&lt;/strong&gt;: It uses structural record indexing (&lt;code&gt;Record&amp;lt;string, unknown&amp;gt;&lt;/code&gt;) to protect the compiler against type-erasure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Predictable Collisions&lt;/strong&gt;: By separating array strategies and value conflicts, the algorithm avoids random reference changes or unexpected state mutations.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Interactive Playground
&lt;/h2&gt;

&lt;p&gt;If you need to merge complex settings side-by-side, analyze conflicts, customize your array concatenation behaviors, and inspect the resulting JSON securely inside your local browser memory:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://tools.kandz.me/object-merger" rel="noopener noreferrer"&gt;JS Object Merging Utility on Kandz.me&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;How do you manage nested configurations in your frameworks? Let's discuss in the comments!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>typescript</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>Writing Secure Shell Scripts: A Guide to Auditing and Sanitizing Unsafe Bash Code</title>
      <dc:creator>kandz</dc:creator>
      <pubDate>Thu, 27 Aug 2026 10:58:13 +0000</pubDate>
      <link>https://dev.to/kandz/writing-secure-shell-scripts-a-guide-to-auditing-and-sanitizing-unsafe-bash-code-2d3h</link>
      <guid>https://dev.to/kandz/writing-secure-shell-scripts-a-guide-to-auditing-and-sanitizing-unsafe-bash-code-2d3h</guid>
      <description>&lt;p&gt;Shell scripting remains the connective tissue of modern deployment pipelines, system administration, and container orchestration. Yet, despite its ubiquity, Bash is notoriously fragile. A single unquoted variable or a missing error handling flag can result in disastrous silent failures, partial script executions, or critical security vulnerabilities.&lt;/p&gt;

&lt;p&gt;In this technical guide, we will analyze common, high-risk anti-patterns in Bash scripts, explain why standard shell environments fail silently, and demonstrate how to programmatically audit shell script structures for duplicate variables and unsafe parameters.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. The High-Risk Anti-Patterns of Silent Bash Failures
&lt;/h2&gt;

&lt;p&gt;By default, Bash execution engines are designed to be permissive. Unlike strict programming environments that throw exceptions and halt execution on errors, shell scripts will happily continue executing even if a key command fails or a variable is undefined.&lt;/p&gt;

&lt;h3&gt;
  
  
  Anti-Pattern A: Missing Safety Headers
&lt;/h3&gt;

&lt;p&gt;Consider this snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="nv"&gt;TARGET_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TARGET_DIR&lt;/span&gt;&lt;span class="s2"&gt;/*"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If this script is executed without arguments, &lt;code&gt;TARGET_DIR&lt;/code&gt; remains an empty string. The shell expands the command to &lt;code&gt;rm -rf /*&lt;/code&gt;, which will attempt to recursively delete the host machine's root directory.&lt;/p&gt;

&lt;h3&gt;
  
  
  Anti-Pattern B: Unquoted Variables and Word Splitting
&lt;/h3&gt;

&lt;p&gt;When you reference a variable without wrapping it in double quotes (e.g., &lt;code&gt;echo $FILE_NAME&lt;/code&gt;), the shell subjects the variable's value to &lt;strong&gt;Word Splitting&lt;/strong&gt; and &lt;strong&gt;Pathname Expansion (Globbing)&lt;/strong&gt; based on internal field separator (IFS) whitespace. If a file name contains spaces, the shell will treat it as multiple separate arguments, leading to unexpected behaviors or syntax failures in conditional tests.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Establishing a Strict Safety Standard
&lt;/h2&gt;

&lt;p&gt;The first step in securing any shell script is to configure a defensive execution header using the &lt;code&gt;set&lt;/code&gt; built-in utility.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Deconstructing the Safe Header Flags:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;set -e&lt;/code&gt; (Exit Immediately)&lt;/strong&gt;: Tells the shell to terminate the script immediately if any command exits with a non-zero status code. This prevents silent cascades where later scripts run despite previous critical dependency failures.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;set -u&lt;/code&gt; (Nounset)&lt;/strong&gt;: Treats any reference to an uninitialized or unbound variable as a fatal syntax error, instantly stopping execution (safeguarding against empty path expansions).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;set -o pipefail&lt;/code&gt; (Pipeline Failures)&lt;/strong&gt;: Normally, a pipeline's exit status is only determined by the very last command. Using &lt;code&gt;pipefail&lt;/code&gt; ensures that if any command in a pipeline fails (e.g., &lt;code&gt;cat missing_file | grep 'pattern'&lt;/code&gt;), the entire pipeline returns a failing exit status.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  3. Auditing Variables and Parameters in TypeScript
&lt;/h2&gt;

&lt;p&gt;To help developers proactively scan their scripts for vulnerabilities before deploying them to production, we can write a client-side parser in TypeScript that audits variables and detects common anomalies like &lt;strong&gt;duplicate declarations&lt;/strong&gt; or &lt;strong&gt;unsafe variable assignments&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Below is a robust, type-safe implementation of a static script scanner:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;SanitizationReport&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;isValid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;warnings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * Parses and audits raw Bash code for common vulnerabilities and duplicate assignments
 * @param scriptSource The raw shell script string to audit
 */&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;sanitizeBashScript&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scriptSource&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;SanitizationReport&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;warnings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;lines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;scriptSource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\r?\n&lt;/span&gt;&lt;span class="sr"&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;declaredVariables&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Set&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&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;// Check for safety headers&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;firstLine&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;lines&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="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;lines&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="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()&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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;firstLine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startsWith&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="nx"&gt;warnings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Warning: Missing standard Shebang header (e.g., #!/bin/bash).&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;scriptBody&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;scriptSource&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;/#.*/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="c1"&gt;// Strip comments&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;scriptBody&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;set -e&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;scriptBody&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;set -o pipefail&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;warnings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Security Alert: Script lacks strict safety controls (e.g., "set -euo pipefail" is highly recommended).&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="c1"&gt;// Detect variable declarations and check for duplicates&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;variableDeclarationRegex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/^&lt;/span&gt;&lt;span class="se"&gt;\s&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-zA-Z_&lt;/span&gt;&lt;span class="se"&gt;][&lt;/span&gt;&lt;span class="sr"&gt;a-zA-Z0-9_&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt;&lt;span class="se"&gt;)\s&lt;/span&gt;&lt;span class="sr"&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;let&lt;/span&gt; &lt;span class="nx"&gt;i&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;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;lines&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="nx"&gt;i&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Ignore lines that are comments or empty&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;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startsWith&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="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&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="k"&gt;continue&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;match&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;variableDeclarationRegex&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;match&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;match&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;varName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;match&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;declaredVariables&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;varName&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;warnings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Line &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;i&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="s2"&gt;: Variable "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;varName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;" is redeclared. Verify if this duplicate assignment was intentional.`&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;declaredVariables&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="nx"&gt;varName&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;// Flag dangerous patterns like unquoted directory removals&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;line&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rm -rf&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="sr"&gt;/rm -rf&lt;/span&gt;&lt;span class="se"&gt;\s&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-zA-Z0-9_&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;(\s&lt;/span&gt;&lt;span class="sr"&gt;|$&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;line&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;warnings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Line &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;i&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="s2"&gt;: Unsafe recursive removal detected. Variables in "rm -rf" should always be double-quoted to prevent root deletions.`&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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;isValid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;warnings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&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;warnings&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;This secure script parser performs all structural inspections entirely client-side. Since no script payloads or deployment credentials are sent over the network, your server keys, database ports, and infrastructure parameters remain completely secure in your browser.&lt;/p&gt;




&lt;h2&gt;
  
  
  Interactive Playground
&lt;/h2&gt;

&lt;p&gt;If you want to validate your Bash scripts, automatically audit variables, strip unsafe parameters, and copy sanitized script headers, feel free to try our free developer tool:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://tools.kandz.me/bash-sanitizer" rel="noopener noreferrer"&gt;Bash Script Sanitizer on Kandz.me&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;How do you secure your production shell scripts? Do you enforce strict linters in your CI/CD pipelines? Let's discuss in the comments!&lt;/p&gt;

</description>
      <category>bash</category>
      <category>devops</category>
      <category>security</category>
      <category>shell</category>
    </item>
    <item>
      <title>Mastering CSS Grid: Visual Layout Prototyping with grid-template-areas</title>
      <dc:creator>kandz</dc:creator>
      <pubDate>Sun, 23 Aug 2026 10:09:29 +0000</pubDate>
      <link>https://dev.to/kandz/mastering-css-grid-visual-layout-prototyping-with-grid-template-areas-3602</link>
      <guid>https://dev.to/kandz/mastering-css-grid-visual-layout-prototyping-with-grid-template-areas-3602</guid>
      <description>&lt;p&gt;Designing responsive web layouts has historically been a balancing act of float properties, absolute position rules, and nested flexbox containers. While CSS Grid introduced a highly structured 2D grid model, many developers still rely on manual column and row span indices (&lt;code&gt;grid-column: 1 / 3;&lt;/code&gt;). &lt;/p&gt;

&lt;p&gt;If you are looking for a more declarative, semantic, and maintainable approach to responsive layouts, &lt;strong&gt;CSS Grid Template Areas&lt;/strong&gt; (&lt;code&gt;grid-template-areas&lt;/code&gt;) is the ultimate standard.&lt;/p&gt;

&lt;p&gt;In this technical breakdown, we will deconstruct how named grid areas work, why they make media queries cleaner, and how to build a client-side visual grid layout editor in TypeScript.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. The Power of Declarative Named Grid Areas
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;grid-template-areas&lt;/code&gt; property allows you to define your layout using clear string templates. Each row in your grid is defined as a string, and each word inside that string represents a single grid cell.&lt;/p&gt;

&lt;p&gt;Consider this classic "Holy Grail" grid layout configuration:&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="nc"&gt;.grid-layout&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="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;grid-template-columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="py"&gt;grid-template-rows&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;grid-template-areas&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="s1"&gt;"header  header  header"&lt;/span&gt;
    &lt;span class="s1"&gt;"sidebar main    main"&lt;/span&gt;
    &lt;span class="s1"&gt;"sidebar footer  footer"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;gap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;16px&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 of managing mathematical indices, we assign grid areas by name:&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="nc"&gt;.header&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;grid-area&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.sidebar&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;grid-area&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;sidebar&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.main&lt;/span&gt;    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;grid-area&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.footer&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;grid-area&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;footer&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;h3&gt;
  
  
  Key Architectural Benefits:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Self-Documenting Code&lt;/strong&gt;: Your stylesheet visualizes the structural page layout directly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Separation of Concerns&lt;/strong&gt;: Your semantic HTML remains completely unaffected by layout changes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero-Math Spans&lt;/strong&gt;: The browser automatically handles merging and spanning boundaries based on adjacent matching names.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Empty Spacers Made Simple&lt;/strong&gt;: To leave a cell completely empty, you simply use a dot (&lt;code&gt;.&lt;/code&gt;) inside your template string (e.g., &lt;code&gt;"header . sidebar"&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  2. Responsive UI Design via Simple Media Queries
&lt;/h2&gt;

&lt;p&gt;One of the greatest advantages of named grid areas is the ease of responsive design. Instead of restructuring your HTML document structure, or changing multiple columns and rows spans on individual elements, you only need to redefine the &lt;code&gt;grid-template-areas&lt;/code&gt; property on the &lt;strong&gt;parent grid container&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Here is how you redefine the same template structure on mobile devices:&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="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;768px&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.grid-layout&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="py"&gt;grid-template-columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="py"&gt;grid-template-areas&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="s1"&gt;"header"&lt;/span&gt;
      &lt;span class="s1"&gt;"main"&lt;/span&gt;
      &lt;span class="s1"&gt;"sidebar"&lt;/span&gt;
      &lt;span class="s1"&gt;"footer"&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;The browser handles repositioning the elements seamlessly.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Designing a Client-Side Grid Layout Painter in TypeScript
&lt;/h2&gt;

&lt;p&gt;To help developers build and experiment with these configurations, we developed a local client-side visual painter. &lt;/p&gt;

&lt;p&gt;We can model the grid states reactively in TypeScript. By representing the grid canvas as a flat array of cell tags corresponding to &lt;code&gt;[rowsCount * colsCount]&lt;/code&gt;, users can click cells to change their area assignments in real-time.&lt;/p&gt;

&lt;p&gt;Here is the core logic to compile the CSS string and distinct selectors:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * Compiles a flat grid array into compliant CSS grid-template-areas strings
 * @param cells Array of area strings (e.g., ['header', 'header', 'main', ...])
 * @param rows Total rows in the layout
 * @param cols Total columns in the layout
 */&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;compileGridTemplate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cells&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cols&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&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;areaRows&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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="k"&gt;for &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;i&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;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rowSlice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cells&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;cols&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&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="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;cols&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;rowStr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;rowSlice&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;cell&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;cell&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;empty&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;.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cell&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;join&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="nx"&gt;areaRows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&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;rowStr&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="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;areaRows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&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="cm"&gt;/**
 * Extracts unique class area selectors for layout structures
 */&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getDistinctSelectors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cells&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]):&lt;/span&gt; &lt;span class="kr"&gt;string&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;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cells&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;c&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;c&lt;/span&gt; &lt;span class="o"&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="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;empty&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;This model compiles the grid definitions instantly inside your browser's private memory sandbox. This ensures maximum privacy, so your custom structures and designs are never sent to external servers.&lt;/p&gt;




&lt;h2&gt;
  
  
  Interactive Playground
&lt;/h2&gt;

&lt;p&gt;If you want to visually paint layouts, customize dimensions, define custom brush tools, and copy ready-to-use CSS and HTML, feel free to try our free developer tool:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://tools.kandz.me/grid-template-areas" rel="noopener noreferrer"&gt;CSS Grid Template Areas Visualizer on Kandz.me&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;How do you manage your CSS Grid structures? Do you prefer manual span properties or named areas? Let's discuss in the comments!&lt;/p&gt;

</description>
      <category>css</category>
      <category>webdev</category>
      <category>frontend</category>
      <category>html</category>
    </item>
    <item>
      <title>Measuring Code Quality: Building a Client-Side JavaScript Complexity &amp; Maintainability Analyzer</title>
      <dc:creator>kandz</dc:creator>
      <pubDate>Wed, 19 Aug 2026 08:24:35 +0000</pubDate>
      <link>https://dev.to/kandz/measuring-code-quality-building-a-client-side-javascript-complexity-maintainability-analyzer-5a8m</link>
      <guid>https://dev.to/kandz/measuring-code-quality-building-a-client-side-javascript-complexity-maintainability-analyzer-5a8m</guid>
      <description>&lt;p&gt;As codebases scale under aggressive product cycles, functions can easily become bloated with deeply nested loops and excessive conditional branches. This increases technical debt and makes unit testing much harder.&lt;/p&gt;

&lt;p&gt;To help developers audit their code hygiene instantly and securely, we built a &lt;strong&gt;JS Code Complexity Analyzer&lt;/strong&gt; running completely client-side. Here is a technical breakdown of how we calculated McCabe's Cyclomatic Complexity, mapped maximum nesting depths, and approximated the industry-standard Maintainability Index in the browser.&lt;/p&gt;




&lt;h3&gt;
  
  
  1. The Mathematics of Cyclomatic Complexity
&lt;/h3&gt;

&lt;p&gt;Developed by Thomas J. McCabe in 1976, &lt;strong&gt;Cyclomatic Complexity&lt;/strong&gt; measures the number of linearly independent execution paths through a program's source code. &lt;/p&gt;

&lt;p&gt;Rather than loading a heavy Abstract Syntax Tree (AST) parser in the browser, our engine performs a highly efficient, regex-based token scan. The algorithm starts with a baseline complexity score of &lt;code&gt;1&lt;/code&gt;. For each decision node or branching point detected in the code, the score increases by &lt;code&gt;1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We scan lines for the following branching patterns (while ignoring matches found inside comments):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Conditional branches: &lt;code&gt;if&lt;/code&gt;, &lt;code&gt;case&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Loop structures: &lt;code&gt;for&lt;/code&gt;, &lt;code&gt;while&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Error handling: &lt;code&gt;catch&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Logical operators: &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt;, &lt;code&gt;||&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Ternary operators: &lt;code&gt;?&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A higher score indicates more independent paths, warning developers that the function requires more unit tests to cover all execution conditions.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Scanning Maximum Nesting Depth
&lt;/h3&gt;

&lt;p&gt;Nesting depth measures how deeply control structures are layered inside one another. High complexity with flat nesting is often manageable, but deeply nested code is notoriously hard to read.&lt;/p&gt;

&lt;p&gt;Our engine calculates the maximum nesting depth by scanning the brace-balance (&lt;code&gt;{&lt;/code&gt; and &lt;code&gt;}&lt;/code&gt;) of the code block sequentially. It tracks the current nesting depth in real-time, recording the maximum depth reached during the lexical scan.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;currentDepth&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;let&lt;/span&gt; &lt;span class="nx"&gt;maxDepth&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="k"&gt;for &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;i&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;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;code&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="nx"&gt;i&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="k"&gt;if &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="nx"&gt;i&lt;/span&gt;&lt;span class="p"&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;{&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;currentDepth&lt;/span&gt;&lt;span class="o"&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;currentDepth&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;maxDepth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;maxDepth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;currentDepth&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="k"&gt;else&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;code&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&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;}&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;currentDepth&lt;/span&gt; &lt;span class="o"&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;max&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;currentDepth&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="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  3. Approximating the Maintainability Index
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;Maintainability Index&lt;/strong&gt; is an industry-standard metric (ranging from 0% to 100%) indicating how easy the code is to support and modify. The classic formula balances Halstead Volume, Cyclomatic Complexity, and Source Lines of Code (SLOC).&lt;/p&gt;

&lt;p&gt;Our engine calculates a highly reliable approximation of this index using a logarithmic scale:&lt;/p&gt;

&lt;p&gt;$$\text{Maintainability Index} = 171 - (3.5 \times \ln(\text{Complexity})) - (0.23 \times \text{Complexity}) - (16.2 \times \ln(\text{SLOC}))$$&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Excellent Maintainability:&lt;/strong&gt; Scores above 75% (low complexity, short, clean).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Moderate Maintainability:&lt;/strong&gt; Scores between 50% and 75%.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Low Maintainability:&lt;/strong&gt; Scores below 50% (high complexity, deep nesting, long lines).&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  4. Interactive Sandbox &amp;amp; Security Hygiene
&lt;/h3&gt;

&lt;p&gt;The tool displays these metrics on a responsive dashboard:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;McCabes Complexity Score:&lt;/strong&gt; Classified by risk ratings (Low Risk &amp;lt; 10, Moderate Risk 10–15, High Risk &amp;gt; 15).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nesting Depth Counter:&lt;/strong&gt; Flags blocks nested too deeply.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SLOC Breakdown:&lt;/strong&gt; Tracks actual Source Lines of Code, comments, and blank spacer lines.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Transmitting proprietary enterprise code, server router functions, or security scripts to external servers poses a severe privacy risk. By executing all static analysis, regex parsing, and index math locally inside your browser's private sandbox memory, your configurations remain completely secure.&lt;/p&gt;

&lt;p&gt;Test your custom JavaScript routines, analyze nested loops, and check your complexity scores:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;Test the Live Tool:&lt;/strong&gt; &lt;a href="https://tools.kandz.me/code-complexity" rel="noopener noreferrer"&gt;https://tools.kandz.me/code-complexity&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>architecture</category>
      <category>programming</category>
    </item>
    <item>
      <title>Building a High-Performance, Client-Side JSON Diff Checker Using Dynamic Programming (LCS)</title>
      <dc:creator>kandz</dc:creator>
      <pubDate>Sat, 15 Aug 2026 10:34:04 +0000</pubDate>
      <link>https://dev.to/kandz/building-a-high-performance-client-side-json-diff-checker-using-dynamic-programming-lcs-560i</link>
      <guid>https://dev.to/kandz/building-a-high-performance-client-side-json-diff-checker-using-dynamic-programming-lcs-560i</guid>
      <description>&lt;p&gt;Comparing nested JSON configuration files across builds or API revisions is a constant necessity in backend development. While standard text diffing utilities exist, semantic JSON comparison requires robust syntax validation combined with clean line-by-line alignment.&lt;/p&gt;

&lt;p&gt;To solve this, we built a secure, client-side &lt;strong&gt;JSON Diff Checker&lt;/strong&gt; that parses, formats, and compares JSON documents locally. Here is a technical breakdown of how we engineered its dynamic programming comparison engine and why local validation matters.&lt;/p&gt;




&lt;h3&gt;
  
  
  The Architecture: JSON Parsing + LCS Line Mapping
&lt;/h3&gt;

&lt;p&gt;A high-fidelity JSON diff utility cannot simply run a raw text string comparison; doing so would highlight harmless differences like varying spacing or reordered properties as false positives. Our engine operates in two clean phases:&lt;/p&gt;

&lt;h4&gt;
  
  
  Phase 1: Semantic Standardizing
&lt;/h4&gt;

&lt;p&gt;First, both inputs are parsed safely via standard browser JSON libraries. This step validates JSON well-formedness, capturing trailing commas, mismatched braces, or double-quote syntax warnings. Once parsed, the objects are compiled back into formatted string arrays with standard 2-space indentation. This standardizes whitespace and makes comparison line-by-row predictable.&lt;/p&gt;

&lt;h4&gt;
  
  
  Phase 2: Longest Common Subsequence (LCS)
&lt;/h4&gt;

&lt;p&gt;Second, we run a dynamic programming LCS algorithm over the standardized line arrays to find the shortest edit path. Here is how the recursive traceback matrix computes the state of each line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Dynamic programming matrix initialization&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[][]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&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="nf"&gt;fill&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="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&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="nf"&gt;fill&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="k"&gt;for &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;i&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="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&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;i&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="k"&gt;for &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;j&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="nx"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;j&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;leftLines&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&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="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;rightLines&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;j&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="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&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="nx"&gt;j&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="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="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;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&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;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&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="nx"&gt;j&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="nx"&gt;j&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="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;By traversing the completed matrix, the engine identifies exactly which formatted lines were &lt;strong&gt;added&lt;/strong&gt; (+), &lt;strong&gt;removed&lt;/strong&gt; (-), or &lt;strong&gt;kept unchanged&lt;/strong&gt; (➔), mapping precise line numbers to both columns.&lt;/p&gt;




&lt;h3&gt;
  
  
  Core Symmetrical Design &amp;amp; Features
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Instant Syntax Diagnostics:&lt;/strong&gt; If either JSON input is malformed, the visualizer halts gracefully, displaying clear syntax error messages and pinpointing the structural issue.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Symmetrical Layout Sizing:&lt;/strong&gt; Built with a 5-column control console on the left (for source payloads and presets) and a 7-column highlight scrollbox on the right (height restricted to 450px) to maintain a perfectly balanced layout.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Log Snapping with Custom Names:&lt;/strong&gt; Includes an editable configuration label so you can save your compared datasets with distinct names (e.g., "User Profile Verification") directly to your local History Log.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Try out the interactive comparison sandbox, paste your configurations, and test the dynamic alignment yourself:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;Test the Live Tool:&lt;/strong&gt; &lt;a href="https://tools.kandz.me/json-diff" rel="noopener noreferrer"&gt;https://tools.kandz.me/json-diff&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>json</category>
      <category>algorithms</category>
    </item>
    <item>
      <title>Visualizing the JavaScript Call Stack &amp; Event Loop: A Deep Dive Into Runtime Mechanics</title>
      <dc:creator>kandz</dc:creator>
      <pubDate>Fri, 14 Aug 2026 09:23:44 +0000</pubDate>
      <link>https://dev.to/kandz/visualizing-the-javascript-call-stack-event-loop-a-deep-dive-into-runtime-mechanics-46i7</link>
      <guid>https://dev.to/kandz/visualizing-the-javascript-call-stack-event-loop-a-deep-dive-into-runtime-mechanics-46i7</guid>
      <description>&lt;p&gt;How does single-threaded JavaScript handle asynchronous tasks without blocking the main execution thread? The answer lies in the orchestration of the &lt;strong&gt;Call Stack&lt;/strong&gt;, &lt;strong&gt;Web APIs&lt;/strong&gt;, the &lt;strong&gt;MicroTask Queue&lt;/strong&gt;, the &lt;strong&gt;Callback (MacroTask) Queue&lt;/strong&gt;, and the &lt;strong&gt;Event Loop&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;To help developers and students master these runtime operations, we built an interactive, step-by-step visualizer running completely client-side. Here is a technical breakdown of how the engine works, how we modeled its stages, and how you can use it to debug complex asynchronous execution patterns.&lt;/p&gt;




&lt;h3&gt;
  
  
  The Architecture of the JavaScript Runtime
&lt;/h3&gt;

&lt;p&gt;Under the hood, JavaScript engines (such as V8 or SpiderMonkey) run on a single main thread. To execute code synchronously and asynchronously, the runtime coordinates five distinct components:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The Call Stack (LIFO):&lt;/strong&gt; Tracks active function execution contexts. When a function is called, its frame is pushed to the top of the stack. When it completes, it is popped off.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Web APIs / Platform Environment:&lt;/strong&gt; Handles background, asynchronous operations like DOM events, &lt;code&gt;fetch&lt;/code&gt; requests, and &lt;code&gt;setTimeout&lt;/code&gt; timers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The MicroTask Queue:&lt;/strong&gt; A high-priority FIFO (First-In, First-Out) queue that stores callbacks from resolved Promises (e.g., &lt;code&gt;.then()&lt;/code&gt; handlers) and MutationObservers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Callback Queue (MacroTask Queue):&lt;/strong&gt; A lower-priority FIFO queue storing callbacks from completed timers (like &lt;code&gt;setTimeout&lt;/code&gt; or &lt;code&gt;setInterval&lt;/code&gt;) and network handshakes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Event Loop:&lt;/strong&gt; A continuous ticking mechanism that monitors the Call Stack. Once the stack is completely empty, it drains the entire MicroTask Queue before pulling a single callback from the MacroTask Queue.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Modeling Asynchronous Priority (The Classic Interview Question)
&lt;/h3&gt;

&lt;p&gt;One of the most common JavaScript interview questions tests the priority of microtasks over macrotasks:&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;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="s2"&gt;Start&lt;/span&gt;&lt;span class="dl"&gt;"&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="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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Timeout&lt;/span&gt;&lt;span class="dl"&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="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Promise&lt;/span&gt;&lt;span class="dl"&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;End&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;What is the execution order? Our visualizer models this step-by-step:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Synchronous Execution:&lt;/strong&gt; &lt;code&gt;console.log("Start")&lt;/code&gt; and &lt;code&gt;console.log("End")&lt;/code&gt; are pushed directly to the Call Stack and execute instantly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;setTimeout Registration:&lt;/strong&gt; &lt;code&gt;setTimeout&lt;/code&gt; is called. The 0ms timer triggers instantly, and the browser transfers &lt;code&gt;cb_Timeout&lt;/code&gt; directly to the &lt;strong&gt;Callback Queue (MacroTask)&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Promise Registration:&lt;/strong&gt; &lt;code&gt;Promise.resolve()&lt;/code&gt; resolves instantly. The &lt;code&gt;.then()&lt;/code&gt; handler registers &lt;code&gt;cb_Promise&lt;/code&gt; into the high-priority &lt;strong&gt;MicroTask Queue&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Stack Clears:&lt;/strong&gt; Once the synchronous script finishes, the Call Stack becomes empty.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MicroTask Execution:&lt;/strong&gt; The Event Loop ticks. It prioritizes the &lt;strong&gt;MicroTask Queue&lt;/strong&gt;, pulling &lt;code&gt;cb_Promise&lt;/code&gt; onto the stack. It prints &lt;code&gt;"Promise"&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MacroTask Execution:&lt;/strong&gt; Only after the MicroTask Queue is completely drained does the Event Loop pull &lt;code&gt;cb_Timeout&lt;/code&gt; from the Callback Queue. It prints &lt;code&gt;"Timeout"&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This results in the correct sequence: &lt;code&gt;Start&lt;/code&gt; ➔ &lt;code&gt;End&lt;/code&gt; ➔ &lt;code&gt;Promise&lt;/code&gt; ➔ &lt;code&gt;Timeout&lt;/code&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  Core Visualizer Features
&lt;/h3&gt;

&lt;p&gt;We built this simulator with several interactive debugging controls to make tracing these transitions intuitive:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;High-Fidelity Step Navigation:&lt;/strong&gt; Step forward or backward through execution frames manually to analyze the exact state change of every queue.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auto-Playback Control:&lt;/strong&gt; Adjust simulation speeds from 500ms to 3500ms to watch the queues animate and update dynamically.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Synchronized Code Highlighting:&lt;/strong&gt; The editor panel highlights the active line of code corresponding to the frame currently executing in the Call Stack.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live Interactive Terminal:&lt;/strong&gt; A simulated console prints logs in real-time as execution frames are processed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Try out the interactive simulation, step through custom asynchronous examples, and analyze the execution loops yourself:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;Test the Live Visualizer:&lt;/strong&gt; &lt;a href="https://tools.kandz.me/call-stack-visualizer" rel="noopener noreferrer"&gt;https://tools.kandz.me/call-stack-visualizer&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>architecture</category>
      <category>programming</category>
    </item>
    <item>
      <title>Under the Hood: Building an Interactive CSS Cubic Bezier Curve Designer</title>
      <dc:creator>kandz</dc:creator>
      <pubDate>Wed, 12 Aug 2026 05:01:04 +0000</pubDate>
      <link>https://dev.to/kandz/under-the-hood-building-an-interactive-css-cubic-bezier-curve-designer-5bhj</link>
      <guid>https://dev.to/kandz/under-the-hood-building-an-interactive-css-cubic-bezier-curve-designer-5bhj</guid>
      <description>&lt;p&gt;In modern UI/UX development, animations dictate how organic and responsive digital interfaces feel. Linear transitions feel static and industrial because physical objects in the real world do not instantly accelerate and decelerate at uniform speeds. Instead, high-quality, professional user interfaces rely on non-linear motion paths that simulate physical characteristics like momentum, friction, and elasticity.&lt;/p&gt;

&lt;p&gt;To help web developers design and visualize these parameters, we built the &lt;strong&gt;CSS Animation Timing Function Curve Designer&lt;/strong&gt; on &lt;code&gt;tools.kandz.me&lt;/code&gt;. Here is a deep dive into the math, layout challenges, and browser rendering models that power it under the hood.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. The Mathematics of Cubic Bezier Curves
&lt;/h2&gt;

&lt;p&gt;A standard CSS transition timing function uses a Cubic Bezier curve defined by four coordinate control points: the anchor start &lt;code&gt;(0, 0)&lt;/code&gt;, the anchor end &lt;code&gt;(1, 1)&lt;/code&gt;, and two independent control handles &lt;code&gt;P1 (x1, y1)&lt;/code&gt; and &lt;code&gt;P2 (x2, y2)&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;While the horizontal time-axis coordinates (&lt;code&gt;x1&lt;/code&gt; and &lt;code&gt;x2&lt;/code&gt;) must strictly remain within the bounds of &lt;code&gt;0&lt;/code&gt; and &lt;code&gt;1&lt;/code&gt; to prevent temporal paradoxes (which is why our sliders enforce this range), the vertical progress-axis coordinates (&lt;code&gt;y1&lt;/code&gt; and &lt;code&gt;y2&lt;/code&gt;) are unbound.&lt;/p&gt;

&lt;p&gt;By setting values less than &lt;code&gt;0&lt;/code&gt; or greater than &lt;code&gt;1&lt;/code&gt; (for example, &lt;code&gt;cubic-bezier(0.68, -0.6, 0.32, 1.6)&lt;/code&gt;), developers can simulate spring-like elastic motion. This forces the element to physically overshoot its landing coordinates before bouncing back, producing a beautiful elastic effect natively.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Drawing the Curve with Vector SVG
&lt;/h2&gt;

&lt;p&gt;To display the active Bezier curve in real-time, our engine maps the user's &lt;code&gt;0..1&lt;/code&gt; coordinates onto a responsive &lt;code&gt;150x150&lt;/code&gt; SVG drawing canvas. &lt;/p&gt;

&lt;p&gt;Using an SVG cubic path command (&lt;code&gt;C&lt;/code&gt;), we can plot the mathematical curve natively. To accommodate elastic easing coordinates where &lt;code&gt;y&lt;/code&gt; goes below &lt;code&gt;0&lt;/code&gt; or above &lt;code&gt;1&lt;/code&gt;, we map the vertical bounds onto a padded height coordinate scale:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;curveSvgPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;computed&lt;/span&gt;&lt;span class="p"&gt;(():&lt;/span&gt; &lt;span class="kr"&gt;string&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;x1&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;x1&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;150&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;y1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;150&lt;/span&gt; &lt;span class="o"&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;y1&lt;/span&gt;&lt;span class="p"&gt;()&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="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;75&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Map -1..2 range onto 0..150 height&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;x2&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;x2&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;150&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;y2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;150&lt;/span&gt; &lt;span class="o"&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;y2&lt;/span&gt;&lt;span class="p"&gt;()&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="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;75&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`M 0 112.5 C &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;x1&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;y1&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;x2&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;y2&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, 150 37.5`&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;This dynamically updates the SVG vector path on every slider event, drawing the exact motion curve alongside turquoise and pink coordinate anchor points.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. GPU-Accelerated Animation Preview: Transitioning left vs. translateX
&lt;/h2&gt;

&lt;p&gt;A major challenge during development was making sure the visual physics simulator worked accurately and responsively across different viewport sizes.&lt;/p&gt;

&lt;p&gt;Initially, we tried toggling arbitrary Tailwind CSS classes using &lt;code&gt;translateX&lt;/code&gt; percentages. However, we ran into a classic CSS transform limitation: percentage values inside &lt;code&gt;translateX&lt;/code&gt; are calculated relative to &lt;strong&gt;the width of the animated element itself&lt;/strong&gt; (32px), not the parent track container.&lt;/p&gt;

&lt;p&gt;To resolve this, we transitioned the absolute &lt;code&gt;left&lt;/code&gt; property instead. In absolute positioning, percentage values are calculated relative to &lt;strong&gt;the parent container's width&lt;/strong&gt;. This allows the animated box to travel from the far left of its track (&lt;code&gt;left: 4px&lt;/code&gt;) to the exact far right (&lt;code&gt;left: calc(100% - 36px)&lt;/code&gt;) responsively on both mobile and 4K displays.&lt;/p&gt;

&lt;p&gt;We then inject the custom compiled CSS ruleset into a safe dynamic style tag inside the DOM:&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="nc"&gt;.easing-box-animated&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;left&lt;/span&gt; &lt;span class="m"&gt;1.2s&lt;/span&gt; &lt;span class="n"&gt;cubic-bezier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0.25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.75&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.75&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;This ensures that the browser uses hardware-accelerated rendering pipelines to run the side-by-side transition preview at a smooth 60fps.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Try it out
&lt;/h2&gt;

&lt;p&gt;Mastering motion physics doesn't have to require manual coordinate guesswork. Try out the designer, test your curves against the linear reference block, and copy clean CSS transitions instantly.&lt;/p&gt;

&lt;p&gt;Try the live tool: &lt;a href="https://tools.kandz.me/css-timing-designer" rel="noopener noreferrer"&gt;tools.kandz.me/css-timing-designer&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>css</category>
      <category>animation</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Under the Hood: Building a 100% Client-Side CSV Deduplicator with Angular 18+ Signals</title>
      <dc:creator>kandz</dc:creator>
      <pubDate>Mon, 10 Aug 2026 10:35:32 +0000</pubDate>
      <link>https://dev.to/kandz/under-the-hood-building-a-100-client-side-csv-deduplicator-with-angular-18-signals-4fjo</link>
      <guid>https://dev.to/kandz/under-the-hood-building-a-100-client-side-csv-deduplicator-with-angular-18-signals-4fjo</guid>
      <description>&lt;p&gt;Tabular data cleaning is one of the most common prep steps in data engineering and business ops. However, pasting a CSV containing sensitive emails, customer IDs, or corporate financials into a third-party server poses massive security risks. &lt;/p&gt;

&lt;p&gt;To solve this, we built a 100% client-side &lt;strong&gt;CSV Row Deduplicator&lt;/strong&gt; on &lt;code&gt;tools.kandz.me&lt;/code&gt;. By processing everything in the browser sandbox, your data never touches a server. &lt;/p&gt;

&lt;p&gt;But parsing and deduplicating CSV format reliably in raw JavaScript is trickier than a simple &lt;code&gt;string.split(',')&lt;/code&gt;. Here is a deep dive into how it works under the hood.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. The Core Architecture &amp;amp; Challenges
&lt;/h2&gt;

&lt;p&gt;At first glance, splitting CSV lines seems trivial. But standard production CSVs present major parsing edge cases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Quoted Values with Commas&lt;/strong&gt;: A field like &lt;code&gt;"Doe, John"&lt;/code&gt; shouldn't be split at the comma.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Header Preservation&lt;/strong&gt;: The column names (first row) must remain at the top and never get removed as "duplicates," even if an identical row appears deep inside the dataset (e.g., if multiple CSV files were merged together).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Whitespace Variations&lt;/strong&gt;: &lt;code&gt;John Doe, john@example.com&lt;/code&gt; and &lt;code&gt;John Doe,john@example.com&lt;/code&gt; (notice the space) should be evaluated as duplicate rows if white spaces are trimmed.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  2. Breaking Down the Parser
&lt;/h2&gt;

&lt;p&gt;To handle quoted cells containing commas, we implement a stateful parser loop instead of a basic &lt;code&gt;.split(',')&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;parseCSVLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;line&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&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;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&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;let&lt;/span&gt; &lt;span class="nx"&gt;inQuotes&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="k"&gt;for &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;i&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;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;line&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="nx"&gt;i&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;char&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;line&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&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;char&lt;/span&gt; &lt;span class="o"&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="nx"&gt;inQuotes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;inQuotes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Toggle quotes state&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&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;char&lt;/span&gt; &lt;span class="o"&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="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;inQuotes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&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="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;char&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;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;current&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;result&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;h2&gt;
  
  
  3. Protecting the Header &amp;amp; Cleaning Merged Files
&lt;/h2&gt;

&lt;p&gt;A major logical bug in naive deduplicators is how they handle the &lt;strong&gt;First Row is Header&lt;/strong&gt; flag. If you shift the header row out of the array before processing, its key signature is never tracked. If an accidental duplicate of that header appears later in the body (very common when concatenating tables), it gets processed as a unique data row.&lt;/p&gt;

&lt;p&gt;To fix this, we generate the key signature of the shifted header and add it to our &lt;code&gt;seen&lt;/code&gt; tracking set &lt;em&gt;before&lt;/em&gt; processing the body:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;seen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Set&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&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;hasHeader&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;headersRow&lt;/span&gt;&lt;span class="p"&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;headerKey&lt;/span&gt; &lt;span class="o"&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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;colIdx&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;headerKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;isTrim&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;headersRow&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;colIdx&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;headersRow&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;colIdx&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cleanHeader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;isTrim&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;headersRow&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;c&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;headersRow&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;headerKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cleanHeader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&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="nx"&gt;seen&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="nx"&gt;headerKey&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensures any repeated headers inside the data rows are instantly stripped out, keeping only the true, anchored header at the top of the output.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Reactive State management with Angular Signals
&lt;/h2&gt;

&lt;p&gt;We use Angular 18+ reactive Signals and &lt;code&gt;computed&lt;/code&gt; properties to keep calculations fast and clean. When the user changes any parameter (such as toggling case-sensitivity or choosing to deduplicate by a specific column), the engine automatically recalculates the output without manual event listeners or dirty DOM rendering.&lt;/p&gt;

&lt;p&gt;By using native input bindings (&lt;code&gt;[value]="csvInput()"&lt;/code&gt; and custom target update events) we bypass standard latency, ensuring smooth performance even with large files.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Summary
&lt;/h2&gt;

&lt;p&gt;By keeping everything client-side, we combine ultimate data privacy with rapid execution. If you need to clean up messy datasets, give the tool a run.&lt;/p&gt;

&lt;p&gt;Try the live tool: &lt;a href="https://tools.kandz.me/csv-deduplicator" rel="noopener noreferrer"&gt;tools.kandz.me/csv-deduplicator&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>angular</category>
      <category>javascript</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
