<?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: Mubeen Khan</title>
    <description>The latest articles on DEV Community by Mubeen Khan (@mubeenkhaaan).</description>
    <link>https://dev.to/mubeenkhaaan</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%2F4155949%2F8dec5289-676e-45d3-b966-980f4271e1db.png</url>
      <title>DEV Community: Mubeen Khan</title>
      <link>https://dev.to/mubeenkhaaan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mubeenkhaaan"/>
    <language>en</language>
    <item>
      <title>The one-line SQL query that broke code review</title>
      <dc:creator>Mubeen Khan</dc:creator>
      <pubDate>Sun, 15 Nov 2026 10:34:51 +0000</pubDate>
      <link>https://dev.to/mubeenkhaaan/the-one-line-sql-query-that-broke-code-review-obj</link>
      <guid>https://dev.to/mubeenkhaaan/the-one-line-sql-query-that-broke-code-review-obj</guid>
      <description>&lt;p&gt;I once reviewed a pull request where the entire database migration was one line. Four hundred and twelve characters of SQL, no line breaks, no indentation, a JOIN buried somewhere in the middle like a landmine. The query was correct. It also took me twenty minutes to be sure it was correct, because I could not read it.&lt;/p&gt;

&lt;p&gt;That is the whole case for a SQL formatter. It does not make your query faster. It does not fix your logic. It makes the query readable enough that a human can spot the bug before it ships.&lt;/p&gt;

&lt;h2&gt;
  
  
  Formatting is not cosmetic
&lt;/h2&gt;

&lt;p&gt;A formatter does two honest things. First, it puts one clause per line: SELECT, FROM, WHERE, GROUP BY, ORDER BY. Second, it indents the parts that belong together, so a JOIN condition sits under its JOIN and a subquery is visibly nested inside its parent. That is it. No magic, no rewriting. The formatted query does exactly what the original did, because only whitespace and casing changed.&lt;/p&gt;

&lt;p&gt;The bug I was hunting in that PR turned out to be a missing condition in the WHERE clause. On one line, the WHERE clause looked like a wall of text and my eyes slid right past it. Formatted, the missing condition was obvious in about four seconds, because the list of conditions was vertical and one item was simply absent.&lt;/p&gt;

&lt;h2&gt;
  
  
  The dialect trap nobody warns you about
&lt;/h2&gt;

&lt;p&gt;Here is where most people pick the wrong formatter: SQL is not one language. MySQL uses backticks for identifiers. SQL Server uses square brackets. PostgreSQL uses double quotes. BigQuery has its own ideas about everything. A formatter that does not know your dialect will happily "fix" syntax that was never broken, or choke on syntax that is perfectly valid in your database.&lt;/p&gt;

&lt;p&gt;So the first question a good formatter asks is not "how many spaces" but "which database". Standard SQL, MySQL, PostgreSQL, SQLite, SQL Server, Oracle, BigQuery, Snowflake, Redshift: each one parses differently. If your formatter treats them all the same, it is guessing, and guessing with production queries is a bad habit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Minify is the opposite direction, and it has a use
&lt;/h2&gt;

&lt;p&gt;Formatting spreads a query out. Minifying crushes it into one line. That sounds like going backwards, until you need to paste a query into a URL parameter, a log line, or a config value where newlines are not welcome. Minify is a transport format, not a reading format. The rule is simple: format for humans, minify for machines, and never confuse the two.&lt;/p&gt;

&lt;p&gt;One warning about minifying: a careless minifier will strip a comment that your query actually needs, or join two tokens that were only separated by whitespace. A good one leaves string literals and comments alone. If yours does not, find another one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your queries should never leave your browser
&lt;/h2&gt;

&lt;p&gt;This matters more than people admit. The queries you format are often production queries. They contain real table names, real column names, sometimes real customer IDs baked into a WHERE clause. A formatter that uploads your SQL to a server to format it is a data leak wearing a tool costume.&lt;/p&gt;

&lt;p&gt;The safe version runs entirely in your browser. Paste, format, copy, done. Nothing is uploaded, nothing is stored, nothing is logged. If a tool cannot promise that, do not paste production SQL into it. I built a free one that works exactly this way, with dialect selection, keyword casing, indentation options and a minify mode: it formats MySQL, PostgreSQL, SQLite, SQL Server, Oracle, BigQuery and more, all in your browser. You can try it here: &lt;a href="https://www.theutilityhub.online/tools/sql-formatter" rel="noopener noreferrer"&gt;https://www.theutilityhub.online/tools/sql-formatter&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  A small habit that pays off
&lt;/h2&gt;

&lt;p&gt;Before you paste a query into a pull request, a migration file, or a chat message to a colleague, run it through a formatter. It takes three seconds. The person reading it, which is often future you, will be able to see the structure instead of decoding a wall of text. And the next time a WHERE condition goes missing, you will spot it in four seconds instead of twenty minutes.&lt;/p&gt;

</description>
      <category>sql</category>
      <category>webdev</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Base64 makes your image 33% bigger. Here is when that is still the right call</title>
      <dc:creator>Mubeen Khan</dc:creator>
      <pubDate>Sat, 14 Nov 2026 10:31:23 +0000</pubDate>
      <link>https://dev.to/mubeenkhaaan/base64-makes-your-image-33-bigger-here-is-when-that-is-still-the-right-call-8g7</link>
      <guid>https://dev.to/mubeenkhaaan/base64-makes-your-image-33-bigger-here-is-when-that-is-still-the-right-call-8g7</guid>
      <description>&lt;p&gt;Every frontend developer eventually meets the same suggestion: just inline the image as Base64. It sounds like free performance, one less HTTP request, no separate file to manage. And then someone points out the catch: Base64 encoding makes the image about 33% bigger. So is inlining ever worth it, or is it a trick that costs more than it saves?&lt;/p&gt;

&lt;p&gt;The honest answer is that it depends entirely on the size of the image and where it lives. The 33% overhead is real and unavoidable, it comes from the encoding itself, but the request you save is also real. For a tiny icon, the trade wins easily. For a hero photo, it loses badly. The skill is knowing where the line sits.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Base64 is 33% bigger
&lt;/h2&gt;

&lt;p&gt;Base64 exists to move binary data through systems that only understand text. An image file is bytes. HTML, CSS, JSON and email are text. Base64 converts every 3 bytes of image into 4 characters of plain ASCII, which is why the output is always roughly one third larger than the file you started with.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..."&lt;/span&gt; &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Logo"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That &lt;code&gt;data:image/png;base64,&lt;/code&gt; prefix is called a data URI. Everything after the comma is the image, encoded as text, embedded directly in your page. No separate file, no extra request, no server round trip. The browser decodes it and renders the image exactly as if it had downloaded a file.&lt;/p&gt;

&lt;p&gt;The encoding is the easy part. The decision is the hard part.&lt;/p&gt;

&lt;h2&gt;
  
  
  When inlining wins: small, repeated, critical images
&lt;/h2&gt;

&lt;p&gt;Inline an image as Base64 when it is small, when it appears on every page, or when it must render before anything else loads. The classic winners are logos, icons, tiny UI graphics and one-pixel tracking or spacer images.&lt;/p&gt;

&lt;p&gt;A 2KB logo becomes about 2.7KB of text. That is nothing, and in exchange you remove a render-blocking request from the critical path. Your logo appears with the first paint instead of after the browser fetches a second file. The same logic applies to the small icons in a button set or a navigation bar: ten tiny icons as ten separate files means ten requests; inlined, they ride along with the HTML you were already downloading.&lt;/p&gt;

&lt;p&gt;Email is the other place where inlining earns its keep. Many email clients block remote images by default, so a remote logo shows up as a broken box until the reader clicks "show images". An inlined logo renders immediately, because it was inside the message all along.&lt;/p&gt;

&lt;h2&gt;
  
  
  When inlining loses: anything large or cacheable
&lt;/h2&gt;

