<?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: Lars-Erik Bruce</title>
    <description>The latest articles on DEV Community by Lars-Erik Bruce (@lebbe).</description>
    <link>https://dev.to/lebbe</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1177700%2F060e8a0a-d7ff-41ce-a4e2-036dfbf5571f.png</url>
      <title>DEV Community: Lars-Erik Bruce</title>
      <link>https://dev.to/lebbe</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/lebbe"/>
    <language>en</language>
    <item>
      <title>Use anchors, not buttons, for navigation!</title>
      <dc:creator>Lars-Erik Bruce</dc:creator>
      <pubDate>Tue, 25 Feb 2025 15:02:56 +0000</pubDate>
      <link>https://dev.to/lebbe/use-anchors-not-buttons-for-navigation-1p95</link>
      <guid>https://dev.to/lebbe/use-anchors-not-buttons-for-navigation-1p95</guid>
      <description>&lt;p&gt;As the web enthusiast that I am, I do prefer that links who takes me to different pages or sites actually use an anchor, and not a button. That is, that in the DOM-tree, it is coded as an a-tag with an href-attribute. By all means - attach an event listener, and do your magic if you must, but please avoid using a button instead of an anchor.&lt;/p&gt;

&lt;p&gt;The reasons for using an anchor are plentiful: Screen readers will know that it is a link, which takes you places, and not a button, that only emits actions. You can right click the link, and open it in a separate tab or window. You can hover over the link, and see where it takes you. But recently I experienced even another good reason, that I haven't contemplated earlier!&lt;/p&gt;

&lt;p&gt;We had a page that became irresponsible due to a javascript bug: A React component was re-rendered in infinity, due to some malicious state update inside a useEffect. The page was merely a navigational page, with lots of buttons for navigation. The buttons was deemed useless, due to the bug. But: If we had used anchors instead of buttons, the page would still have been working just fine! The bug would still be there, of course, but our end users wouldn’t even know that the page was buggy.&lt;/p&gt;

&lt;p&gt;Of course, I fixed the re-rendering bug as well. But before I did so, I confirmed that using links worked, despite the bug being present. And I guess the morality of the story is, that even when javascript runs amok, and kills most of the interactivity and dynamic behaviour on the page, completely normal, good old anchors, still works as a charm!&lt;/p&gt;

&lt;p&gt;So no need breaking the web with navigational buttons!&lt;/p&gt;

</description>
      <category>html</category>
      <category>webdev</category>
      <category>programming</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Name your APIs carefully!</title>
      <dc:creator>Lars-Erik Bruce</dc:creator>
      <pubDate>Tue, 29 Oct 2024 10:15:40 +0000</pubDate>
      <link>https://dev.to/lebbe/name-your-apis-carefully-3okb</link>
      <guid>https://dev.to/lebbe/name-your-apis-carefully-3okb</guid>
      <description>&lt;p&gt;The content of thoughts are words and concepts. The more precise your vocabulary is, the more precise are your thoughts.&lt;/p&gt;

&lt;p&gt;Misleading or wrong names on fields, variable names, endpoints, will make your thoughts about your own code less precise. This is the most important in APIs meant to be consumed by several programmers.&lt;/p&gt;

&lt;p&gt;If you find that something in your API could be named more precise, I find that it will be better for all parts if you deprecate this at once, and introduce the more precise name.&lt;/p&gt;

</description>
      <category>api</category>
      <category>programming</category>
    </item>
    <item>
      <title>GlobalErrorHandler: Catch the errors that falls through ErrorBoundary's fingers!</title>
      <dc:creator>Lars-Erik Bruce</dc:creator>
      <pubDate>Mon, 21 Oct 2024 10:56:54 +0000</pubDate>
      <link>https://dev.to/lebbe/globalerrorhandler-catch-the-errors-that-falls-through-errorboundarys-fingers-3m5d</link>
      <guid>https://dev.to/lebbe/globalerrorhandler-catch-the-errors-that-falls-through-errorboundarys-fingers-3m5d</guid>
      <description>&lt;p&gt;ErrorBoundary is a magnificent tool to capture errors thrown from React components. You can provide custom error messages according to the nature and placement of the error itself. But not all errors thrown are handled by the ErrorBoundary! What do you do with those?&lt;/p&gt;

&lt;p&gt;When considering both async errors and errors throw from outside of React, the ErrorBoundary fall short. To mitigate this, I have in my applications created what I call an GlobalErrorHandler. A functional component that simply A) Pop up an error dialog, telling the user that &lt;em&gt;something&lt;/em&gt; went wrong, B) Logs the error to the server, so we can investigate and find solutions.&lt;/p&gt;

&lt;p&gt;The idea is simple. We want one GlobalErrorHandler in the root of our application. This handler should &lt;em&gt;only handle errors not caught by the ErrorBoundary&lt;/em&gt;. What more, it should be easily dismissed by the user, and we should assume that the application still is usable (to some degree).&lt;/p&gt;

&lt;p&gt;So the strategy is this: The GlobalErrorHandler doesn't do anything at all, except rendering its children (i.e. the rest of the application), by default. But, it sets up two event listeners, listening for all &lt;code&gt;error&lt;/code&gt; and &lt;code&gt;unhandledrejection&lt;/code&gt; events in the browser. Then it examines the error, and see if it has already been handled by any ErrorBoundaries. Finally, if that isn't the case, it pops up a Dialog, telling the user that something went wrong somewhere, and lets the user dismiss the dialog and continue using the application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Has the error already been handled
&lt;/h2&gt;

