<?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: Kerry Boyko</title>
    <description>The latest articles on DEV Community by Kerry Boyko (@kerryboyko).</description>
    <link>https://dev.to/kerryboyko</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%2F111183%2Fdb08b246-e62e-4938-99f3-215bfed0a90a.jpg</url>
      <title>DEV Community: Kerry Boyko</title>
      <link>https://dev.to/kerryboyko</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kerryboyko"/>
    <language>en</language>
    <item>
      <title>A little trick for CSS/SCSS module safety</title>
      <dc:creator>Kerry Boyko</dc:creator>
      <pubDate>Fri, 05 Apr 2024 22:05:24 +0000</pubDate>
      <link>https://dev.to/kerryboyko/a-little-trick-for-cssscss-module-safety-eo1</link>
      <guid>https://dev.to/kerryboyko/a-little-trick-for-cssscss-module-safety-eo1</guid>
      <description>&lt;p&gt;This is a tip for those using CSS Modules. You know, things like: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;import styles from './componentStyles.module.scss'&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;While we may never have anything near the "type safety" of TypeScript in styling with SCSS or CSS, we can take advantage of a quirk in how CSS Modules work to make it so that we will be warned if we try to access a style in our stylesheet that is undefined. &lt;/p&gt;

&lt;p&gt;This actually comes up quite a bit - you may have a defined style (in BEM syntax) of something like &lt;code&gt;.home__button__main {&lt;/code&gt; but reference it in your React code as &lt;br&gt;
&lt;code&gt;&amp;lt;button className={styles.home__main__button}&amp;gt;Text&amp;lt;/button&amp;gt;&lt;/code&gt;. Or any number of typos.  The point is, if you try to access a value on the &lt;code&gt;styles&lt;/code&gt; object that is undefined, it will return &lt;code&gt;undefined&lt;/code&gt; which is a valid value, and which will be interpreted by your browser as &lt;code&gt;"undefined"&lt;/code&gt; leading to elements having class &lt;code&gt;.undefined&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Wouldn't it be great if we could get our browser to throw an error at build time or run time if we attempted to use a property on &lt;code&gt;styles&lt;/code&gt; that just wasn't there? &lt;/p&gt;

&lt;p&gt;We can. &lt;/p&gt;

&lt;p&gt;This is because style modules are interpreted in the JavaScript code as objects.  In Typescript, they'd be considered &lt;code&gt;type StyleModule = Record&amp;lt;string, string&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Here's the cool bit. In JS, there's a rarely used set of keywords: "get" and "set".  Getters and setters often make code more complicated and hard to follow - that's why they're used sparingly, and many people prefer the syntax of creating a getter function. Setters are even more confusing, because they can execute arbitrary code logic whenever assigning a variable.  There are a few cases in which this might be useful. For example:&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;class&lt;/span&gt; &lt;span class="nc"&gt;Weight&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;value&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="kd"&gt;get&lt;/span&gt; &lt;span class="nf"&gt;kilograms &lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nf"&gt;pounds &lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;2.2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="kd"&gt;set&lt;/span&gt; &lt;span class="nf"&gt;kilograms &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&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;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="kd"&gt;set&lt;/span&gt; &lt;span class="nx"&gt;pounds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mf"&gt;2.2&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;weight&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;Weight &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;weight&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;kilograms&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 10&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;weight&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pounds&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 22.0&lt;/span&gt;
&lt;span class="nx"&gt;weight&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;kilograms&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;weight&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pounds&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 11&lt;/span&gt;
&lt;span class="nx"&gt;weight&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pounds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;44&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;weight&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;kilograms&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 20&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And so on and so forth. &lt;/p&gt;

&lt;p&gt;Using this, we can actually run code &lt;em&gt;on setting or retrieving values&lt;/em&gt;, and change the output conditionally.  So what does this mean? &lt;/p&gt;

&lt;p&gt;It means we can write something like this:&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;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;makeSafeStyles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;level&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;strict&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;warn&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;passthrough&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;strict&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&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="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;prop&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="na"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// if element is defined, return it. &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;prop&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Reflect&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="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="c1"&gt;// otherwise, &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;level&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;strict&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TypeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`This class has no definition: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;level&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;warn&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;warn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="s2"&gt;`This class has no definition: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;. Defaulting to 'undefined &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
                &lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="c1"&gt;// we should &lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`undefined_class_definition &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Proxy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handler&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 result: When you use an undefined style in a project... this happens. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2de9zbnd3tfkz2iuj0fq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2de9zbnd3tfkz2iuj0fq.png" alt="Image description" width="800" height="482"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I can go into the code and see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;progress-bar-outer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;
                    &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;progress-inner-bar&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                    &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;width&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;formCompletionPercentage&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&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="si"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and to my module and see&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="nc"&gt;.progress-bar-outer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;relative&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$progress-bar-height&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="nf"&gt;get-palette&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"progress-bar-background"&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="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.progress-bar-inner&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;absolute&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$progress-bar-height&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="n"&gt;ease-out&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="mi"&gt;.25s&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="nf"&gt;get-palette&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"progress-bar-fill"&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;And I immediately know that there is a typo or spelling error that is simply fixed by correcting the line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;progress-bar-outer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;
                    &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;progress-bar-inner&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                    &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;width&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;formCompletionPercentage&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&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="si"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>css</category>
      <category>testing</category>
    </item>
    <item>
      <title>Talking with a client about Tailwind.</title>
      <dc:creator>Kerry Boyko</dc:creator>
      <pubDate>Fri, 15 Sep 2023 13:38:20 +0000</pubDate>
      <link>https://dev.to/kerryboyko/talking-with-a-client-about-tailwind-pjm</link>
      <guid>https://dev.to/kerryboyko/talking-with-a-client-about-tailwind-pjm</guid>
      <description>&lt;p&gt;I've been working on a 6wk contract gig to shore up some code, and the previous developer decided to go with Tailwind.  I've mentioned why I think that's a bad idea before, but I had to explain to my new clients some of the problems that have happened because of that initial poor choice:&lt;/p&gt;




&lt;p&gt;ME: So - I realise that it was another {my contractor} developer who chose to add Tailwind to this project. I don't know his or her reasoning. I can tell you, however, that one of the big problems with using Tailwind to create UI components is that it is extremely difficult (near impossible) to overwrite those properties assigned by tailwind utility classes when trying to extend a component to have the same functionality but different styles.&lt;/p&gt;

&lt;p&gt;I think for now it's best to just create a seperate "TransparentButton" and "RippleButton" components which are independent of the Button component defined in {our UI library}. &lt;/p&gt;

&lt;p&gt;Response: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I believe the overall goal with adding tailwind was to reduce the number of components and or css classes/styling we have to maintain. Ideally we maintain "nothing" outside of our core value prop and can just plug &amp;amp; play industry standard components &amp;amp; libraries.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I think that is a noble goal.  Unfortunately, in practice, I find Tailwind to actually be &lt;em&gt;counterproductive&lt;/em&gt; to that goal, because since you can't just make minor tweaks to existing libraries, or existing components, you end up having to recreate entire components from scratch.&lt;/p&gt;

&lt;p&gt;This is mostly because CSS does something Tailwind doesn't - it cascades.&lt;/p&gt;

&lt;p&gt;That is, if the library has a button called "Button" with the className of "bg-orange", it will have an orange background.  I can't then modify Button with react props or adding more Tailwind classes to create a button that is identical except it has different styling, (such as a transparent background).&lt;/p&gt;

&lt;p&gt;On the other hand, if the library's Button component were created with a CSS file associated with the class &lt;code&gt;.button&lt;/code&gt;, where button was defined as&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;.button&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="no"&gt;orange&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 could simply use that component, add another class name (&lt;code&gt;.transparent-button&lt;/code&gt;, for example) and then define the .transparent-button with&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;.transparent-button&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="nb"&gt;transparent&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 computer will read &lt;code&gt;&amp;lt;button class="button transparent-button"&amp;gt;Button&amp;lt;/button&amp;gt;&lt;/code&gt; as "First apply the &lt;code&gt;.button&lt;/code&gt; styles.  Then apply the &lt;code&gt;.transparent-button&lt;/code&gt; styles, overwriting any styles that are different."&lt;/p&gt;

&lt;p&gt;Tailwind doesn't have that functionality, in part because a design choice of tailwind is that it sorts class definitions according to it's own criteria (which I presume is alphabetical) in the tailwind postprocessor, not based on the order in which you write them.  &lt;/p&gt;

&lt;p&gt;So, If you were to define &lt;code&gt;&amp;lt;button class="bg-orange bg-transparent"/&amp;gt;&lt;/code&gt; then Tailwind would apply the orange. Because (I presume) "bg-o" comes before "bg-t"  alphabetically.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Modifying the Vue prototype is "evil monkey-patching"</title>
      <dc:creator>Kerry Boyko</dc:creator>
      <pubDate>Wed, 28 Apr 2021 23:16:05 +0000</pubDate>
      <link>https://dev.to/kerryboyko/modifying-the-vue-prototype-is-evil-monkey-patching-5dmi</link>
      <guid>https://dev.to/kerryboyko/modifying-the-vue-prototype-is-evil-monkey-patching-5dmi</guid>
      <description>&lt;p&gt;If you're not familiar with 'monkey-patching', it's when you modify the prototype of an existing language feature. Like adding a new method to Array.prototype, or redefining Array.prototype.reduce because it's just slightly more efficient to use lodash's version. &lt;/p&gt;

&lt;p&gt;It's a feature in a lot of high-level languages that use some type of inheritance, specifically Ruby, Python, and (naturally) Javascript. &lt;/p&gt;

&lt;p&gt;But just because you &lt;em&gt;can&lt;/em&gt; do something in Javascript &lt;a href="https://en.wikipedia.org/wiki/Monkey_patch#Pitfalls" rel="noopener noreferrer"&gt;doesn't mean you &lt;em&gt;should&lt;/em&gt;&lt;/a&gt;. Monkey-patching can lead to namespace collisions if two developers have their own methods - and you won't really know "which runs first" until runtime in most cases. (It's also really hard to unit test, since both methods will be tested and get correct assertions in isolation.) Additionally they create a discrepancy between the original source code and observed behavior.  &lt;/p&gt;

&lt;p&gt;Most importantly for the purposes of this article, it's a change that isn't immediately visible to those who use the code after you. You &lt;em&gt;think&lt;/em&gt; you're telling the computer to do one thing, but you're &lt;em&gt;actually&lt;/em&gt; telling the computer to do something else.  That, of course, is how you get bugs. &lt;/p&gt;

&lt;p&gt;Let's switch gears for a moment to the Vue framework.  &lt;/p&gt;




&lt;p&gt;First, I think Vue is great. It is well designed, written, documented. I like the way it's going with Vue 3.0 and the Vue Composition API, I like Vue templates, I like .vue files, I like that it's about 1/3rd the size of React. I like a lot of things about it. &lt;/p&gt;

&lt;p&gt;But if Paulie Walnuts held a gun to my head, and asked me what my favorite framework is, I'd say React.  &lt;/p&gt;

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

&lt;p&gt;And the reason is quite simple: Vue gives you &lt;em&gt;a lot of ways to do the same thing&lt;/em&gt;, and not all of those ways are good ways. Computed vs. Watch, callbacks vs. emits, mapGetters vs. mapState vs. this.$store... &lt;/p&gt;

&lt;p&gt;All are equally valid. None of these methods are canonically &lt;em&gt;wrong&lt;/em&gt; or &lt;em&gt;right&lt;/em&gt;. They all &lt;em&gt;work&lt;/em&gt;. This is part of the reason Vue is much easier to learn and get going with quickly than React is. But you start to lose out as the program and the team starts to scale. If you give a team of 10 developers 10 different ways to code something, you will end up with 10 different ways to do the same thing in your codebase, and a lot of highly-coupled code with duplicated logic.    &lt;/p&gt;




&lt;p&gt;At Deverus, where I first started working with Vue in 2017, we hired some (good) outside contractors which put configuration information on Vue.prototype.$config, constants on Vue.prototype.$constants, and all our asynchronous API methods on Vue.prototype.$API. They were probably following one of the many blog posts which suggested this pattern, like &lt;a href="https://www.telerik.com/blogs/api-factories-vue-nuxt" rel="noopener noreferrer"&gt;this one from Telerik&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;But this created a problem - and that problem was that now &lt;em&gt;every&lt;/em&gt; Vue component - even presentational ones that really did no logic - now had access to every API call, had access to every configuration setting, had access to every constant, even if they weren't needed. They also had the ability to redefine them at will. &lt;/p&gt;

&lt;p&gt;The most problematic was the &lt;code&gt;this.$API&lt;/code&gt; methods. If there was a problem, you'd have to search through every component to see what components were using this.$API, see where the data was being stored.  More often than not, multiple calls were being made to the same API method when one would do - data was often duplicated (or worse, duplicated, then became &lt;em&gt;out of sync&lt;/em&gt;) in many different &lt;code&gt;data()&lt;/code&gt; observables of components. &lt;/p&gt;

&lt;p&gt;This wasn't &lt;em&gt;wrong&lt;/em&gt;.  It's considered a &lt;em&gt;valid Vue pattern&lt;/em&gt;. And if you're using this pattern, you're not using Vue &lt;em&gt;wrong&lt;/em&gt;, but for us, it led to these problems. We had to create more style rules (in our case, put all the API calls into the Vuex store, not components, and pass down the data via mapped getters,) and refactor the application so that we could create a more testable application that was easier to add features to.  &lt;/p&gt;

&lt;p&gt;So - that's a bit of a long way round to get to the point of this post - which is to say that while there's no &lt;em&gt;official&lt;/em&gt; best practice guide that says you shouldn't modify, or "monkey-patch" the Vue prototype, &lt;em&gt;I'm&lt;/em&gt; saying that &lt;em&gt;from my experience&lt;/em&gt; you're probably going to have a bad time if you do. &lt;/p&gt;

&lt;p&gt;I suppose that vue prototype modification isn't "monkey-patching" the way that modifying the prototype of, say, Array or Object is.  But once you add the Vue framework to an application, it really does become so integral that the Vue prototype takes on a lot of the same importance as a core language feature. React developers expect React to behave like React every React application they work on.  Vue developers... well, in an ideal world they &lt;em&gt;should&lt;/em&gt; be able to rely on Vue, but because prototype modification is a &lt;em&gt;thing&lt;/em&gt;, they can't always. &lt;/p&gt;

&lt;p&gt;This can be further frustrating because monkey-patching the Vue prototype &lt;em&gt;is&lt;/em&gt; how vue-router and vuex (and a lot of other good plugins) work -- and work well. And it is extremely easy, for example, to get your route params from this.$route.params, compared to the hoops you used to have to jump through passing your parameters to your component with React (though the useRouter hook makes it really easy now).&lt;/p&gt;

&lt;p&gt;I'd like to think that they're exceptions. See, one of the things Vue has going for it is that because it doesn't try to stop you from doing &lt;em&gt;stupid things&lt;/em&gt;, it allows you to do very &lt;em&gt;clever&lt;/em&gt; things as well.  And vue-router and vuex are very clever indeed. &lt;/p&gt;

&lt;p&gt;And I'm not saying that you or your team isn't clever.  But if you're using Vue in production for a mission critical app, changes are you're dealing with things that make your team less clever than a decidicated core of open-source developers making sure that they can rigourously test, type, and develop software over many iterations.  &lt;/p&gt;

&lt;p&gt;A team that doesn't have time to pay off technical debt is going to lose "cleverness". A team being pressured to add a new feature before a deadline is going to lose "cleverness."  It's one of the reasons why open source purists like Richard Stallman (*1) believe that &lt;em&gt;all&lt;/em&gt; programming should be open source - a view I don't share, but one that has enough of a point that I can't fault him for holding it. &lt;/p&gt;

&lt;p&gt;So in the vein of "real world" programming for commercial applications (as opposed to open-source or academic purposes), monkey-patching the Vue prototype probably isn't something you want to get in the habit of. &lt;/p&gt;

&lt;p&gt;As always, looking to have a discussion in the comments below - I'm sure my experience wasn't universal, and plenty of people have been clever with Vue in their teams. &lt;/p&gt;

&lt;p&gt;In the meantime, if you want to take a look at some other suggestions I have for keeping large Vue projects organized, checkout my &lt;a href="https://gist.github.com/brianboyko/91fdfb492071e743e389d84eee002342" rel="noopener noreferrer"&gt;styleguide for Deverus (based on Vue 1.0)&lt;/a&gt; and my styleguide for the &lt;a href="https://gist.github.com/brianboyko/6e0af86f71da83a82cd4f074363ce046" rel="noopener noreferrer"&gt;Vue Composition API&lt;/a&gt; back when it was in proposal form.  I'll probably update and combine both and put them here on Dev.to soon.  &lt;/p&gt;




&lt;p&gt;&lt;a href="https://www.flickr.com/photos/scragz/132750805/in/photostream/" rel="noopener noreferrer"&gt;Evil monkey image by Jason Scragz&lt;/a&gt;, used under &lt;a href="https://creativecommons.org/licenses/by/2.0/" rel="noopener noreferrer"&gt;CC-2.0-Attribution&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Footnote: &lt;br&gt;
(*1) Correction: An earlier version of this article refered to Richard Stallman as Eric Stallman, (confusing him with fellow open source evangelist, Eric S. Raymond.) I regret the error.  &lt;/p&gt;

</description>
      <category>vue</category>
      <category>frontend</category>
      <category>javascript</category>
      <category>prototypes</category>
    </item>
    <item>
      <title>[RFC] Airfoil: Coding an alternative to Tailwind</title>
      <dc:creator>Kerry Boyko</dc:creator>
      <pubDate>Wed, 21 Apr 2021 17:18:21 +0000</pubDate>
      <link>https://dev.to/kerryboyko/rfc-coding-an-alternative-to-tailwind-30gp</link>
      <guid>https://dev.to/kerryboyko/rfc-coding-an-alternative-to-tailwind-30gp</guid>
      <description>&lt;p&gt;Update: Created a &lt;a href="https://github.com/brianboyko/Airfoil"&gt;crude github repo&lt;/a&gt; for Airfoil. It's mostly just a placeholder right now. &lt;/p&gt;




&lt;p&gt;My &lt;a href="https://dev.to/brianboyko/tailwindcss-adds-complexity-does-nothing-3hpn"&gt;previous post on TailwindCSS&lt;/a&gt; got a lot of views and comments. &lt;/p&gt;

&lt;p&gt;To my horror, while I've convinced many not to go down the path of Tailwind, a few others including, &lt;code&gt;(grumble, grumble)&lt;/code&gt; &lt;em&gt;my team lead&lt;/em&gt;, still think Tailwind has some good ideas. &lt;/p&gt;

&lt;p&gt;And here are some of his points: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Its valuable to be able to define a custom style within a single class, then use that wherever. For example: example box-shadow, border radius, different colors, font styles...&lt;/li&gt;
&lt;li&gt;Tailwind (with the CSS-in-JS tool, &lt;a href="https://twind.dev/"&gt;twind&lt;/a&gt;) provides a mental model to organize utility classes without polluting the global stylesheet. &lt;/li&gt;
&lt;li&gt;If you're going to use a utility class approach, why not use the same one as thousands of other developers? Otherwise you need to document your stuff well.
&lt;/li&gt;
&lt;li&gt;I think the alternative: building, managing, planning, documenting, fixing our own utility class solution is a nightmare.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And then he said some words I think he might now regret: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you think you can do a better job I would love to see how you'd approach it. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/yUI3a7RwLhOFy/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/yUI3a7RwLhOFy/giphy.gif" alt="WOO"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  WOO! WEEKEND PROJECT
&lt;/h1&gt;

&lt;p&gt;The truth is, yes, I &lt;em&gt;do&lt;/em&gt; think I could do better. And I don't think it would take that long. &lt;/p&gt;

&lt;p&gt;To his points directly: I think that we can define a much smaller &lt;em&gt;subset&lt;/em&gt; of the features of Tailwind, and do it better. I think that the cost of "building, managing, planning, documenting, and fixing" our own library that is &lt;em&gt;tiny&lt;/em&gt; (relative to Tailwind) is going to be easier than maintaining Tailwind in our projects, (as I believe Tailwind doesn't remove code you have to maintain, it just obscures it.) &lt;/p&gt;

&lt;p&gt;Let's be clear - in this library, (working title: "Airfoil") I wouldn't want to do everything that Tailwind does, because I'm firmly convinced 97% of what Tailwind does, Tailwind doesn't need to do, and indeed, &lt;em&gt;shouldn't&lt;/em&gt; do.  &lt;/p&gt;

&lt;p&gt;Instead, I'm talking about extracting only those utility classes which actually provide a good shorthand for complex concepts in CSS.  &lt;/p&gt;

&lt;p&gt;So for example, I can see how someone might like the shorthand "container" for something like this:&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;/* breakpoints */&lt;/span&gt;
&lt;span class="nt"&gt;--breakpoint-sm&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;640&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;--breakpoint-md&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;768&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;--breakpoint-lg&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;1024&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;--breakpoint-xl&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;1280&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;--breakpoint-2xl&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;1536&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="nc"&gt;.container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="n"&gt;screen&lt;/span&gt; &lt;span class="n"&gt;and&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--breakpoint-sm&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--breakpoint-sm&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="n"&gt;screen&lt;/span&gt; &lt;span class="n"&gt;and&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--breakpoint-md&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--breakpoint-md&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="n"&gt;screen&lt;/span&gt; &lt;span class="n"&gt;and&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--breakpoint-lg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--breakpoint-lg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="n"&gt;screen&lt;/span&gt; &lt;span class="n"&gt;and&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--breakpoint-xl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--breakpoint-xl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="n"&gt;screen&lt;/span&gt; &lt;span class="n"&gt;and&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--breakpoint-2xl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--breakpoint-2xl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;This&lt;/strong&gt;, to me, is the &lt;em&gt;perfect&lt;/em&gt; example of when a utility class makes sense to use. One word: "container" replaces 30 or so lines of code. It's reusable and does what it says on the tin. The only thing I'd do differently is name it 'with-container' rather than 'container', as I think the prefix 'with-' makes a lot of sense for a utility class to distinguish it from a semantic class. &lt;/p&gt;

&lt;p&gt;And if Tailwind were full of code like this, I wouldn't have a problem with it. &lt;/p&gt;

&lt;p&gt;But "container" is one of the eight or so exceptions which prove the 200+ rules that Tailwind is just full of stuff that can be replaced by one or two lines of 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;.flex&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.py-6&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;padding-left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.5rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding-right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.5rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So I went through Tailwind's documentation, and picked out the nine classes that I'd actually &lt;em&gt;keep&lt;/em&gt; out of the 200+ that Tailwind offers. &lt;/p&gt;

&lt;p&gt;And they are: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;container&lt;/li&gt;
&lt;li&gt;ring&lt;/li&gt;
&lt;li&gt;box-shadow&lt;/li&gt;
&lt;li&gt;filter (but possibly as a function/mixin)&lt;/li&gt;
&lt;li&gt;backdrop-filter (which will be difficult as neither Edge nor Firefox support backdrop-filter natively)&lt;/li&gt;
&lt;li&gt;drop-shadow&lt;/li&gt;
&lt;li&gt;animate-spin&lt;/li&gt;
&lt;li&gt;animate-ping&lt;/li&gt;
&lt;li&gt;animate-pulse&lt;/li&gt;
&lt;li&gt;screen-reader-only&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And at this point, if you're saying to the screen: "Well, what about X?" -- that's why I'm writing the post. &lt;/p&gt;

&lt;p&gt;I'm soliciting comments on what you think needs to be added to such a library.  Maybe it's in Tailwind and I missed it.  Maybe it's not in Tailwind, but you wish something like it was.  &lt;/p&gt;

&lt;p&gt;I also would like to know how you think it should be developed.  I think right now, the goal is to start life as a .CSS file on Github Gist, to get the proper effects right. &lt;/p&gt;

&lt;p&gt;Then, provide two different versions - one as styles and mixins as a partial (_airfoil.scss?) for an SCSS file, another which takes a function and just returns a string, for integration into libraries such as &lt;a href="https://styled-components.com/"&gt;styled-components&lt;/a&gt; and &lt;a href="https://emotion.sh/docs/introduction"&gt;emotion/css&lt;/a&gt;.  &lt;/p&gt;

&lt;p&gt;But again - before I do that, I need to scope out the project.  So - please retweet this among your dev friends, both &lt;a href="https://pbfcomics.com/comics/skub/"&gt;"pro-tailwind" and "anti-tailwind"&lt;/a&gt; and talk about what you'd like to see - or not like to see - in the comments below. &lt;/p&gt;

</description>
      <category>tailwindcss</category>
      <category>frontend</category>
      <category>css</category>
      <category>libraries</category>
    </item>
    <item>
      <title>TailwindCSS: Adds complexity, does nothing.</title>
      <dc:creator>Kerry Boyko</dc:creator>
      <pubDate>Mon, 19 Apr 2021 19:39:13 +0000</pubDate>
      <link>https://dev.to/kerryboyko/tailwindcss-adds-complexity-does-nothing-3hpn</link>
      <guid>https://dev.to/kerryboyko/tailwindcss-adds-complexity-does-nothing-3hpn</guid>
      <description>&lt;p&gt;If you work in the front-end, you've probably heard a lot about TailwindCSS, a CSS library, much like Bootstrap. Much &lt;em&gt;unlike&lt;/em&gt; Bootstrap, however, Tailwind takes a different approach - it is all "utility classes". &lt;/p&gt;

&lt;p&gt;And I am not a fan. I got a whiff of it and quickly learned the name is appropos: it was as welcome and useful as passed gas. &lt;/p&gt;

&lt;p&gt;Before we start, let me try to explain what a utility class is.  Let's say that you have many components, and many of them need to have the CSS style property: "display: flex;". Instead of writing that over and over in your css, multiple times, instead you create a class called "flex"&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.flex&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&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, in every component that needs to be flexed, you add that "flex" class.  &lt;/p&gt;

&lt;p&gt;This is not a bad thing.  I have written, and used utility classes a great deal myself, especially when I'm writing CSS without the aid of CSS-in-JS solutions or a preprocessor like Sass/SCSS. &lt;/p&gt;

&lt;p&gt;What Tailwind does is take that concept to the extreme, with the idea being that you &lt;em&gt;almost never&lt;/em&gt; have to write CSS, you just write different classes based on what styles you need to apply. &lt;/p&gt;

&lt;p&gt;Which is an interesting choice, because...&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgflip.com%2F56b3nt.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgflip.com%2F56b3nt.jpg" alt="This is just inline styles with extra steps"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  This is just inline styles with extra steps.
&lt;/h2&gt;

&lt;p&gt;That's it. Writing &lt;code&gt;&amp;lt;div class="flex"&amp;gt;foo&amp;lt;/div&amp;gt;&lt;/code&gt; has the same exact effect as writing &lt;code&gt;&amp;lt;div style="display: flex;"&amp;gt;foo&amp;lt;/div&amp;gt;&lt;/code&gt;. Well -- slightly different in that inline styles have higher priority than classes, but that's not really relevant in this context.  &lt;/p&gt;

&lt;p&gt;So - with that in mind, with the exception of CSS prioritization, any argument you could make against using inline styles in your codebase is also an argument against using Tailwind. For example: &lt;a href="https://www.lifewire.com/avoid-inline-styles-for-css-3466846" rel="noopener noreferrer"&gt;Lifewire: Avoiding Inline Styles for CSS Design&lt;/a&gt;. Or &lt;a href="https://stackoverflow.com/questions/2612483/whats-so-bad-about-in-line-css" rel="noopener noreferrer"&gt;StackOverflow: What's so bad about inline CSS?&lt;/a&gt;.   Or &lt;a href="https://blog.logrocket.com/why-you-shouldnt-use-inline-styling-in-production-react-apps/" rel="noopener noreferrer"&gt;LogRocket: Why you shouldn’t use inline styling in production React apps&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I know it seems a bit lazy to rehash other users criticisms of inline styles to explain what's wrong with Tailwind, but it really is a 1-to-1 mapping.  It's &lt;em&gt;just inline styles with extra steps.&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;Some of the problems Tailwind shares with inline styles: &lt;/p&gt;

&lt;h2&gt;
  
  
  It's WET, not DRY.
&lt;/h2&gt;

&lt;p&gt;When you want to change your site styling in a major way, if you've used utility classes, you need to go through each use of those utility classes - that is, every component - and visually determine what needs to be updated.  For example, let's say that your company's primary color is blue.  You'll have lots of blue stuff in your website, marked with things like: "text-blue-500" or "bg-blue-300" to determine different shades of blue. And that's fine until your company decides to rebrand, and all of the buttons - but only the buttons - on the site need to be red. &lt;/p&gt;

&lt;p&gt;Now you have to go through each component and manually change "text-blue-500" to "text-red-500". And with 1000 edits comes 1000 oppertunities to introduce a bug. It is almost a &lt;em&gt;textbook&lt;/em&gt; definition of why the DRY principle is in place. &lt;/p&gt;

&lt;p&gt;Alternatively, if you're using regular-old CSS, what you probably did is create a class called ".button".  You can just go into that class and change a single line: "background-color: 'red';". Any element that uses that class definition will now be red.  &lt;/p&gt;

&lt;p&gt;That brings us to the next point: &lt;/p&gt;

&lt;h2&gt;
  
  
  HTML should only concern itself with the &lt;em&gt;structure&lt;/em&gt; of your page, not the &lt;em&gt;styling&lt;/em&gt; of the page.
&lt;/h2&gt;

&lt;p&gt;People talk about seperation of concerns a lot in development. CSS Modules (and especially .vue files) have done a lot to dispel the notion that you need to segregate structure, behavior, and style of the same basic building block of your site in seperate folders, but there is something to be said for seperating concerns. That is - each part of your code should be "loosely coupled and highly cohesive."  &lt;/p&gt;

&lt;p&gt;In other words, your HTML (structure syntax) shouldn't have information about what the styles should be, it should only contain information about the &lt;em&gt;structure&lt;/em&gt; of the page. &lt;/p&gt;

&lt;p&gt;Indeed, &lt;em&gt;the ultimate reason for the invention of CSS,&lt;/em&gt; the whole &lt;strong&gt;point&lt;/strong&gt; of the entire enterprise of CSS... was &lt;em&gt;specifically&lt;/em&gt; so that you could seperate &lt;em&gt;content&lt;/em&gt; from &lt;em&gt;presentation.&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;And the method for doing this is through the "class" attribute. &lt;/p&gt;

&lt;p&gt;The whole point of "class" is specifically that you can tell the computer what an element &lt;em&gt;is&lt;/em&gt; - that is, describe an element's &lt;em&gt;content.&lt;/em&gt;  Once you've defined the content, then you just need to decide what content of that type should look like. &lt;/p&gt;

&lt;p&gt;This not only means that you can go and change how an element looks without worrying about the underlying structure of the page, but &lt;em&gt;also&lt;/em&gt; means that you can use these classes to &lt;em&gt;describe&lt;/em&gt; what an element is.  Indeed, part of the reason for BEM's naming syntax is that BEM names not only tell you what the component is, but also what it's relationship to other components in the document is.  &lt;/p&gt;

&lt;p&gt;Remember that when we write code, we write it for two audiences: the first is the computer itself, which doesn't care how the code &lt;em&gt;looks&lt;/em&gt; so long as it &lt;em&gt;runs&lt;/em&gt;, and the other is your fellow programmers.  The easier it is for them to quickly identify what parts of your program are and how they interrelate, the more quickly that they can fix bugs, add features, and bring value to the organization. &lt;/p&gt;

&lt;p&gt;Which brings us to:&lt;/p&gt;

&lt;h2&gt;
  
  
  It's hard to read
&lt;/h2&gt;

&lt;p&gt;If you look at some HTML with Tailwind in it, you might say to yourself that the HTML looks "busy" or even "ugly." That's true, but it's missing the point. &lt;/p&gt;

&lt;p&gt;Say what you will about inline styles, but they're at least providing enough context to let you know what's happening. Tailwind code is full of semantically obscure abbreviations; most of which are just redefinitions of already well known CSS properties.  &lt;/p&gt;

&lt;p&gt;Worse still, when they're not redefinitions, they can become downright &lt;em&gt;cryptic&lt;/em&gt;. Tailwind prefers to use prefixed class names instead of media queries.  Here's an example from &lt;a href="https://www.aleksandrhovhannisyan.com/blog/why-i-dont-like-tailwind-css/#1-tailwind-makes-your-code-difficult-to-read" rel="noopener noreferrer"&gt;Aleksandr Hovhannisyan&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So this in Tailwind:&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;div&lt;/span&gt;
  &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"w-16 h-16 rounded text-white bg-black py-1 px-2 m-1 text-sm md:w-32 md:h-32 md:rounded-md md:text-base lg:w-48 lg:h-48 lg:rounded-lg lg:text-lg"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  Yikes.
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;could be expressed as:&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;style&amp;gt;&lt;/span&gt;
&lt;span class="nc"&gt;.thing&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;16px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&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;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;white&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="no"&gt;black&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;0.25rem&lt;/span&gt; &lt;span class="m"&gt;0.5rem&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.25rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.25rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.875rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;line-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.25rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="n"&gt;screen&lt;/span&gt; &lt;span class="n"&gt;and&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;768px&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.thing&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;32px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;32px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.375rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;line-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.5rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="n"&gt;screen&lt;/span&gt; &lt;span class="n"&gt;and&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1024px&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.thing&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;48px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;48px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.5rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.125rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;line-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.75rem&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="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"thing"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Yikes.&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, the first example, I grant, is an awful lot less code to write, but look at how the second example is &lt;em&gt;explictly&lt;/em&gt; defining height and width at specific breakpoints.  &lt;/p&gt;

&lt;p&gt;It is verbose - as raw CSS usually happens to be, but there are other solutions - such as Sass/SCSS, or solutions such as Emotion, Styled Components, etc. which allow you to use much more terse syntax &lt;em&gt;without&lt;/em&gt; losing the cohesive meaning behind it. &lt;/p&gt;

&lt;p&gt;Again, this is programmer 101. It's why senior developers get on junior developers for naming variables "const h = 10" instead of "const height = 10" &lt;/p&gt;

&lt;p&gt;Another reason why the latter is easier to read than the former - Tailwind's classes are arranged horizontally, while the CSS is written vertically.  The wider text is, the harder it is for a reader's eyes to jump to the next line, and the harder it is to find the one particular word you're looking for in a wall of horizontal text. &lt;/p&gt;

&lt;p&gt;I bet your eyes started glazing over the second you saw the horizontal scroll bar on that Tailwind code sample, didn't they?&lt;/p&gt;

&lt;h2&gt;
  
  
  You lose a lot of the features built into standard CSS
&lt;/h2&gt;

&lt;p&gt;I won't harp on this too much, but it should be pointed out that because Tailwind doesn't allow you to use the power of many of CSS's basic features.  You can't chain selectors together, like so:&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;.foo&lt;/span&gt;&lt;span class="nd"&gt;:focus&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
&lt;span class="nc"&gt;.foo&lt;/span&gt;&lt;span class="nd"&gt;:active&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
&lt;span class="nc"&gt;.foo&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* css code */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can't use combinators.&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;.foo&lt;/span&gt; &lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* all p that are decendants of a .foo */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.foo&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* all p that are direct children of a .foo */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.foo&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* all p that are directly -after- a .foo */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.foo&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt; &lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* all p that are siblings of a .foo */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  It solves a problem that doesn't exist.
&lt;/h2&gt;

&lt;p&gt;One of the craziest things is that there's an obvious limitation to Tailwind's utility-class paradigm. What happens if you want to group related styles together?  Rarely is "display:flex;" used without "justify-content: {value}", for example. CSS allows you to group these styles together into (wait for it), &lt;em&gt;classes&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;There's a tool for grouping related Tailwind classes together too.  It's called &lt;a class="mentioned-user" href="https://dev.to/apply"&gt;@apply&lt;/a&gt;.  It's special, non-standard syntax that goes in your CSS file (a directive) and allows you to string together a collection of tailwind classes and place them all under one class name.  &lt;/p&gt;

&lt;p&gt;That is to say, completely defeating the purpose behind the utility-class paradigm.  If you end up having to use &lt;a class="mentioned-user" href="https://dev.to/apply"&gt;@apply&lt;/a&gt;, then *why don't you just use normal, ordinary, conventional CSS, which is easier to read, understand, modify, and doesn't require special tooling or parsing. CSS syntax can be complex, but it's been pretty stable since the late 90s, and isn't going to radically change anytime soon.  &lt;/p&gt;

&lt;p&gt;There's a very simple mental experiment I'd like to conduct with you. &lt;/p&gt;

&lt;p&gt;Imagine a world in which CSS was never developed, but something akin to Tailwind was. That is, webpages could only be styled through repeating these individual class names... presumably through using table tags for layout. (To give you an idea of how old I am, I used to code web pages as a summer job in my junior year of high school in 1996 - and we used a LOT of table tags.) &lt;/p&gt;

&lt;p&gt;If you could go from the limitations of Tailwind &lt;em&gt;to&lt;/em&gt; CSS, wouldn't you consider that a &lt;em&gt;quantum leap&lt;/em&gt; forward?  &lt;em&gt;Expressive syntax! Semantic naming! Style grouping! Selectors and combinators!&lt;/em&gt;. It would be like moving from Assembly to C for the first time. If so, why are we considering replacing CSS with something that does less, is more complex, creates bad quality codebases, and possibly ends up with massive vendor-lock in down the line?  &lt;/p&gt;

&lt;h2&gt;
  
  
  If you want better than CSS, there are &lt;em&gt;already&lt;/em&gt; solutions.
&lt;/h2&gt;

&lt;p&gt;So a lot of the hype around Tailwind is that you can get rid of CSS.  I know, everyone knows CSS can be hard to work with - especially if you have legacy codebases where the CSS wasn't written that well. &lt;/p&gt;

&lt;p&gt;But for the most part, there &lt;em&gt;are&lt;/em&gt; other, better improvements on CSS that &lt;em&gt;actually do&lt;/em&gt; make styling simpler.  There's the various CSS-in-JS solutions that allow you to leverage the power of Javascript to create dynamic class definitions; there's preprocessers such as Sass/SCSS/LESS; there's linters like Stylelint; there's best-practices methods like BEM/SMACSS. Is there overhead in learning these technologies?  Yes.  Is there tooling that needs to be part of your build chain?  Yes.  But unlike Tailwind, all of these solutions &lt;em&gt;actively provide a tangible benefit to your code&lt;/em&gt; -- which is something that Tailwind can't claim. &lt;/p&gt;

&lt;h2&gt;
  
  
  It literally provides no value, and tons of problems.
&lt;/h2&gt;

&lt;p&gt;At the end of the day, what do you get for all these problems?  What are you left with?  You're basically left with a less readable, more complex version of inline styles, a coding technique that we've been trying to breed out of junior developers for the past decade or so.  &lt;/p&gt;

&lt;p&gt;If you adopt Tailwind, it's going to provide problems for you and your team for years to come, and it's going to be hard to remove it. &lt;/p&gt;




&lt;p&gt;Updates based on the comments section. &lt;/p&gt;

&lt;p&gt;A few notes based on responses from the comments section. &lt;/p&gt;

&lt;h3&gt;
  
  
  Why trash something if you don't like it?
&lt;/h3&gt;

&lt;p&gt;It's important to write about bad frameworks as much as it is to write about good ones, because of two reasons.&lt;/p&gt;

&lt;p&gt;First, is the John Stewart Mill argument of "the value of the wrongful idea" - that in making a (good faith) argument for something incorrect, one arrives at a more correct, more complete view by analysis and refutation. Ideas must be continually challenged lest they go stale. Indeed - "one who doesn't understand one's opponent's arguments does not understand one's own" is a maxim I try to apply. When I wrote this article, I tried to look for the good in Tailwind. Why do people like it? (They don't have to write css. They can put style info in their HTML. They can write terser code. It gives them power to do things they don't know how to do in css.) Once I knew why people liked it, I had a much better understanding of why I didn't. (It combines content and presentation. It makes things harder to maintain. The syntax is obscure. You lose the power to do things that you can do in css.)&lt;/p&gt;

&lt;p&gt;Second is that someone down the line is going to think: Hmm, should I add Tailwind to my app that has to be maintained by my team? And they're going to google "pros and cons of TailwindCSS". There will be plenty of articles explaining the pros. Here's one explaining the cons. Hopefully I've made a compelling argument not to use Tailwind so that future developers won't have to deal with it.&lt;/p&gt;

&lt;h3&gt;
  
  
  You're being disrespectful to the people who like Tailwind.
&lt;/h3&gt;

&lt;p&gt;This isn't New Orleans Jazz.&lt;/p&gt;

&lt;p&gt;I don't like New Orleans Jazz, so I don't have to listen to it. I don't buy New Orleans Jazz albums.&lt;/p&gt;

&lt;p&gt;I am not in the habit of making detailed criticisms of what I feel to be the music compositional problems of New Orleans Jazz.&lt;/p&gt;

&lt;p&gt;But I have never had a team lead, product owner, or stakeholder come up to me and say: "For the next project, I'm thinking that everyone on the team has to learn how to appreciate and play New Orleans Jazz." &lt;/p&gt;

&lt;p&gt;Engineers and developers are often required to work with technology that they not only don't like, but which makes their work harder - often because decision makers either didn't care about the software's tradeoffs, or didn't know. Can't do much about the former, but we can do things about the latter. &lt;/p&gt;

&lt;p&gt;When team leaders are thinking about incorporating a new technology into their tech stack, they should look for blog posts like this one to help them evaluate whether or not it's worth a try.&lt;/p&gt;

&lt;p&gt;My thesis is not, as you seem to think, "I don't like Tailwind, and therefore YOU shouldn't like Tailwind either". That's a 12 year old's viewpoint of technology criticism.&lt;/p&gt;

&lt;p&gt;Rather my thesis is: "If you choose Tailwind for a mission critical application, you will end up making your job harder, your application more brittle, and your team, in the long-term, will suffer."&lt;/p&gt;

&lt;h3&gt;
  
  
  But CSS has massive problems!
&lt;/h3&gt;

&lt;p&gt;It really does. And there are better solutions than plain CSS. But Tailwind isn't one of them. &lt;/p&gt;

&lt;p&gt;Say that in the 1990s, the only way to build a house was to bang nails in with a flat rock (CSS). And then, around the mid 2000s, a really smart guy invented "the hammer." (SCSS) It took adjusting, and you have to learn a new tool, but it did the job much better.&lt;/p&gt;

&lt;p&gt;Around the early to mid 2010s, another guy invented the nail gun (CSS-in-JS). It did a lot of the same stuff as a hammer, but you had to know how to use it. There were tradeoffs, but generally, people who chose to work with hammers or with nail-guns usually ended up okay. Many peoplee would often use a manual hammer when the manual hammer seemed appropriate, and the nail gun when they seemed to need it. And all was good in the world of carpentry.&lt;/p&gt;

&lt;p&gt;Then in 2017, someone came up to the carpenters and said: "Hey, see what happens when I do this!" and starts hammering in nails with the butt end of a loaded revolver (Tailwind).&lt;/p&gt;

&lt;p&gt;And it's supporters quickly point out how more effective it is at building houses than banging in rocks. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"But it's a loaded gun. It might go off and shoot someone"&lt;br&gt;
   "Hasn't happened to me yet."&lt;br&gt;
   "Why don't you use a hammer? Or a nail gun?"&lt;br&gt;
   "I don't like hammers or nail guns."&lt;br&gt;
   "I can understand why you might not, but even if you used a rock, that would be safer in the long run."&lt;br&gt;
   "But using a rock is so difficult and inefficient."&lt;br&gt;
   "I'm not saying to use a rock. I'm saying that the hammer already solves the problems you have with the rock, but even the rock is a better tool for this than a loaded gun because it won't shoot anyone."&lt;br&gt;
   "But I love my gun." &lt;br&gt;
   "I guess it's alright if you use your gun on smaller projects on your own property, but..."&lt;br&gt;
   "Nope, I'm the foreman. Everyone on the site is using loaded guns from now on, because they're awesome." &lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;Update: 9 May 2021 - Check out &lt;a href="https://dev.to/neophen/tailwind-is-bad-because-i-don-t-like-it-24eh"&gt;this blog post by Mykolas Mankevicius&lt;/a&gt; which attempts to rebut this article. I disagree, of course, but I think it adds to the debate, and if you're reading this deciding whether to use tailwind or not, you should hear what the "other side" of this issue has to say.  &lt;/p&gt;

&lt;p&gt;Agree but think my writing style might be too abrasive?  Check out &lt;a href="https://dev.to/benface/tailwind-css-might-not-be-for-you-jk0"&gt;Benoît Rouleau's take on this article&lt;/a&gt; entitled &lt;a href="https://dev.to/benface/tailwind-css-might-not-be-for-you-jk0"&gt;Tailwind CSS might not be for you&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/cher"&gt;Cher&lt;/a&gt; writes about some of the response this article has gotten and how it relates to our own unconcious bias in &lt;a href="https://dev.to/cher/sexism-racism-toxic-positivity-and-tailwindcss-cil"&gt;"Sexism, Racism, Toxic Positivity, and TailwindCSS"&lt;/a&gt;&lt;/p&gt;

</description>
      <category>tailwindcss</category>
      <category>javascript</category>
    </item>
    <item>
      <title>This is a test post</title>
      <dc:creator>Kerry Boyko</dc:creator>
      <pubDate>Mon, 13 Jan 2020 20:18:27 +0000</pubDate>
      <link>https://dev.to/brianboyko/this-is-a-test-post-4c1e</link>
      <guid>https://dev.to/brianboyko/this-is-a-test-post-4c1e</guid>
      <description>&lt;p&gt;I'm going to be frank. This is a test post. I just want to know if I can redirect my domain, &lt;a href="http://www.frontendgineer.com"&gt;www.frontendgineer.com&lt;/a&gt;, here. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0UGLdn0K--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/1pltvm97aamm0ywkqyai.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0UGLdn0K--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/1pltvm97aamm0ywkqyai.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>testpost</category>
    </item>
  </channel>
</rss>