&lt;p&gt;Do not inline a photo. A 200KB product photo becomes about 267KB of text baked into your HTML, and that text downloads again on every single page load, because an inlined image cannot be cached separately from the page around it. A linked image file downloads once and then sits in the browser cache for every page after that.&lt;/p&gt;

&lt;p&gt;The same applies to images that change often. Update a linked logo and every visitor gets the new one on their next visit. Update an inlined logo and you have to change every page, email or stylesheet that contains the old string, and anyone with a cached copy of the old page keeps seeing the old logo.&lt;/p&gt;

&lt;p&gt;A practical rule of thumb: if the image is under about 10KB, inlining is usually a win. Between 10KB and 50KB, it depends on how critical the image is. Above that, link the file and let the browser cache do its job.&lt;/p&gt;

&lt;h2&gt;
  
  
  The conversion itself takes ten seconds
&lt;/h2&gt;

&lt;p&gt;Converting an image to Base64 is not a server job and it should never involve uploading your file anywhere. The browser already has everything it needs: the FileReader API reads the file and hands you the data URI, all inside your own tab.&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="n"&gt;reader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FileReader&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="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;onload&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="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="n"&gt;dataUri&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// "data:image/png;base64,..."&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'img'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dataUri&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="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readAsDataURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&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;What you get back is the full data URI, ready to paste into an &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tag, a CSS &lt;code&gt;background-image&lt;/code&gt;, or a JSON payload. If you only need the encoded text without the prefix, strip everything up to the comma. The same string also decodes in reverse: paste a data URI into a decoder and you get the image back, which is how you check what an unfamiliar Base64 blob actually contains before trusting it.&lt;/p&gt;

&lt;h2&gt;
  
  
  One trick that makes the 33% hurt less
&lt;/h2&gt;

&lt;p&gt;If the image is a JPEG or WebP, re-encoding it at a lower quality before converting can shrink the Base64 output by far more than the encoding adds. A 120KB screenshot re-encoded as JPEG at 80% quality might drop to 40KB, and its Base64 form lands around 53KB, smaller than the original file was. The encoding overhead stays 33%, but 33% of a much smaller number is a much smaller number.&lt;/p&gt;

&lt;p&gt;This is worth doing only for images where a little quality loss is invisible, photos and screenshots qualify, crisp logos and line art do not. And it only makes sense when the image was already a candidate for inlining: small, repeated, or critical. Re-encoding a hero photo to make it inlineable is solving the wrong problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  The decision, in one paragraph
&lt;/h2&gt;

&lt;p&gt;Inline images under about 10KB, especially logos and icons that appear everywhere or must render instantly. Link everything larger, everything that changes, and everything the browser should cache. Convert locally, never upload an image to a random site to get its Base64 string, because the file you upload is your file. And when you do inline, re-encode JPEGs and WebPs first, so the 33% overhead applies to the smallest file you can honestly produce.&lt;/p&gt;

&lt;p&gt;I built a free image to Base64 converter that does the whole job in your browser: drop an image in, get the raw Base64, the full data URI, and ready-to-paste HTML, CSS and Markdown snippets, with an optional re-encode step to shrink the output first. It also decodes in reverse, so you can paste any data URI back in and preview the image it holds. No upload, no signup, and you can try it here: &lt;a href="https://www.theutilityhub.online/tools/image-to-base64-converter" rel="noopener noreferrer"&gt;Image to Base64 Converter&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The 33% is not a reason to avoid Base64. It is the price of the trick, and for small images, it is a price worth paying.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>html</category>
      <category>css</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>JSON and XML do not describe data the same way, and every converter has to pick a side</title>
      <dc:creator>Mubeen Khan</dc:creator>
      <pubDate>Fri, 13 Nov 2026 10:33:40 +0000</pubDate>
      <link>https://dev.to/mubeenkhaaan/json-and-xml-do-not-describe-data-the-same-way-and-every-converter-has-to-pick-a-side-50pm</link>
      <guid>https://dev.to/mubeenkhaaan/json-and-xml-do-not-describe-data-the-same-way-and-every-converter-has-to-pick-a-side-50pm</guid>
      <description>&lt;p&gt;Every API speaks JSON now. Every legacy system still speaks XML. Sooner or later you have to move data from one to the other, and that is when you discover the two formats do not describe data the same way at all.&lt;/p&gt;

&lt;p&gt;JSON has six kinds of value: objects, arrays, strings, numbers, booleans and null. XML has elements, attributes and text. There is no one-to-one mapping between them, so every converter has to make four decisions for you, and most of them make those decisions silently.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decision 1: what is the root?
&lt;/h2&gt;

&lt;p&gt;XML demands exactly one root element. JSON does not. Your JSON might be an object, an array, or even a single string, and the converter has to wrap it in something.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"Ana"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;"city"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"Karachi"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;root&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;name&amp;gt;&lt;/span&gt;Ana&lt;span class="nt"&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;city&amp;gt;&lt;/span&gt;Karachi&lt;span class="nt"&gt;&amp;lt;/city&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/root&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That &lt;code&gt;&amp;lt;root&amp;gt;&lt;/code&gt; is a choice, not a fact. Some converters name it after your file. Some let you pick the name. If the system receiving your XML expects &lt;code&gt;&amp;lt;order&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;lt;catalog&amp;gt;&lt;/code&gt;, a converter that hardcodes &lt;code&gt;&amp;lt;root&amp;gt;&lt;/code&gt; hands you a file you have to edit by hand. Pick one that lets you name the root before you convert, not after.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decision 2: what happens to arrays?
&lt;/h2&gt;

&lt;p&gt;XML has no array type. JSON does. So when the converter meets this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;"tags"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"new"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"sale"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"featured"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;it has to choose. The honest choice is to repeat the element:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;tags&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;item&amp;gt;&lt;/span&gt;new&lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;item&amp;gt;&lt;/span&gt;sale&lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;item&amp;gt;&lt;/span&gt;featured&lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/tags&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The lazy choice is to join the values into one string, &lt;code&gt;new,sale,featured&lt;/code&gt;, which destroys the structure and makes the data unparseable on the other side. If you are converting a list of products, orders or line items, repeated elements are the only representation that survives a round trip. Check what your converter does with an array before you trust it with a real payload.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decision 3: attributes or elements?
&lt;/h2&gt;

&lt;p&gt;XML has attributes. JSON does not. So a converter has to decide whether &lt;code&gt;{"id": 42}&lt;/code&gt; becomes &lt;code&gt;&amp;lt;product&amp;gt;&amp;lt;id&amp;gt;42&amp;lt;/id&amp;gt;&amp;lt;/product&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;lt;product id="42"&amp;gt;&amp;lt;/product&amp;gt;&lt;/code&gt;. Both are valid XML. They mean different things to the system reading them.&lt;/p&gt;

&lt;p&gt;The convention most tools use is a prefix: keys starting with &lt;code&gt;@&lt;/code&gt; become attributes, and a special &lt;code&gt;#text&lt;/code&gt; key holds the text content of an element. It is not a standard, it is a handshake, but it is the handshake almost every converter understands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;"product"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;"@id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"42"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;"@currency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"USD"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;"#text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"Running shoes"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;product&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"42"&lt;/span&gt; &lt;span class="na"&gt;currency&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"USD"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Running shoes&lt;span class="nt"&gt;&amp;lt;/product&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your converter does not support that convention, you cannot express attributes at all, and every piece of metadata becomes a child element whether the receiving system wants it there or not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decision 4: what about null?
&lt;/h2&gt;

&lt;p&gt;JSON has null. XML has no equivalent. A converter meeting &lt;code&gt;"discount": null&lt;/code&gt; has three options: emit an empty element &lt;code&gt;&amp;lt;discount/&amp;gt;&lt;/code&gt;, skip the key entirely, or mark it explicitly with &lt;code&gt;xsi:nil="true"&lt;/code&gt;. Each one means something different. An empty element can mean "present but blank". Omitting the key can mean "not applicable". Only &lt;code&gt;xsi:nil&lt;/code&gt; says, unambiguously, "this value is null". For a SOAP service or a config file, the wrong choice here is a silent bug: the field looks converted, but the receiving system reads it as something else entirely.&lt;/p&gt;