&lt;p&gt;Before pestering end users with unnecessary dialogs ON TOP OF the handling done by ErrorBoundary, we first have to start with asking the error: Have you been handled already? My solution to this, is to introduce a new field on the error-object &lt;code&gt;isHandledByBoundary&lt;/code&gt;. This is set to true within ErrorBoundary:&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="nf"&gt;componentDidCatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;errorInfo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ErrorInfo&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;error&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;isHandledByBoundary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&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 this in place in all ErrorBoundary-components (and other machinery that handles uncaught errors), we are ready to start defining our &lt;code&gt;GlobalErrorHandler&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bare skeleton
&lt;/h2&gt;

&lt;p&gt;Then we can build the skeleton of our GlobalErrorHandler. It straightforwardly render its children, and it also renders an "ErrorDialog" defined elsewhere. (If you want to share this component across applications, the ErrorDialog could be a prop instead.)&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ReactNode&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ErrorDialog&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../Components/ErrorDialog&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ReactNode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;GlobalErrorHandler&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Error&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kr"&gt;string&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;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isDialogOpen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setDialogOpen&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&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="p"&gt;....&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleCloseDialog&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setDialogOpen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&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="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isDialogOpen&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ErrorDialog&lt;/span&gt;
          &lt;span class="nx"&gt;actionName&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Unhandled error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="nx"&gt;loggFeilmelding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="nx"&gt;onClose&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleCloseDialog&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;)}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;The only thing we are lacking now, are the error handling itself, defined within &lt;code&gt;useEffect&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handling the errors
&lt;/h2&gt;

&lt;p&gt;All the code in this section should be located within the &lt;code&gt;useEffect&lt;/code&gt; function!&lt;/p&gt;

&lt;p&gt;First we define &lt;code&gt;handleWindowError&lt;/code&gt;. This is to be delivered to the &lt;code&gt;error&lt;/code&gt; event-handler on the &lt;code&gt;window&lt;/code&gt;-object. Nothing mysterious here, but witness that the error event also contains information about source, line number and col number. Which might be valuable to collect.&lt;/p&gt;

&lt;p&gt;Usually this information is also found within the error object, but I need to make more empirical investigations into this. Perhaps we always should keep the line and col numbers as reported by the error-event? In that case, we could also have a state for this within &lt;code&gt;GlobalErrorHandler&lt;/code&gt; (and make sure this is sent when logging the error).&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;handleWindowError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;message&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;|&lt;/span&gt; &lt;span class="nx"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;source&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;lineno&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;colno&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;error&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nb"&gt;Error&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;error&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;isHandledByBoundary&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="kc"&gt;true&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;errorMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;
        &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;
        &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Error: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; at &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;source&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;lineno&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;colno&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="nf"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;errorMessage&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nf"&gt;setDialogOpen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&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;We will also define the &lt;code&gt;handleUnhandledRejection&lt;/code&gt; handler. This is for errors that are raised within promises, but where we forgot to write a &lt;code&gt;.catch()&lt;/code&gt;-clause.&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;handleUnhandledRejection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PromiseRejectionEvent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Unhandled promise rejection: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reason&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="nf"&gt;setDialogOpen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then all we need to do, is to setup the listeners, and remove the listeners whenever GlobalErrorHandler is not rendered anymore:&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="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleWindowError&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;unhandledrejection&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleUnhandledRejection&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleWindowError&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;unhandledrejection&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;handleUnhandledRejection&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 return statements is, of course, where we return out of the function we are feeding &lt;code&gt;useEffect&lt;/code&gt;. This ensures that we are starting to listen on events and handle them when the component renders, and stop when the component is not rendered any more.&lt;/p&gt;

&lt;p&gt;Thus we have a GlobalEventHandler, to handle those pesky errors in our React-application that are either thrown from asynchronous sources, or thrown from outside of the React components!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>react</category>
      <category>typescript</category>
      <category>javascript</category>
    </item>
    <item>
      <title>AHA-programming, an analogy</title>
      <dc:creator>Lars-Erik Bruce</dc:creator>
      <pubDate>Fri, 11 Oct 2024 07:25:24 +0000</pubDate>
      <link>https://dev.to/lebbe/aha-programming-an-analogy-3c85</link>
      <guid>https://dev.to/lebbe/aha-programming-an-analogy-3c85</guid>
      <description>&lt;p&gt;&lt;strong&gt;DRY code&lt;/strong&gt; is like a desert, useful code is miles apart.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;WET code&lt;/strong&gt; is like the ocean, you are drowning in code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AHA code&lt;/strong&gt; is like as if the old Greek philosophers woke up from the dead, and started programming.&lt;/p&gt;

&lt;p&gt;If you have no clue what I'm on about, read &lt;a href="https://kentcdodds.com/blog/aha-programming" rel="noopener noreferrer"&gt;this post about AHA-programming&lt;/a&gt; by Kent C. Dodds.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>code</category>
      <category>aha</category>
      <category>dry</category>
    </item>
    <item>
      <title>You probably don't need a monorepo</title>
      <dc:creator>Lars-Erik Bruce</dc:creator>
      <pubDate>Mon, 26 Aug 2024 09:32:37 +0000</pubDate>
      <link>https://dev.to/lebbe/you-probably-dont-need-a-monorepo-50oc</link>
      <guid>https://dev.to/lebbe/you-probably-dont-need-a-monorepo-50oc</guid>
      <description>&lt;p&gt;If you have several npm packages inside the same "monorepo", you and your users would probably be better off if this was one big coherent package instead.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A lot of bookkeeping and administrative tasks just disappear.&lt;/li&gt;
&lt;li&gt;Three shaking removes unused code either way.&lt;/li&gt;
&lt;li&gt;Unhealthy dependencies between each package is impossible, because everything is just one single dependency.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Instead of "monorepo", consider a monolith instead. That is, one huge application. It solves the same "issues", but with a lot less administration between the teams sharing the components.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>programming</category>
    </item>
    <item>
      <title>Just the Code!</title>
      <dc:creator>Lars-Erik Bruce</dc:creator>
      <pubDate>Thu, 30 May 2024 07:14:58 +0000</pubDate>
      <link>https://dev.to/lebbe/just-the-code-2ib5</link>
      <guid>https://dev.to/lebbe/just-the-code-2ib5</guid>
      <description>&lt;p&gt;I have written two GPTs to help me write code. They are both called "Just the Code". They are instructed to just answer with the code, and keep the explanations to the minimum, when helping you code an application.&lt;/p&gt;

&lt;p&gt;Both are geared towards browser applications, one for &lt;a href="https://chatgpt.com/g/g-MFFoy4LoX-just-the-code-vanilla-javascript" rel="noopener noreferrer"&gt;vanilla Javascript&lt;/a&gt; and one for &lt;a href="https://chatgpt.com/g/g-nwYx83z7Q-just-the-code-react-typescript" rel="noopener noreferrer"&gt;React + TypeScript&lt;/a&gt;. Give them both a go!&lt;/p&gt;

&lt;p&gt;Since free users of ChatGPT now also are able to use GPTs, everyone are now able to test out these code helpers. So be sure to check it out!&lt;/p&gt;

&lt;p&gt;As an example, &lt;a href="https://lebbe.neocities.org/snake" rel="noopener noreferrer"&gt;here is an implementation of snake&lt;/a&gt; Just the Code wrote in &lt;a href="https://chatgpt.com/g/g-MFFoy4LoX-just-the-code-vanilla-javascript" rel="noopener noreferrer"&gt;vanilla Javascript&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>chatgpt</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>react</category>
    </item>
    <item>
      <title>Why you should always set responsive mode to 320px when checking "mobile layout" on your web pages</title>
      <dc:creator>Lars-Erik Bruce</dc:creator>
      <pubDate>Tue, 07 May 2024 07:38:49 +0000</pubDate>
      <link>https://dev.to/lebbe/why-you-should-always-set-responsive-mode-to-320px-when-checking-mobile-layout-on-your-web-pages-3gd9</link>
      <guid>https://dev.to/lebbe/why-you-should-always-set-responsive-mode-to-320px-when-checking-mobile-layout-on-your-web-pages-3gd9</guid>
      <description>&lt;p&gt;In this day and age, you would seldom come across a smart phone with 320px width. So, why would you spend time checking your web sites or web applications against 320px window width? As it turns out, there are actually a handfull of good reasons to &lt;a href="https://developer.chrome.com/docs/devtools/device-mode" rel="noopener noreferrer"&gt;simulate a device width&lt;/a&gt; of 320px during web development!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;WCAG Reflow Compliance&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Lets take the most important point first. According to the Web Content Accessibility Guidelines (WCAG), &lt;a href="https://www.w3.org/WAI/WCAG21/Understanding/reflow.html" rel="noopener noreferrer"&gt;content must reflow&lt;/a&gt; on the screen so users can scroll vertically without having to scroll horizontally. This rule states that the minimum screen size must be either 320 CSS pixels or 1280 CSS pixels at 400% zoom.&lt;/p&gt;

&lt;p&gt;If you calculate 1280 / 4, you quickly discover that these are exactly the same size requirements. So when I develop web pages and web applications, I always ensure everything looks fine, and there are no horizontal scroll, at 320px, to stay WCAG compliant.&lt;/p&gt;

&lt;p&gt;Also make sure that if you intend for the page to scroll horizontally (instead of vertically), the WCAG requirement is then to support a screen height as small as 256 CSS pixels.&lt;/p&gt;

&lt;p&gt;But even if you don't consider WCAG compliance of importance, there are still other good reasons to always check against 320px width!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Detecting Overflow Issues&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you use 320px for testing, you will immediately identify overflow issues. If your layout does not cause horizontal scrolling at 320px during testing, you can be quite confident that this is true in production as well, for wider screen sizes!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cross-Device Compatibility&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you test the smallest size first, you are more likely to find potential issues that could affect larger sizes as well.  If everything is readable, all touch interactions works flawless, and the design still doesn't look cramped at 320px,  then you are certain to have no such issues with a larger screen size.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Crow epistemology: Have as few items as possible on each page&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In general, you want your audience to find what they are searching after as soon as possible. The best way to be certain that your web application isn't crowded with buttons and functionality, is to make the web page behave nice on a small 320px screen. You should see the most important information without any scrolling, and also be able to navigate further into the major sections within your application with ease. If this is manageable at 320px, you have a clean and clear page.&lt;/p&gt;