&lt;h2&gt;
  
  
  The keys that are not legal XML
&lt;/h2&gt;

&lt;p&gt;There is one more trap, and it is the one that breaks conversions most often. JSON keys can be almost anything. XML element names cannot start with a digit, cannot contain spaces, and cannot contain most punctuation. A key like &lt;code&gt;"2fa_enabled"&lt;/code&gt; or &lt;code&gt;"first name"&lt;/code&gt; is perfectly good JSON and invalid XML.&lt;/p&gt;

&lt;p&gt;A good converter repairs those names and tells you it did so, turning &lt;code&gt;2fa_enabled&lt;/code&gt; into something like &lt;code&gt;_2fa_enabled&lt;/code&gt; and flagging the change. A bad converter either crashes on the first bad key or emits XML that no parser will accept, and you only find out when the other system rejects the whole file.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this still matters in 2026
&lt;/h2&gt;

&lt;p&gt;Nobody writes new systems in XML. But RSS feeds, sitemaps, SOAP APIs, banking integrations, government portals, old ERPs and configuration files all still run on it. The JSON-to-XML bridge is not a legacy curiosity, it is a weekly task for developers who integrate with anything older than five years.&lt;/p&gt;

&lt;p&gt;The conversion itself is simple once you know the four decisions: name your root, repeat elements for arrays, use the &lt;code&gt;@&lt;/code&gt; prefix for attributes, and decide what null means before you convert. Get those four right and the output is XML any parser will accept.&lt;/p&gt;

&lt;p&gt;I built a free JSON to XML converter that makes all four choices visible instead of hiding them: you name the root and array items, toggle the XML declaration and indentation, pick how nulls are handled, and it flags every key it had to repair. It runs entirely in your browser, so nothing you paste is uploaded, and you can try it here: &lt;a href="https://www.theutilityhub.online/tools/json-to-xml-converter" rel="noopener noreferrer"&gt;JSON to XML Converter&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The conversion is not the hard part. Knowing what the converter decided for you is.&lt;/p&gt;

</description>
      <category>json</category>
      <category>xml</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Stop stripping HTML with regex: the browser already knows the plain text</title>
      <dc:creator>Mubeen Khan</dc:creator>
      <pubDate>Thu, 12 Nov 2026 10:30:41 +0000</pubDate>
      <link>https://dev.to/mubeenkhaaan/stop-stripping-html-with-regex-the-browser-already-knows-the-plain-text-5fj5</link>
      <guid>https://dev.to/mubeenkhaaan/stop-stripping-html-with-regex-the-browser-already-knows-the-plain-text-5fj5</guid>
      <description>&lt;p&gt;Every developer has written this line at some point:&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="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;html&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="o"&gt;/&amp;lt;&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="o"&gt;*&amp;gt;/&lt;/span&gt;&lt;span class="n"&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="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It looks reasonable. It passes the first test. Then it meets real HTML and falls apart in five different ways at once.&lt;/p&gt;

&lt;p&gt;The problem is not your regex. The problem is that HTML is not a regular language, and no pattern can understand it the way a parser can.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the regex breaks
&lt;/h2&gt;

&lt;p&gt;Take a simple email template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Hi Ana,&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Your order &lt;span class="nt"&gt;&amp;lt;strong&amp;gt;&lt;/span&gt;#4821&lt;span class="nt"&gt;&amp;lt;/strong&amp;gt;&lt;/span&gt; ships on &lt;span class="nt"&gt;&amp;lt;time&amp;gt;&lt;/span&gt;Friday&lt;span class="nt"&gt;&amp;lt;/time&amp;gt;&lt;/span&gt;.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;Tracking link inside your account&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;Free returns for 30 days&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Strip the tags with a regex and you get:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Hi Ana,Your order #4821 ships on Friday.Tracking link inside your accountFree returns for 30 days
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every paragraph boundary is gone. The list items run together. The text is technically tag-free and completely unreadable. A regex sees characters, not structure. It cannot know that &lt;code&gt;&amp;lt;/p&amp;gt;&lt;/code&gt; means "new paragraph" or that &lt;code&gt;&amp;lt;li&amp;gt;&lt;/code&gt; means "new line with a bullet".&lt;/p&gt;

&lt;p&gt;Then there are the cases where it silently corrupts content. A &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; block full of comparison operators becomes text. A &lt;code&gt;&amp;gt;&lt;/code&gt; inside an attribute value (&lt;code&gt;&amp;lt;a title="a &amp;gt; b"&amp;gt;&lt;/code&gt;) ends the "tag" early and leaves markup in your output. An HTML entity like &lt;code&gt;&amp;amp;amp;&lt;/code&gt; stays as the literal characters &lt;code&gt;&amp;amp;amp;&lt;/code&gt; instead of becoming &lt;code&gt;&amp;amp;&lt;/code&gt;. And &lt;code&gt;&amp;amp;nbsp;&lt;/code&gt; becomes a non-breaking space that looks identical to a normal space but breaks every search, split and comparison you run on the result afterwards.&lt;/p&gt;

&lt;h2&gt;
  
  
  The browser already solved this
&lt;/h2&gt;

&lt;p&gt;Here is the thing most people miss: you do not need a library to extract text from HTML correctly. The browser ships with a real HTML parser, and it is one function call away.&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="n"&gt;doc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;DOMParser&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="nf"&gt;parseFromString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"text/html"&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="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;innerText&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;DOMParser&lt;/code&gt; builds a real document from your markup. It is inert: scripts never run, images and stylesheets never load, nothing is fetched. Then &lt;code&gt;innerText&lt;/code&gt; walks that document the way a browser renders it: block elements get line breaks, paragraphs get blank lines between them, &lt;code&gt;&amp;lt;br&amp;gt;&lt;/code&gt; becomes a newline, list items get their markers, table cells get separated. The parser handles the entities, the malformed nesting, the unclosed tags. All the edge cases your regex was about to meet have already been handled, by the same engine that renders every web page you have ever opened.&lt;/p&gt;

&lt;p&gt;There are two details worth knowing. First, &lt;code&gt;innerText&lt;/code&gt; is aware of what is visible, so content inside &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt; is excluded, while &lt;code&gt;textContent&lt;/code&gt; would include it. If you want the readable text of a page, &lt;code&gt;innerText&lt;/code&gt; is the one you want. Second, this runs entirely in the browser. Nothing is uploaded, which matters when the HTML you are cleaning is a client email template or a page full of internal links.&lt;/p&gt;

&lt;h2&gt;
  
  
  The options that make the output actually usable
&lt;/h2&gt;