&lt;p&gt;If you find this difficult on a 320px screen, then new users not accustomed to your application will also find it difficult to navigate and find what they are looking for when using a big screen.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Even though no one would ever use a small phone with only 320px screen width these days, setting the responsive width in your browser to 320 pixels when developing can make you confident that you are making a page that can be used with ease by everyone.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>css</category>
      <category>javascript</category>
      <category>beginners</category>
    </item>
    <item>
      <title>this.savedUrl.startsWith is not a function</title>
      <dc:creator>Lars-Erik Bruce</dc:creator>
      <pubDate>Tue, 16 Apr 2024 15:13:24 +0000</pubDate>
      <link>https://dev.to/lebbe/thissavedurlstartswith-is-not-a-function-f3b</link>
      <guid>https://dev.to/lebbe/thissavedurlstartswith-is-not-a-function-f3b</guid>
      <description>&lt;p&gt;For years we had this dreaded error in our logs: &lt;code&gt;"this.savedUrl.startsWith is not a function"&lt;/code&gt;. Heaps of time has been spent trying to debug this, along with it's cousins "url.startsWith is not a function." and "url.match is not a function.". Here is the story about how I finally uncovered the causes of this bug, and how I fixed it.&lt;/p&gt;

&lt;p&gt;A search for &lt;a href="https://www.google.com/search?q=%22this.savedUrl.startsWith+is+not+a+function%22" rel="noopener noreferrer"&gt;"this.savedUrl.startsWith is not a function"&lt;/a&gt; did not yield a single search result. But we had a lot of these in our logs. How could it be that we where the only one affected?&lt;/p&gt;

&lt;p&gt;I could not, for the life of me, find "this.savedUrl.startsWith" anywhere in our codebase. The bug, it seemed, weren't ours. And I didn't feel I had anything to go by. At least the stack trace agreed: It claimed that the line of code with the error was outside of any script-file: It claimed the error was on the first line in the index.html file, or in a place called "@user-script:12:1:390" or something similar.&lt;/p&gt;

&lt;p&gt;Trying to debugging this, I enhanced our logging, and began collecting the User Agent for every log message. This gave some interesting insights:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;"url.match is not a function." all come from the iOS snapchat browser&lt;/li&gt;
&lt;li&gt;"this.savedUrl.startsWith is not a function." all come from Chrome on iOS&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I also noticed from the stack trace, that it had something to do with calls to XMLHttpRequest.prototype.open, so I assumed there must have been som non-standard implementation of this method.&lt;/p&gt;

&lt;p&gt;What I assumed next, was that we somehow managed to send &lt;code&gt;undefined&lt;/code&gt; instead of a &lt;code&gt;string&lt;/code&gt; as URL somewhere. But this didn't make sense either: Our application worked for most of the cases, only these peculiar edge cases seemed to cause trouble.&lt;/p&gt;

&lt;p&gt;But either way, the issue was only on iOS devices. I did not have any iOS device for debugging, and the company didn't have any test devices available. So I noted that a developer with an iPhone should take over these bug ticket, and kept developing new features instead of worrying about this old bug.&lt;/p&gt;




&lt;p&gt;But months went by, without anyone picking up the thread. We regularly had end users complaining about not being able to use our web application, and we still saw these error messages in the logs. So I started investigating some more. I got the bright idea that, instead of searching for the full error message "this.savedUrl.startsWith is not a function", what about only searching for "this.savedUrl.startsWith" instead?&lt;/p&gt;

&lt;p&gt;And what I found surprised me: The only place I could find this string, was some forks of the iOS implementation of Chrome.  So I got ahold of another developer who had an iPhone with Chrome, and got him to log into the application. But everything worked as expected. But then I started to investigate the code around "this.savedUrl.startsWith", and saw this was code for translating the page with Google translate!&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="cm"&gt;/**
 * Redefine XMLHttpRequest's send to call into the browser if it matches the
 * predefined translate security origin.
 * Only redefines once because this script may be injected multiple times.
 */&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;XMLHttpRequest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;realSend&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;undefined&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;XMLHttpRequest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;realSend&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;XMLHttpRequest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;send&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;XMLHttpRequest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;send&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// If this is a translate request, save this xhr and proxy the request to&lt;/span&gt;
    &lt;span class="c1"&gt;// the browser. Else, pass it through to the original implementation.&lt;/span&gt;
    &lt;span class="c1"&gt;// |securityOrigin| is predefined by translate_script.cc.&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;savedUrl&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="nx"&gt;securityOrigin&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;length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;__gCrWeb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;translate&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;xhrs&lt;/span&gt;&lt;span class="dl"&gt;'&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;__gCrWeb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invokeOnHost&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;command&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;translate.sendrequest&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;method&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;savedMethod&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;url&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;savedUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;body&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;requestID&lt;/span&gt;&lt;span class="dl"&gt;'&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;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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;realSend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="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;I asked my colleague to turn on automatic translation in his Chrome-for-iOS browser, and there it was! The bug appeared! The whole page crashed and became unusable, if it tried to translate the page during pageload.&lt;/p&gt;

&lt;p&gt;After a while, with devtools in Safari, we figured out how to get a breakpoint inside the specific chrome javascript. And sure enough, the url was not a string. &lt;strong&gt;&lt;em&gt;It was an array!&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So my assumption that the URL must have been undefined, was wrong. It was an array! And in hindsight this makes sense: If the url was undefined, the error message would have been something completely different, namely: "Uncaught TypeError: Cannot read properties of undefined (reading 'startsWith')".&lt;/p&gt;

&lt;p&gt;I felt a bit bad about this: My "undefined" hunch was so wrong, and perhaps I would have solved the bug months ago if I just kept my head straight. But either way, I now know that the URL we tried to fetch was an array, and not a string. Why?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If we only had used TypeScript instead of JavaScript, I guess this bug would never have existed in the first place.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;By some reasons, a developer decided many many years ago, when first implementing this application, to send in an array to &lt;code&gt;axios.get&lt;/code&gt; with a single element consisting of the URL, instead of the URL itself. Somehow XMLHttpRequest (and Axios) handles this correctly. But plugins and browsers who intercepts all traffic going through XMLHttpRequest, wasn't quite prepared that we serve an array, instead of a string, to &lt;code&gt;axios.get&lt;/code&gt;...&lt;/p&gt;

&lt;p&gt;More digging into the history of the code, I saw that initially the code looked something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;page&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;but in a commit it was rewritten to&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;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And this has, ever since, caused issues for the iOS snapchat browser, Chrome on iOS that translates pages automatically and also browsers with adblock-plugins. If we only had used TypeScript instead of JavaScript, I guess this bug would never have existed in the first place.&lt;/p&gt;

</description>
      <category>development</category>
      <category>javascript</category>
      <category>network</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Don't feed async functions to express handlers</title>
      <dc:creator>Lars-Erik Bruce</dc:creator>
      <pubDate>Thu, 18 Jan 2024 13:20:01 +0000</pubDate>
      <link>https://dev.to/lebbe/dont-feed-async-functions-to-express-handlers-4ia7</link>
      <guid>https://dev.to/lebbe/dont-feed-async-functions-to-express-handlers-4ia7</guid>
      <description>&lt;p&gt;Express does not support async handlers. I have witnessed an application who restarted every time the async function threw an error. This was on Node 16.&lt;/p&gt;

&lt;p&gt;When we updated to Node 20, the whole application froze instead. After too many hours with debugging, I uncovered that the issue was async functions in express.&lt;/p&gt;