&lt;p&gt;A raw text dump is only half the job. Three small choices turn it into text you can paste somewhere and trust:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Keep the link destinations.&lt;/strong&gt; A link that reads "read the docs" is useless in plain text unless the URL survives. Writing it as &lt;code&gt;read the docs (https://example.com/docs)&lt;/code&gt; keeps the destination attached to the words.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Keep image alt text.&lt;/strong&gt; In plain text, an image is invisible, but its alt text is often the only description of what was there. Writing it as &lt;code&gt;[Product photo: blue running shoes]&lt;/code&gt; preserves the information instead of silently dropping it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Keep the list structure.&lt;/strong&gt; Bullets and numbers are not decoration. They tell the reader where one item ends and the next begins, and without them a five-item list becomes one long sentence.&lt;/p&gt;

&lt;p&gt;Tables deserve the same treatment. A row of cells joined with tabs keeps the columns readable, while cells joined with nothing turn "Price 49.99" into "Price49.99".&lt;/p&gt;

&lt;h2&gt;
  
  
  When you actually need this
&lt;/h2&gt;

&lt;p&gt;This comes up more often than people expect. Cleaning up HTML email templates before pasting them into a plain-text field. Pulling the readable text out of a saved web page for a search index. Turning a Word export full of markup into something you can paste into a form. Preparing page content for an LLM prompt, where every stray tag is wasted tokens. Checking what a screen reader or a search engine actually sees when the styling is gone.&lt;/p&gt;

&lt;p&gt;In every one of those cases, the goal is the same: the words, in the right order, with the structure a human reader needs and nothing else.&lt;/p&gt;

&lt;p&gt;I built a free HTML to text converter that does exactly this, using the browser parser approach above. It keeps paragraphs, lists and tables readable, decodes entities properly, strips scripts and styles, and lets you choose whether link URLs and image alt text survive. It also takes a file upload and gives you a clean .txt download. It runs entirely in your browser, and you can try it here: &lt;a href="https://www.theutilityhub.online/tools/html-to-text-converter" rel="noopener noreferrer"&gt;HTML to Text Converter&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Your HTML is not text with angle brackets sprinkled on it. It is a document. Let a parser read it.&lt;/p&gt;

</description>
      <category>html</category>
      <category>webdev</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>The minifier that ate your spaces: why HTML minifying is harder than it looks</title>
      <dc:creator>Mubeen Khan</dc:creator>
      <pubDate>Wed, 11 Nov 2026 10:45:38 +0000</pubDate>
      <link>https://dev.to/mubeenkhaaan/the-minifier-that-ate-your-spaces-why-html-minifying-is-harder-than-it-looks-3g3e</link>
      <guid>https://dev.to/mubeenkhaaan/the-minifier-that-ate-your-spaces-why-html-minifying-is-harder-than-it-looks-3g3e</guid>
      <description>&lt;p&gt;Minifying CSS is easy. Minifying JavaScript is a solved problem. Minifying HTML looks easy too, until the day your minifier eats a space that mattered and two words glue themselves together on the live page.&lt;/p&gt;

&lt;p&gt;Here is the trap. In HTML, whitespace is not decoration. It is content.&lt;/p&gt;

&lt;h2&gt;
  
  
  The space between two words is load-bearing
&lt;/h2&gt;

&lt;p&gt;Take this markup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Click &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/pricing"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;here&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt; to see the price.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is a space after "Click" and a space before "to". A careless minifier sees whitespace between tags and deletes it, because most whitespace in HTML is meaningless. But these two spaces are the only thing keeping "Click", "here" and "to see the price" as separate words. Strip them and your page reads "Clickhere to see the price." or worse, "Clickhereto see the price."&lt;/p&gt;

&lt;p&gt;The same rule applies everywhere inline elements touch text: &lt;code&gt;&amp;lt;strong&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;em&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;code&amp;gt;&lt;/code&gt;. A minifier that treats HTML like a flat string will break your sentences. A correct minifier has to understand the document: it must know which elements are inline, which are block-level, and where a space is a word separator rather than formatting.&lt;/p&gt;

&lt;h2&gt;
  
  
  The elements a minifier must never touch
&lt;/h2&gt;

&lt;p&gt;Whitespace is not the only landmine. Three elements carry content where every single character matters:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;pre&amp;gt;&lt;/code&gt;&lt;/strong&gt; — the whole point of a preformatted block is that spaces and line breaks are preserved. Minify inside one and your code sample collapses into a single unreadable line.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;textarea&amp;gt;&lt;/code&gt;&lt;/strong&gt; — the default text inside a textarea is user-visible content. Strip its leading newline and the first line of your form shifts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt;&lt;/strong&gt; — these contain other languages. A space inside a JavaScript string literal is data, not formatting. An HTML minifier that rewrites script contents is a bug waiting to happen. The right move is to leave these blocks byte-for-byte alone and let a dedicated JS or CSS minifier handle them.&lt;/p&gt;

&lt;p&gt;Conditional comments (&lt;code&gt;&amp;lt;!--[if IE]&amp;gt;...&amp;lt;![endif]--&amp;gt;&lt;/code&gt;) are another one. They look like comments, but old versions of Internet Explorer treat them as instructions. Delete them and you change behavior for the exact users they were written for.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a good HTML minifier actually removes
&lt;/h2&gt;

&lt;p&gt;Once the protected zones are fenced off, the safe savings are real:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Comments&lt;/strong&gt; that carry no instructions (regular &lt;code&gt;&amp;lt;!-- --&amp;gt;&lt;/code&gt; comments).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Whitespace between block-level elements&lt;/strong&gt;, where it never renders. The newline between &lt;code&gt;&amp;lt;/div&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; is invisible to every browser.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optional end tags.&lt;/strong&gt; HTML allows you to drop &lt;code&gt;&amp;lt;/p&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;/li&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;/td&amp;gt;&lt;/code&gt; and a few others, because the parser infers them. Removing them is valid, but only when the next tag makes the boundary unambiguous.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Quotes around attribute values&lt;/strong&gt;, but only when the value contains no spaces or special characters. &lt;code&gt;class=button&lt;/code&gt; is fine. &lt;code&gt;class=big button&lt;/code&gt; is not, and must keep its quotes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Boolean attributes.&lt;/strong&gt; &lt;code&gt;disabled="disabled"&lt;/code&gt; can become just &lt;code&gt;disabled&lt;/code&gt;. Same meaning, fewer bytes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On a typical hand-written page these add up to 20 to 40 percent smaller HTML. On a page generated by a framework with generous indentation, it can be more.&lt;/p&gt;

&lt;h2&gt;
  
  
  The test every minifier should pass
&lt;/h2&gt;

&lt;p&gt;Before trusting any HTML minifier with your production markup, run one check: minify a page, then beautify it again, then minify it a second time. The two minified outputs should be identical. If they are not, the tool is making decisions that depend on formatting rather than structure, and it will eventually make a wrong one.&lt;/p&gt;

&lt;p&gt;The other check is simpler: paste in a paragraph with a link in the middle of a sentence, minify it, and read the sentence back. If the words are still separate, the tool understands HTML. If they glued together, it is a string replacer wearing a minifier costume.&lt;/p&gt;

&lt;p&gt;I built a free HTML minifier that passes both checks. It uses a tag-aware scanner, so inline word spaces survive, &lt;code&gt;pre&lt;/code&gt;, &lt;code&gt;textarea&lt;/code&gt;, &lt;code&gt;script&lt;/code&gt; and &lt;code&gt;style&lt;/code&gt; contents are preserved verbatim, conditional comments and the doctype stay put, and you get five toggles for exactly how aggressive it should be. It also beautifies, so you can round-trip your markup and confirm the output is stable. It runs entirely in your browser, and you can try it here: &lt;a href="https://www.theutilityhub.online/tools/html-minifier" rel="noopener noreferrer"&gt;HTML Minifier&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Your HTML is probably 30 percent whitespace. The trick is removing the 30 percent that does nothing while keeping the spaces that are actually words.&lt;/p&gt;

</description>
      <category>html</category>
      <category>webdev</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Your minifier did not break your code. The missing semicolon did.</title>
      <dc:creator>Mubeen Khan</dc:creator>
      <pubDate>Tue, 10 Nov 2026 10:34:41 +0000</pubDate>
      <link>https://dev.to/mubeenkhaaan/your-minifier-did-not-break-your-code-the-missing-semicolon-did-1bdi</link>
      <guid>https://dev.to/mubeenkhaaan/your-minifier-did-not-break-your-code-the-missing-semicolon-did-1bdi</guid>
      <description>&lt;p&gt;Minification gets blamed for a lot of bugs it never caused. A script works fine in development, you run it through a minifier, and suddenly it throws in production. The minifier must have mangled something, right?&lt;/p&gt;

&lt;p&gt;Most of the time, no. The minifier just removed the whitespace that was secretly holding your code together. The real culprit is automatic semicolon insertion, and it was already in your code, waiting.&lt;/p&gt;

&lt;h2&gt;
  
  
  The newline that was doing real work
&lt;/h2&gt;

&lt;p&gt;JavaScript inserts semicolons for you when it thinks a statement has ended. That is convenient right up until a newline is the only thing separating two statements that should not be joined.&lt;/p&gt;

&lt;p&gt;Take this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;tax&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="nf"&gt;applyDiscount&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="nf"&gt;checkout&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;With the newline in place, JavaScript reads two statements. Now minify it by joining the lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;tax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="nf"&gt;applyDiscount&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="nf"&gt;checkout&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;That is one statement now, and it calls &lt;code&gt;tax&lt;/code&gt; as a function. &lt;code&gt;tax&lt;/code&gt; is a number, so you get &lt;code&gt;tax is not a function&lt;/code&gt; in production, on a line that looks nothing like your source.&lt;/p&gt;

&lt;p&gt;A good minifier knows this and keeps a newline or a semicolon where ASI matters. A naive whitespace stripper does not, and this is the exact bug that makes people say "minifiers are unsafe."&lt;/p&gt;

&lt;h2&gt;
  
  
  What a minifier actually removes
&lt;/h2&gt;

&lt;p&gt;A real minifier does three jobs, in order of how much they save:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Comments and whitespace.&lt;/strong&gt; The biggest, safest win. Nothing about how the code runs changes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shortening names.&lt;/strong&gt; Local variables like &lt;code&gt;shoppingCartTotal&lt;/code&gt; become &lt;code&gt;t&lt;/code&gt;. Top-level names are usually left alone, because another script might use them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rewriting expressions.&lt;/strong&gt; &lt;code&gt;if (false) { ... }&lt;/code&gt; disappears. &lt;code&gt;true&lt;/code&gt; becomes &lt;code&gt;!0&lt;/code&gt;. &lt;code&gt;const x = 1 + 2&lt;/code&gt; becomes &lt;code&gt;const x = 3&lt;/code&gt;. This is the part that needs a real parser, because it has to prove the rewrite is safe before doing it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That third job is why a parser-based minifier (Terser is the one behind webpack and Vite) beats a text-based one. A text tool can only guess where a string ends and a comment begins. A parser knows.&lt;/p&gt;

&lt;h2&gt;
  
  
  What minification is not
&lt;/h2&gt;

&lt;p&gt;Minification is not obfuscation, and it is not security. Anyone can run your minified file through a formatter and get readable code back in seconds. If the code contains a secret, minifying it does not hide the secret. It only makes the file smaller.&lt;/p&gt;

&lt;p&gt;It is also not a substitute for a bundler. If your project has a build step, let the bundler minify. An online minifier is for the one-off jobs: a tag manager snippet, a CMS embed, a bookmarklet, a quick check of how small a script can get.&lt;/p&gt;

&lt;h2&gt;
  
  
  The habit that prevents the whole class of bugs
&lt;/h2&gt;

&lt;p&gt;Write semicolons, or use a formatter that inserts them. That is the entire fix. If every statement ends with an explicit semicolon, no minifier can ever join two statements by accident, because there is nothing ambiguous left to join.&lt;/p&gt;

&lt;p&gt;And before you ship a minified one-off script, paste it back into your browser console and run it once. Thirty seconds of checking beats a production error every time.&lt;/p&gt;

&lt;p&gt;If you want to try it on your own code, this free JavaScript minifier runs entirely in your browser: &lt;a href="https://www.theutilityhub.online/tools/javascript-minifier" rel="noopener noreferrer"&gt;JavaScript Minifier&lt;/a&gt;. Paste a script, toggle mangling and compression, and watch the byte count drop. Your code never leaves your device, and if it has a syntax error you get the parser's own message instead of broken output.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Your CSS is 30% whitespace. Here is what a minifier actually removes</title>
      <dc:creator>Mubeen Khan</dc:creator>
      <pubDate>Mon, 09 Nov 2026 10:51:18 +0000</pubDate>
      <link>https://dev.to/mubeenkhaaan/your-css-is-30-whitespace-here-is-what-a-minifier-actually-removes-397g</link>
      <guid>https://dev.to/mubeenkhaaan/your-css-is-30-whitespace-here-is-what-a-minifier-actually-removes-397g</guid>
      <description>&lt;p&gt;Your stylesheet is bigger than it needs to be. Not because of your selectors or your design, but because of the parts a browser never reads: the comments, the indentation, the line breaks, the last semicolon in every rule, the &lt;code&gt;px&lt;/code&gt; after every &lt;code&gt;0&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A CSS minifier strips exactly those things. Nothing else. The page renders identically, but the file is smaller, downloads sooner, and blocks rendering for less time. CSS is render-blocking, so a smaller stylesheet is one of the cheapest performance wins on the web.&lt;/p&gt;

&lt;h2&gt;
  
  
  What gets removed
&lt;/h2&gt;

&lt;p&gt;Take a typical hand-written rule:&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;/* Main layout for the blog cards */&lt;/span&gt;
&lt;span class="nc"&gt;.card&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;flex-direction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;column&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&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="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;24px&lt;/span&gt; &lt;span class="m"&gt;16px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0px&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;#ffffff&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;Minified, it becomes:&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;.card&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nb"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="nl"&gt;flex-direction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nb"&gt;column&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="nl"&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="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;24px&lt;/span&gt; &lt;span class="m"&gt;16px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;#fff&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Six things happened there. The comment is gone. The whitespace collapsed. The last semicolon dropped. &lt;code&gt;#ffffff&lt;/code&gt; became &lt;code&gt;#fff&lt;/code&gt;. &lt;code&gt;0px&lt;/code&gt; became &lt;code&gt;0&lt;/code&gt;. And the whole thing is one line. Most stylesheets shrink 15 to 40 percent this way, depending on how many comments and how much formatting the original has.&lt;/p&gt;

&lt;h2&gt;
  
  
  The one thing a minifier must never touch: calc()
&lt;/h2&gt;

&lt;p&gt;There is a trap in naive minification, and it is &lt;code&gt;calc()&lt;/code&gt;. This is valid CSS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.card&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;100%&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="m"&gt;32px&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;Remove the spaces around the minus and you get &lt;code&gt;calc(100%-32px)&lt;/code&gt;, which is invalid CSS. The browser throws the whole declaration away, and your layout silently breaks. A real minifier has to understand CSS, not just delete spaces: it keeps the spaces inside &lt;code&gt;calc()&lt;/code&gt;, leaves quoted strings alone, and never mangles a &lt;code&gt;url()&lt;/code&gt; value.&lt;/p&gt;

&lt;p&gt;The same rule applies to &lt;code&gt;content&lt;/code&gt; strings. If your stylesheet says &lt;code&gt;content: "a  b"&lt;/code&gt;, those two spaces are part of the text on the page. A blind find-and-replace would eat them. A scanner that knows what a string is will not.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to minify, and when to use a build tool
&lt;/h2&gt;

&lt;p&gt;For a full project, a build tool like cssnano or Lightning CSS will save more: it understands source maps, merges duplicate rules, and folds into your pipeline. Use it there.&lt;/p&gt;

&lt;p&gt;But most of the time you are not minifying a project. You are pasting one stylesheet from a theme, a snippet from a tutorial, or a chunk copied out of DevTools, and you want it smaller right now. That is the job for a paste-and-go minifier: no install, no config, no upload. Paste it in, copy the smaller version out, done.&lt;/p&gt;

&lt;p&gt;I built one that does exactly this, with the calc() and string handling above, plus a beautify mode that turns a minified file back into indented, readable CSS when you inherit one and need to read it: &lt;a href="https://www.theutilityhub.online/tools/css-minifier" rel="noopener noreferrer"&gt;CSS Minifier&lt;/a&gt;. It runs entirely in your browser, so your stylesheet never leaves your device, which matters when the CSS belongs to a client project.&lt;/p&gt;

&lt;h2&gt;
  
  
  The honest footnote
&lt;/h2&gt;

&lt;p&gt;Minifying is the raw saving. Once your server applies gzip or Brotli, the transfer size shrinks again, so the percentage a minifier shows you is the before-compression number. The real win is smaller on the wire than on disk, but it is still real, and it costs you nothing: the file is smaller at every step from here on.&lt;/p&gt;

&lt;p&gt;So before your next deploy, run your stylesheet through a minifier once. If it comes back 30 percent smaller, that was 30 percent of your CSS doing nothing but taking up space.&lt;/p&gt;

</description>
      <category>css</category>
      <category>webdev</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Your Kubernetes manifest is YAML. Your API wants JSON. Here is the conversion, done right</title>
      <dc:creator>Mubeen Khan</dc:creator>
      <pubDate>Sun, 08 Nov 2026 10:32:38 +0000</pubDate>
      <link>https://dev.to/mubeenkhaaan/your-kubernetes-manifest-is-yaml-your-api-wants-json-here-is-the-conversion-done-right-gc3</link>
      <guid>https://dev.to/mubeenkhaaan/your-kubernetes-manifest-is-yaml-your-api-wants-json-here-is-the-conversion-done-right-gc3</guid>
      <description>&lt;h1&gt;
  
  
  Your Kubernetes manifest is YAML. Your API wants JSON. Here is the conversion, done right
&lt;/h1&gt;

&lt;p&gt;Every developer who has touched Kubernetes, Docker Compose, or a GitHub Actions workflow has hit the same small wall. The config lives in YAML. The tool that needs to consume it, validate it, or pipe it through &lt;code&gt;jq&lt;/code&gt; only speaks JSON. So you convert it. And the conversion is where quiet bugs are born.&lt;/p&gt;

&lt;h2&gt;
  
  
  YAML is not JSON with nicer formatting
&lt;/h2&gt;

&lt;p&gt;It looks like it. Both describe nested maps and lists. But YAML has opinions JSON does not. A bare &lt;code&gt;yes&lt;/code&gt; is a boolean in YAML 1.1 and a string in YAML 1.2. &lt;code&gt;on&lt;/code&gt; and &lt;code&gt;off&lt;/code&gt; have the same split personality. A timestamp like &lt;code&gt;2026-11-08&lt;/code&gt; can silently become a date object in one parser and stay a string in another. Anchors (&lt;code&gt;&amp;amp;defaults&lt;/code&gt;) and aliases (&lt;code&gt;*defaults&lt;/code&gt;) let one block appear in five places, and merge keys (&lt;code&gt;&amp;lt;&amp;lt;&lt;/code&gt;) fold shared config into a service definition. None of that exists in JSON, so a converter has to decide what each of those becomes, and a careless one decides wrong without telling you.&lt;/p&gt;

&lt;p&gt;The classic failure looks like this. A Docker Compose file defines a shared logging block once with an anchor, then reuses it in three services. Someone pastes it into a converter that drops anchors instead of expanding them. The JSON comes out clean, valid, and wrong: three services with no logging config at all. Nothing errors. The deploy goes out, and the missing logs are discovered at 2am, during an incident, when logs are the one thing you need.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a good conversion actually does
&lt;/h2&gt;

&lt;p&gt;First, it expands anchors and merge keys into full copies, so every place that referenced a block gets the complete block. Second, it tells you which YAML version its typing follows, because &lt;code&gt;enabled: yes&lt;/code&gt; becoming &lt;code&gt;true&lt;/code&gt; or &lt;code&gt;"yes"&lt;/code&gt; changes what your application does. Third, it handles multi-document files. A Kubernetes manifest is often three documents separated by &lt;code&gt;---&lt;/code&gt; in one file, and the honest JSON for that is an array with one entry per document, not a silent merge that drops two of them. Fourth, it reports errors with a line and column, because "invalid YAML" without a location is not an error message, it is a shrug.&lt;/p&gt;

&lt;p&gt;The reverse direction matters just as much. JSON to YAML should produce readable block style, not a wall of flow syntax, because the YAML you get back is usually going into a file a human will edit next.&lt;/p&gt;

&lt;h2&gt;
  
  
  The privacy part nobody thinks about until it is too late
&lt;/h2&gt;

&lt;p&gt;YAML files are where secrets hide in plain sight. A Compose file holds registry credentials. A Helm values file holds tuned internal hostnames. A GitHub Actions workflow embeds environment names and deployment logic. Pasting any of that into a server-side converter sends your infrastructure's address book to a stranger's server. A converter that runs entirely in your browser never uploads anything, and that is not a marketing line, it is the only safe way to handle config files.&lt;/p&gt;

&lt;p&gt;I built a free converter that does all of this in the browser: YAML to JSON and back, multi-document files become a JSON array, anchors expand properly, errors come with exact line numbers, and nothing ever leaves your device. It is at &lt;a href="https://www.theutilityhub.online/tools/yaml-to-json-converter" rel="noopener noreferrer"&gt;YAML to JSON Converter&lt;/a&gt;. Try it with a real Compose file, then check the JSON against what you expected, especially any anchors. If the output surprises you, the surprise was in your YAML all along, and now you know before production tells you.&lt;/p&gt;

</description>
      <category>yaml</category>
      <category>webdev</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Your API returned one giant line of XML. Here is how to read it</title>
      <dc:creator>Mubeen Khan</dc:creator>
      <pubDate>Sat, 07 Nov 2026 10:30:45 +0000</pubDate>
      <link>https://dev.to/mubeenkhaaan/your-api-returned-one-giant-line-of-xml-here-is-how-to-read-it-1l5c</link>
      <guid>https://dev.to/mubeenkhaaan/your-api-returned-one-giant-line-of-xml-here-is-how-to-read-it-1l5c</guid>
      <description>&lt;p&gt;You call an endpoint, you get a response, and it is one enormous line of XML. No line breaks. No indentation. Just a wall of angle brackets that your eyes slide straight off.&lt;/p&gt;

&lt;p&gt;You could paste it into your editor and hope the formatter plugin is installed. You could squint at it in the terminal. Or you could format it in about two seconds, in the browser, without uploading it anywhere.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why XML arrives as one line
&lt;/h2&gt;

&lt;p&gt;Minified XML is not broken. APIs and export tools strip whitespace on purpose, because whitespace costs bytes and machines do not care about readability. The document is perfectly valid. It is just unreadable to a human.&lt;/p&gt;

&lt;p&gt;The fix is mechanical: re-indent every element by its nesting depth. An opening tag pushes the next line one level deeper. A closing tag pulls it back. Text content stays on its own line. That is the whole trick, and any tool that does it well is worth keeping bookmarked.&lt;/p&gt;

&lt;h2&gt;
  
  
  Format it in the browser, privately
&lt;/h2&gt;

&lt;p&gt;The fastest route is a formatter that runs entirely in your browser. Paste the blob, pick an indent (two spaces is the usual default, four if your team prefers it), and you get a readable document back. No upload means the XML never leaves your machine, which matters when the payload contains internal endpoints, customer records, or production config.&lt;/p&gt;

&lt;p&gt;I built one for exactly this job: a free XML formatter and validator that pretty-prints, minifies, validates, and converts XML to JSON, all client-side. It flags malformed XML with the exact line and column of the problem instead of a vague "parse error", and it refuses DOCTYPE declarations and external entities, so pasting untrusted XML cannot trigger an XXE-style surprise. Try it here: &lt;a href="https://www.theutilityhub.online/tools/xml-formatter" rel="noopener noreferrer"&gt;https://www.theutilityhub.online/tools/xml-formatter&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The errors you will actually see
&lt;/h2&gt;

&lt;p&gt;Most malformed XML is one of three mistakes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Mismatched tags.&lt;/strong&gt; &lt;code&gt;&amp;lt;user&amp;gt;&amp;lt;name&amp;gt;Alex&amp;lt;/user&amp;gt;&amp;lt;/name&amp;gt;&lt;/code&gt; closes the tags in the wrong order. XML is strict about nesting, unlike HTML, which forgives it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unclosed tags.&lt;/strong&gt; One &lt;code&gt;&amp;lt;item&amp;gt;&lt;/code&gt; never gets its &lt;code&gt;&amp;lt;/item&amp;gt;&lt;/code&gt;, usually after a copy-paste.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A second root element.&lt;/strong&gt; XML allows exactly one root. Two top-level elements is not a document, it is two documents glued together.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A good validator points at the line and column. A bad one just says "invalid". When you are debugging a 200KB response, that difference is the whole job.&lt;/p&gt;

&lt;h2&gt;
  
  
  Minify, and XML to JSON
&lt;/h2&gt;

&lt;p&gt;Formatting is only half the tool. Minify does the reverse: it strips the whitespace back out when you need the smallest possible payload to paste into a test or a config field. And XML to JSON conversion is handy when the rest of your pipeline speaks JSON and you want the data, not the markup.&lt;/p&gt;

&lt;p&gt;One habit makes all of this painless: never debug raw XML. Format first, read second. The bug is almost always visible the moment the nesting is correct.&lt;/p&gt;

</description>
      <category>xml</category>
      <category>webdev</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>The five characters that break your HTML (and the one habit that fixes them)</title>
      <dc:creator>Mubeen Khan</dc:creator>
      <pubDate>Fri, 06 Nov 2026 10:31:50 +0000</pubDate>
      <link>https://dev.to/mubeenkhaaan/the-five-characters-that-break-your-html-and-the-one-habit-that-fixes-them-3b6g</link>
      <guid>https://dev.to/mubeenkhaaan/the-five-characters-that-break-your-html-and-the-one-habit-that-fixes-them-3b6g</guid>
      <description>&lt;p&gt;You have done this. You paste a code snippet into a blog post, a comment box, or a CMS field, hit save, and half of it vanishes. The &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; you typed is gone. The &lt;code&gt;&amp;amp;&lt;/code&gt; in "Tom &amp;amp; Jerry" turned into something weird. A &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag someone typed into a form actually ran.&lt;/p&gt;

&lt;p&gt;It is not a bug in your editor. It is HTML doing exactly what it was designed to do: angle brackets mean "a tag starts here", and ampersands mean "an entity starts here". When you want those characters to show up as plain text, you have to tell the browser so, by writing them as HTML entities.&lt;/p&gt;

&lt;h2&gt;
  
  
  The five characters that matter
&lt;/h2&gt;

&lt;p&gt;Almost every encoding problem comes down to five characters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;&amp;amp;&lt;/code&gt; becomes &lt;code&gt;&amp;amp;amp;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;&lt;/code&gt; becomes &lt;code&gt;&amp;amp;lt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;gt;&lt;/code&gt; becomes &lt;code&gt;&amp;amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;"&lt;/code&gt; becomes &lt;code&gt;&amp;amp;quot;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;'&lt;/code&gt; becomes &lt;code&gt;&amp;amp;#39;&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is the whole list for safe output. Encode those five and your text displays exactly as typed, in every browser, with no surprises. Everything else, accented letters, currency symbols, emoji, can stay as plain UTF-8 text in a modern page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this is a security habit, not a formatting trick
&lt;/h2&gt;

&lt;p&gt;Encoding is the same operation that stops cross-site scripting. When a comment, a username, or a search box value is printed into a page without encoding, a stranger's &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag becomes your page's script tag. The OWASP XSS Prevention Cheat Sheet puts it plainly: encode untrusted data at output time, in the HTML body context, every time.&lt;/p&gt;

&lt;p&gt;The rule is "encode once, at output". Encoding twice is the classic self-inflicted bug: &lt;code&gt;&amp;amp;amp;&lt;/code&gt; encoded again becomes &lt;code&gt;&amp;amp;amp;amp;&lt;/code&gt; and your readers see raw codes on the page. If your output shows literal &lt;code&gt;&amp;amp;amp;&lt;/code&gt; text, you almost certainly encoded something that was already encoded.&lt;/p&gt;

&lt;h2&gt;
  
  
  The three forms an entity can take
&lt;/h2&gt;

&lt;p&gt;Entities come in three flavours, and a good decoder handles all of them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Named: &lt;code&gt;&amp;amp;copy;&lt;/code&gt; for ©, &lt;code&gt;&amp;amp;nbsp;&lt;/code&gt; for a non-breaking space, &lt;code&gt;&amp;amp;euro;&lt;/code&gt; for €.&lt;/li&gt;
&lt;li&gt;Decimal numeric: &lt;code&gt;&amp;amp;#169;&lt;/code&gt; for the same ©.&lt;/li&gt;
&lt;li&gt;Hex numeric: &lt;code&gt;&amp;amp;#xA9;&lt;/code&gt;, again the same ©.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They are interchangeable to the browser. Named entities are the readable choice when a human will read the source; numeric entities are the fallback for characters with no named form. Decoding has to recognise all three, including mixed content where a string contains named and numeric entities side by side.&lt;/p&gt;

&lt;h2&gt;
  
  
  When named entities actually help
&lt;/h2&gt;

&lt;p&gt;For everyday content, minimal encoding (the five characters) plus UTF-8 is the right default. Named entities earn their keep in three spots: &lt;code&gt;&amp;amp;nbsp;&lt;/code&gt; when two words must never split across a line, &lt;code&gt;&amp;amp;mdash;&lt;/code&gt; and &lt;code&gt;&amp;amp;ndash;&lt;/code&gt; when you want real dashes without worrying about keyboard layouts, and &lt;code&gt;&amp;amp;copy;&lt;/code&gt; &lt;code&gt;&amp;amp;reg;&lt;/code&gt; &lt;code&gt;&amp;amp;trade;&lt;/code&gt; in footers and legal lines where the symbol has to survive copy-paste through systems that mangle UTF-8.&lt;/p&gt;

&lt;p&gt;A quick way to check your own output: paste a snippet containing &lt;code&gt;&amp;lt;&lt;/code&gt;, &lt;code&gt;&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;amp;&lt;/code&gt; and a quote into a free HTML entities encoder and decoder, encode it, and read the result. If the output is readable and every special character turned into an entity, your mental model is right. I built one for exactly this check, it runs entirely in your browser and never uploads your text: &lt;a href="https://www.theutilityhub.online/tools/html-entities-encoder-decoder" rel="noopener noreferrer"&gt;https://www.theutilityhub.online/tools/html-entities-encoder-decoder&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The habit to keep
&lt;/h2&gt;

&lt;p&gt;Encode at output, decode at input, never twice, and never trust raw text from a user into a page. It is five characters and one rule, and it removes an entire class of bugs, from vanishing code snippets to stored XSS, in one move.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>tutorial</category>
      <category>html</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Your brand has one color. The color wheel knows the other four.</title>
      <dc:creator>Mubeen Khan</dc:creator>
      <pubDate>Thu, 05 Nov 2026 10:30:23 +0000</pubDate>
      <link>https://dev.to/mubeenkhaaan/your-brand-has-one-color-the-color-wheel-knows-the-other-four-45b1</link>
      <guid>https://dev.to/mubeenkhaaan/your-brand-has-one-color-the-color-wheel-knows-the-other-four-45b1</guid>
      <description>&lt;p&gt;Every designer has been here. You have one good brand color, maybe a blue you love, and now you need four more that go with it. So you open a color picker, guess a lighter blue, guess a pink that might work, and twenty minutes later your palette looks like five strangers at a bus stop.&lt;/p&gt;

&lt;p&gt;That guessing is the problem. Color harmony is not taste, it is math, and the color wheel has done the work for you for about three hundred years.&lt;/p&gt;

&lt;h2&gt;
  
  
  The wheel is a calculator
&lt;/h2&gt;

&lt;p&gt;A color is really three numbers: hue (where it sits on the wheel, 0 to 360), saturation (how vivid it is) and lightness (how bright). Harmony rules are just recipes for picking hues at fixed distances from your base color.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Complementary:&lt;/strong&gt; your color plus the one exactly opposite it on the wheel, 180 degrees away. Blue and orange, purple and yellow. High contrast, high energy, and the reason every "50 percent off" banner you have ever seen is orange on blue. Use it for accents and calls to action, never for two big areas side by side, or the page starts vibrating.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Analogous:&lt;/strong&gt; your color plus its two neighbors, 30 degrees on either side. Blue, blue-green and green. Calm, natural, almost impossible to get wrong. This is the palette of dashboards and documentation sites, the ones that feel quiet and professional without trying.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Triadic:&lt;/strong&gt; three colors evenly spaced, 120 degrees apart. Bold and balanced at the same time, which is why it shows up in branding for kids products, games and anything that needs to feel fun without feeling random. The trick is letting one color dominate and using the other two sparingly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Split-complementary:&lt;/strong&gt; your color plus the two colors next to its opposite. You get almost the punch of complementary without the vibration. It is the safe version of the loudest rule, and it is the one I reach for most.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tetradic:&lt;/strong&gt; two complementary pairs, a rectangle on the wheel. Four colors is a lot, so this one needs discipline: one dominant color, the rest as support. Get it right and a site feels rich; get it wrong and it feels like a carnival.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Monochromatic:&lt;/strong&gt; one hue, different lightnesses. The easiest palette that always works. A dark navy, a mid blue, a pale sky blue, and you have a complete UI with zero risk. Boring is a feature when the content needs to do the talking.&lt;/p&gt;

&lt;h2&gt;
  
  
  The mistake everyone makes with tints
&lt;/h2&gt;

&lt;p&gt;Pick a palette from a generator and the first thing people do is lighten a color by mixing it with white in RGB. That is how you get washed out pastels that look tired. Lighten in HSL space instead: keep the hue and saturation, raise the lightness. The color stays itself, just brighter. The same applies to darkening, which is how you get deep, rich shades instead of muddy ones.&lt;/p&gt;

&lt;p&gt;The second mistake is contrast. A beautiful palette is useless if nobody can read the text on it. The rule is simple and checkable: body text needs a contrast ratio of at least 4.5 to 1 against its background, large text 3 to 1. You can compute this exactly from the two colors, so there is no reason to guess. If your light grey text fails on your light blue background, darken the text or darken the background until the number passes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The workflow that saves the twenty minutes
&lt;/h2&gt;

&lt;p&gt;You do not need to memorize the wheel. Pick your base color, pick a rule, and let the math build the palette: &lt;a href="https://www.theutilityhub.online/tools/color-palette-generator" rel="noopener noreferrer"&gt;https://www.theutilityhub.online/tools/color-palette-generator&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The generator I built gives you all six harmony rules from one base color, lets you lock the swatches you like and regenerate the rest, checks the WCAG contrast ratio for any text and background pair, and exports the finished palette as CSS variables, a Tailwind config or JSON. Copy the variables into your stylesheet and the palette is live in your project.&lt;/p&gt;

&lt;p&gt;One habit worth stealing: export the palette as CSS variables on day one, before you write a single component. &lt;code&gt;--color-primary&lt;/code&gt;, &lt;code&gt;--color-accent&lt;/code&gt;, &lt;code&gt;--color-surface&lt;/code&gt;, &lt;code&gt;--color-text&lt;/code&gt;. When the brand color changes later, and it will, you change one line instead of hunting hex codes through fifty files.&lt;/p&gt;

&lt;p&gt;Your brand color was never the hard part. The wheel already knew the other four. Let it tell you.&lt;/p&gt;

</description>
      <category>css</category>
      <category>webdev</category>
      <category>tutorial</category>
      <category>design</category>
    </item>
    <item>
      <title>Your CSS gradient has a muddy middle, and it is not your fault</title>
      <dc:creator>Mubeen Khan</dc:creator>
      <pubDate>Wed, 04 Nov 2026 10:29:47 +0000</pubDate>
      <link>https://dev.to/mubeenkhaaan/your-css-gradient-has-a-muddy-middle-and-it-is-not-your-fault-1moe</link>
      <guid>https://dev.to/mubeenkhaaan/your-css-gradient-has-a-muddy-middle-and-it-is-not-your-fault-1moe</guid>
      <description>&lt;p&gt;A two color gradient should be simple. You pick a blue and a pink, you write one line of CSS, and the middle comes out grey. Not blue-pink. Grey. Muddy, washed out grey, like someone mixed all the paint together.&lt;/p&gt;

&lt;p&gt;That grey middle is not a bug in your code. It is how RGB interpolation works, and once you see it you cannot unsee it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the browser actually does
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;background: linear-gradient(90deg, #2563eb 0%, #ec4899 100%)&lt;/code&gt; tells the browser to walk from blue to pink. In RGB space that walk passes through the average of the two colors, and the average of a saturated blue and a saturated pink is a desaturated mauve-grey. The browser did exactly what you asked. You just asked in the wrong color space.&lt;/p&gt;

&lt;p&gt;Three fixes, in order of effort:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Add a middle stop.&lt;/strong&gt; Put a vivid color at 50 percent and the gradient has to pass through it. &lt;code&gt;#2563eb 0%, #8b5cf6 50%, #ec4899 100%&lt;/code&gt; never goes grey because the midpoint is a real purple, not an average. This is the fastest fix and it works everywhere.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Use more stops, closer together.&lt;/strong&gt; A gradient with stops at 0, 25, 50, 75 and 100 percent gives you control over the whole journey instead of letting the browser improvise the middle. Hard stops, two stops at the same percentage, give you a clean split instead of a blend, which is how striped and two-tone backgrounds are made.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Change the interpolation space.&lt;/strong&gt; Modern CSS lets you write &lt;code&gt;linear-gradient(in oklch, #2563eb, #ec4899)&lt;/code&gt;, and OKLCH walks through vivid colors instead of grey. It looks dramatically better. The catch is older browsers: keep a plain RGB gradient line above it as a fallback, and browsers that understand the new syntax will use the better one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Angle and shape matter more than color
&lt;/h2&gt;

&lt;p&gt;Most gradients people dislike are not bad colors, they are bad geometry. A 90 degree gradient across a wide hero banner stretches the blend so thin that most of the banner is one flat color. A 135 degree diagonal keeps the blend visible. A radial gradient centered on the content draws the eye inward, which is why it works for cards and modals. A conic gradient starting at the top spins color around a point, which is great for pie charts and progress rings and terrible for backgrounds.&lt;/p&gt;

&lt;p&gt;Pick the type for the job: linear for banners and buttons, radial for spotlights and cards, conic for rings and charts.&lt;/p&gt;

&lt;h2&gt;
  
  
  The workflow that saves time
&lt;/h2&gt;

&lt;p&gt;Write gradients by hand and you will spend twenty minutes tweaking percentages and reloading. Use a visual builder instead: pick the type, drag the stops, set the angle, and copy the finished CSS. I built one that also gives you the Tailwind class and a PNG or SVG export for when the design needs an image instead of code: &lt;a href="https://www.theutilityhub.online/tools/css-gradient-generator" rel="noopener noreferrer"&gt;https://www.theutilityhub.online/tools/css-gradient-generator&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One more habit worth stealing: never ship a gradient without a fallback background color. Put &lt;code&gt;background-color&lt;/code&gt; with your first stop color on the line above the gradient. If anything fails, the page still shows a sensible solid color instead of white.&lt;/p&gt;

&lt;p&gt;The grey middle was never your taste failing. It was RGB interpolation doing its job. Give it a middle stop or a better color space, and the gradient you imagined is the one that shows up.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>tutorial</category>
      <category>css</category>
      <category>design</category>
    </item>
  </channel>
</rss>