&lt;p&gt;Running express on node 20, we weren't able to even see anyhing in the log. With node 16, the application crashed, with this error message:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node:internal/process/promises:279
triggerUncaughtException(err, true /* fromPromise */);
^
[UnhandledPromiseRejection: This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason "AxiosError: Request failed with status code 400".] {
code: 'ERR_UNHANDLED_REJECTION'
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So what happened was that inside an express route async function, we did a subsequent call to another API with Axios, that failed with a status code 400. But since express doesn't support async functions, it couldn't catch the error and handle it.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to fix it? Call your async function as a promise!
&lt;/h2&gt;

&lt;p&gt;Let's say you have the following route defined:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.get('/api/some/endpoint', someAsyncHandler);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can here write an inplace wrapper for the async handler:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.get('/api/some/endpoint', function someAsyncHandlerWrapper(req, res) {
  someAsyncHandler(req, res).catch(function errorHandler(error) {
    logger('Failed to handle this API endpoint.', e.message);
    res.sendStatus(500);
  }
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, use the async function as a promise (since async/await is just syntactic sugar for promises either way), and send a response code of 500 back to the client!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>beginners</category>
      <category>programming</category>
    </item>
    <item>
      <title>5 killer tricks to make your React Design System Component highly reusable! (You won't believe the Bonus trick!)</title>
      <dc:creator>Lars-Erik Bruce</dc:creator>
      <pubDate>Wed, 10 Jan 2024 13:28:50 +0000</pubDate>
      <link>https://dev.to/lebbe/5-killer-tricks-to-make-your-react-design-system-component-highly-reusable-you-wont-believe-the-bonus-trick-4kgh</link>
      <guid>https://dev.to/lebbe/5-killer-tricks-to-make-your-react-design-system-component-highly-reusable-you-wont-believe-the-bonus-trick-4kgh</guid>
      <description>&lt;p&gt;You have just made your perfect Component for the company's design system, and are ready to ship it out in your Component Library. But, are the developers depending on it as excited as you? No, because they know, with their new Component follows restraints in the form of a straight jacket and a trip to the nearest mental hospital!&lt;/p&gt;

&lt;p&gt;Why? Because the Jira asked for a rainbow component with custom colors, and odd behavior, which makes perfect business sense from their point of view, but that you "forgot" to think about in your crazy laboratory while cooking up new components!&lt;/p&gt;

&lt;p&gt;Don't fret! Let me tell you what features you should always include, so developers won't send you ugly thoughts and karma while they are crying themselves into sleep at night.&lt;/p&gt;

&lt;p&gt;Lets start with a made-up component. Scenario: You want to style a FormComponent in accordance with the design system sketches. Let's say you came up with the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export function FormComponent({ prefix, value, onChange }) {
  return (
    &amp;lt;div className={css.fsComponent}&amp;gt;
      &amp;lt;div className={css.fsComponentHeader}&amp;gt;{prefix}&amp;lt;/div&amp;gt;
      &amp;lt;input
        className={css.fsComponentInput}
        type="text"
        value={value}
        onChange={onChange}
      /&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It does exactly what is asked for, a simple input element with a prefix (and of course, your beautiful CSS styling). But how can we make this component both easier and more flexible to use?&lt;/p&gt;

&lt;h1&gt;
  
  
  1. Utilize PropTypes or TypeScript for type safety!
&lt;/h1&gt;

&lt;p&gt;Before we do anything else, we should add types to our component, so that developers using it gets a clear idea how it can be used automatically through their code editor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type Props = {
  prefix: string;
  value: string;
  onChange: (event: React.ChangeEvent&amp;lt;HTMLInputElement&amp;gt;) =&amp;gt; void;
};

export function FormComponent({ prefix, value, onChange }: Props) {
  return (
    &amp;lt;div className={css.fsComponent}&amp;gt;
      &amp;lt;div className={css.fsComponentHeader}&amp;gt;{prefix}&amp;lt;/div&amp;gt;
      &amp;lt;input
        className={css.fsComponentInput}
        type="text"
        value={value}
        onChange={onChange}
      /&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But, it looks like we adopted the mentality of restraining our developers in our types! What if the Jira calls for a flag icon in the input prefix?!&lt;/p&gt;

&lt;h1&gt;
  
  
  2. Use React.ReactNode as type for children and other props for jsx-arguments
&lt;/h1&gt;

&lt;p&gt;Don't impose strict rules about what is allowed for the compositional props, like &lt;code&gt;children&lt;/code&gt; (or &lt;code&gt;prefix&lt;/code&gt; in our example) . We never know how our Components are going to be used in advance.&lt;/p&gt;

&lt;p&gt;If we want to render props straight into the JSX-tree, we should never enforce the developers to send a string. Or an element for that sake! Sometimes, I just want to use a string as a child, but I have to put it inside a span, because the component requires an element! :-(&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type Props = {
  prefix: React.ReactNode;
  value: string;
  onChange: (event: React.ChangeEvent&amp;lt;HTMLInputElement&amp;gt;) =&amp;gt; void;
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;React.ReactNode allows for &lt;code&gt;null&lt;/code&gt;, &lt;code&gt;undefined&lt;/code&gt;, &lt;code&gt;string&lt;/code&gt;, &lt;code&gt;number&lt;/code&gt; and all variants of React elements!&lt;/p&gt;

&lt;h1&gt;
  
  
  3. Always include all props from the proper DOM-element
&lt;/h1&gt;

&lt;p&gt;Never limit the users of your component for what already exists in the DOM API! This not only allows the users of the component to customize your component with &lt;code&gt;style&lt;/code&gt; or &lt;code&gt;className&lt;/code&gt; when needed (which I'm sure you dread), it also gives them access to literally hundreds of other attributes from the DOM API!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type Props = {
  prefix: React.ReactNode;
  value: string;
  onChange: (event: React.ChangeEvent&amp;lt;HTMLInputElement&amp;gt;) =&amp;gt; void;
} &amp;amp; React.HTMLAttributes&amp;lt;HTMLDivElement&amp;gt;;

export function FormComponent({ prefix, value, onChange, ...props }: Props) {
  return (
    &amp;lt;div {...props} className={css.fsComponent + ' ' + (props.className || '')}&amp;gt;
      ...
    &amp;lt;/div&amp;gt;
  );
}

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

&lt;/div&gt;



&lt;p&gt;You can use the React.HTMLAttributes to easily add all DOM attributes as properties to your component. Remember to send in the HTMLElement that you use as a wrapper element (HTMLDivElement if it is a div, etc).&lt;/p&gt;

&lt;h1&gt;
  
  
  4. Propagate &lt;code&gt;ref&lt;/code&gt; with &lt;code&gt;forwardRef&lt;/code&gt;
&lt;/h1&gt;

&lt;p&gt;If you include a way for the developer to refer to your component, they are allowed to do basic stuff like managing focus, measure dimensions and positions and even integrate with third party DOM libraries!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type Props = {
  prefix: React.ReactNode;
  value: string;
  ref?: React.ForwardedRef&amp;lt;HTMLDivElement&amp;gt;;
  inputRef?: React.ForwardedRef&amp;lt;HTMLInputElement&amp;gt;;
  onChange: (event: React.ChangeEvent&amp;lt;HTMLInputElement&amp;gt;) =&amp;gt; void;
} &amp;amp; React.HTMLAttributes&amp;lt;HTMLDivElement&amp;gt;;

export function FormComponent({
  prefix,
  value,
  onChange,
  ref,
  inputRef,
  ...props
}: Props) {
  return (
    &amp;lt;div
      {...props}
      className={css.fsComponent + ' ' + (props.className || '')}
      ref={ref}
    &amp;gt;
      &amp;lt;div className={css.fsComponentHeader}&amp;gt;{prefix}&amp;lt;/div&amp;gt;
      &amp;lt;input
        ref={inputRef}
        className={css.fsComponentInput}
        type="text"
        value={value}
        onChange={onChange}
      /&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You don't have to provide a ref for every HTML tag you use in the components JSX. But the container element should have one, and also some pivotal elements, like input elements, could benefit from this.&lt;/p&gt;

&lt;p&gt;This way, the developers using your component can speak directly with the elements DOM API with ease, when needed.&lt;/p&gt;

&lt;h1&gt;
  
  
  5. Support both controlled and uncontrolled modes
&lt;/h1&gt;

&lt;p&gt;Don't decide how developers should use your component. Support both controlled and uncontrolled modes. Right now, we have a controlled component. By turning it into a component that can be used both controlled and uncontrolled, we empower the users of our Component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export function FormComponent({
  prefix,
  value,
  ref,
  onChange,
  inputRef,
  ...props
}: Props) {
  const [internalValue, setInternalValue] = useState(value);

  useEffect(() =&amp;gt; {
    // Update value if it is used as a controlled component
    if (onChange === undefined) {
      setInternalValue(value);
    }
  }, [value, onChange]);

  return (
    &amp;lt;div
      {...props}
      className={css.fsComponent + ' ' + (props.className || '')}
      ref={ref}
    &amp;gt;
      &amp;lt;div className={css.fsComponentHeader}&amp;gt;{prefix}&amp;lt;/div&amp;gt;
      &amp;lt;input
        ref={inputRef}
        className={css.fsComponentInput}
        type="text"
        value={onChange === undefined ? internalValue : value}
        onChange={(e) =&amp;gt; {
          if (onChange) {
            onChange(e);
          } else {
            setInternalValue(e.target.value);
          }
        }}
      /&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

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

&lt;/div&gt;



&lt;h1&gt;
  
  
  Bonus 6! Keep functionality out of your design style library!
&lt;/h1&gt;

&lt;p&gt;If your component library is meant to enforce a style guide, or a design pattern, why not let the users of the component library worry about the logic and only implement the styling? Then you also have a lot less of bug testing to worry about (I'm certain you will find bugs in the above example, for instance). What about just this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
type Props = {
  prefix: React.ReactNode;
  children: React.ReactNode;
  ref?: React.ForwardedRef&amp;lt;HTMLDivElement&amp;gt;;
} &amp;amp; React.HTMLAttributes&amp;lt;HTMLDivElement&amp;gt;;

export function FormComponent({ prefix, children, ref, ...props }: Props) {
  return (
    &amp;lt;div
      {...props}
      className={css.fsComponent + ' ' + (props.className || '')}
      ref={ref}
    &amp;gt;
      &amp;lt;div className={css.fsComponentHeader}&amp;gt;{prefix}&amp;lt;/div&amp;gt;
      &amp;lt;div className={css.fsComponentInputContainer}&amp;gt;{children}&amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

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

&lt;/div&gt;



&lt;p&gt;Style it up assuming that {children} is an input-element, state this clearly in the documentation, and let the developers deal with it if they feel they need something else. Then the design system only deals with the looks and feel of the application, while the application code deals with the functionality:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;FormElement prefix={&amp;lt;Icon svgPath={keyIconPath} /&amp;gt;}&amp;gt;
  &amp;lt;input type="password" value={password} onChange={(e) =&amp;gt; setPassword(e.target.value)} /&amp;gt;
&amp;lt;/FormElement&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
    <item>
      <title>CSS in Stylesheets</title>
      <dc:creator>Lars-Erik Bruce</dc:creator>
      <pubDate>Wed, 03 Jan 2024 09:18:13 +0000</pubDate>
      <link>https://dev.to/lebbe/css-in-stylesheets-bke</link>
      <guid>https://dev.to/lebbe/css-in-stylesheets-bke</guid>
      <description>&lt;p&gt;What if we wrote the CSS rules in separate files, provided to the browsers as a form of "style sheets"?&lt;/p&gt;

&lt;p&gt;Instead of transpiling SASS, writing CSS in our Javascript or fill our HTML or templates with class-names that describes the style we want, here is a novel idea: What if we provided pure simple text files to the browser, explaining how we would like our web applications and documents to be styled?&lt;/p&gt;

&lt;p&gt;There seems to be many benefits of providing CSS in text files like these:&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Improved performance
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Faster loading times
&lt;/h3&gt;

&lt;p&gt;Pure CSS files are lightweight and it turns out, the browsers can work out their contents and apply the style much faster than competing methods. This again, makes sure the loading times are much faster.&lt;/p&gt;

&lt;p&gt;Also, the CSS doesn't even have to load, before the page is started rendering. The browser can apply styles whenever new style sheets are ready loaded.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cache efficiency
&lt;/h3&gt;

&lt;p&gt;Browsers can cache pure text files, which means that once a user has visited your web page, his browser doesn't have to download the CSS file again until next time you have changed the sites appearance.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Improved maintainance
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Simplified debugging
&lt;/h3&gt;

&lt;p&gt;When the CSS are located in separate files, it is easier to locate and fix styling issues. Especially when we write the style sheets ourselves, instead of relying on transpilation. When we isolate CSS from JS and HTML, we reduce complexity and make debugging a more straightforward process.&lt;/p&gt;

&lt;h3&gt;
  
  
  Version control friendly
&lt;/h3&gt;

&lt;p&gt;Writing the styles in pure text files, we can track, reverse and collaborate our style sheets with ease in git. &lt;/p&gt;

&lt;h2&gt;
  
  
  3. Enhanced flexibility and scalability
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Reusability
&lt;/h3&gt;

&lt;p&gt;CSS in text files can be reused across multiple pages. CSS written for a specific style class, can be reused for multiple components. This saves time, and ensures consistency in design.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scalability
&lt;/h3&gt;

&lt;p&gt;Having CSS in separate text files makes it easier to organize our styles. We can split the styles into different "sheets" (text files) and manage them independently.&lt;/p&gt;

&lt;p&gt;There are many ways we could divide the CSS files. We could use one for each component we make, one for each screen in our application, or heck, for smaller projects we could even make do with one single CSS file for the entire web site.&lt;/p&gt;

&lt;h2&gt;
  
  
  In conclusion
&lt;/h2&gt;

&lt;p&gt;Instead of the tried and tested approaches like "utility first" style classes like Tailwind, "css-in-js" frameworks, transpiled super CSS like SASS or Less, we could try something novel: Write plain CSS in plain text files. I think this would be an important and beneficial practice for modern web development. By understanding and implementing these principles, developers can create more efficient, maintainable and flexible web pages and web applications.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>css</category>
      <category>html</category>
      <category>productivity</category>
    </item>
    <item>
      <title>A px is not a pixel, long live the px!</title>
      <dc:creator>Lars-Erik Bruce</dc:creator>
      <pubDate>Mon, 27 Nov 2023 16:32:06 +0000</pubDate>
      <link>https://dev.to/lebbe/a-px-is-not-a-pixel-long-live-the-px-26l7</link>
      <guid>https://dev.to/lebbe/a-px-is-not-a-pixel-long-live-the-px-26l7</guid>
      <description>&lt;p&gt;One of the lessons you need to have conquered, before becoming the ultimate CSS maestro, is embracing the fact that a css &lt;code&gt;px&lt;/code&gt; is not the same as a screen resolution pixel. In CSS a px is a unit of measurement that is supposed to represent "one dot on the screen". Though, it is not always that  &lt;code&gt;1px&lt;/code&gt; is made up of a single screen pixel. Actually, in these "high resolution" days, seeing a CSS pixel actually align with screen pixels are quite rare. How can this be?&lt;/p&gt;

&lt;p&gt;One of the problems, is that screen resolution keeps getting larger, and if we insisted on letting &lt;code&gt;1px&lt;/code&gt; equal a screen pixel, web pages would become unreadable and ridiculously small on high resolution monitors.&lt;/p&gt;

&lt;p&gt;One CSS pixel is defined as the visual angle of one pixel on a device with a pixel density of 96 DPI (dots per inch) and a distance from the reader of an arm's length. Therefore we can also call a CSS pixel for "the visual angle unit". This definition is designed to make web content appear at a similar size across different devices.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"The absolute length units are fixed in relation to each other and anchored to some physical measurement. They are mainly useful when the output environment is known. The absolute units consist of the physical units (in, cm, mm, pt, pc, Q) and the visual angle unit (pixel unit) (px)." - &lt;a href="https://drafts.csswg.org/css-values/#absolute-lengths" rel="noopener noreferrer"&gt;CSS Values and Units Module Level 4 (w3C)&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Furthermore, the CSS specification defines a pixel to be &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/CSS_pixel" rel="noopener noreferrer"&gt;exactly 1/96th of a CSS inch&lt;/a&gt;, while &lt;code&gt;1cm&lt;/code&gt; is defined as &lt;code&gt;96px/2.54&lt;/code&gt; ( since one inch is 2.54 centimeters).&lt;/p&gt;

&lt;h2&gt;
  
  
  What can we learn from this? CSS pixel as the canonical unit!
&lt;/h2&gt;

&lt;p&gt;All this means that, when it comes to all CSS units of absolute length (cm, mm, Q, in, pc, pt and px), they are all reduced to a &lt;code&gt;px&lt;/code&gt; value. This means that you really don't need any other absolute length units than &lt;code&gt;px&lt;/code&gt;!&lt;/p&gt;

&lt;p&gt;It can sure be helpful to know that an inch is always 96 CSS pixels, or that a centimeter is always around 37.8 CSS pixels, as a guide to how many pixels you need. But in the end, in the style sheet, you are probably better off just specifying all absolute sizes in pixels.&lt;/p&gt;

&lt;h2&gt;
  
  
  What about relative length units?
&lt;/h2&gt;

&lt;p&gt;Many of the relative length units are also anchored to pixels, but you have to do the anchoring yourself. For instance, &lt;code&gt;1em&lt;/code&gt; is the same as the font-size in the element. So if the font-size is set to &lt;code&gt;14px&lt;/code&gt; for an element, then &lt;code&gt;1em&lt;/code&gt; is identical to &lt;code&gt;14px&lt;/code&gt;. &lt;code&gt;1rem&lt;/code&gt; is the same as the font-size in the root-element.&lt;/p&gt;

&lt;p&gt;This means that, in the end, if you specify all sizes with &lt;code&gt;px&lt;/code&gt; instead of these relative units, the screen will look identical. The upside of having used these relative units, comes when you change the font-size, and witness everything else adjust its sizes accordingly.&lt;/p&gt;

&lt;p&gt;I would argue, none-the-less, that in most cases setting the sizes with the &lt;code&gt;px&lt;/code&gt; unit is enough here as well, either way. If you maintain an application that rarely change design/font-sizes, it is rare that you need this automatic adjustment, and if you use &lt;code&gt;px&lt;/code&gt; as unit you have more control over the actual final sizes in your style.&lt;/p&gt;

&lt;p&gt;From an Universal Design perspective, you think you might need these relative units after all. So that the user might change their default font size in their browser settings. From empirical experience, it looks like most people who need a larger text either use browser/OS zoom, or reduce the screen resolution on their devices.&lt;/p&gt;

&lt;p&gt;So I'd say, go &lt;code&gt;px&lt;/code&gt; all the way!&lt;/p&gt;

</description>
      <category>css</category>
      <category>webdev</category>
      <category>beginners</category>
      <category>html</category>
    </item>
  </channel>
</rss>
