<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[The Frontier]]></title><description><![CDATA[Welcome to The Frontier. Where I blog about the latest technologies and practices around Web Development, React, Typescript, and Web3.]]></description><link>https://blog.samdaryl.dev</link><generator>RSS for Node</generator><lastBuildDate>Fri, 17 Apr 2026 18:19:31 GMT</lastBuildDate><atom:link href="https://blog.samdaryl.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Create Beautiful Banners and Other Graphics Easily Using HTML and CSS - Examples]]></title><description><![CDATA[Introduction
I previously posted about using HTML and CSS to create banner images on the fly without the use of any tooling other than chrome.
Create Beautiful Banners and Other Graphics Easily Using HTML and CSS
It seemed to garner a fair amount of ...]]></description><link>https://blog.samdaryl.dev/create-beautiful-banners-and-other-graphics-easily-using-html-and-css-examples</link><guid isPermaLink="true">https://blog.samdaryl.dev/create-beautiful-banners-and-other-graphics-easily-using-html-and-css-examples</guid><category><![CDATA[4articles4weeks]]></category><category><![CDATA[#week4]]></category><category><![CDATA[HTML5]]></category><category><![CDATA[CSS]]></category><category><![CDATA[CSS3]]></category><dc:creator><![CDATA[Sam Phillips]]></dc:creator><pubDate>Mon, 05 Sep 2022 16:20:55 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1662394471250/ynZwE89do.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-introduction">Introduction</h1>
<p>I previously posted about using HTML and CSS to create banner images on the fly without the use of any tooling other than chrome.</p>
<p><a target="_blank" href="https://blog.samdaryl.dev/create-beautiful-banners-and-other-graphics-easily-using-html-and-css">Create Beautiful Banners and Other Graphics Easily Using HTML and CSS</a></p>
<p>It seemed to garner a fair amount of interest, so I thought I would extend it with some base examples of banners I have used in the past.</p>
<blockquote>
<p>All examples are set to 1600x840 as that is the recommended resolution for cover images on hashnode, all examples can be tweaked to your preferences easily.</p>
</blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1662367835737/ecLpe9n2i.webp" alt="Behold" class="image--center mx-auto" /></p>
<h1 id="heading-simple-gradient-banner">Simple Gradient Banner</h1>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1662384067613/YUcO3ThRw.png" alt="Simple Gradient Banner" class="image--center mx-auto" /></p>
<p>Slightly more in depth than the original article, but the same simple principle 👍</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">http-equiv</span>=<span class="hljs-string">"X-UA-Compatible"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"IE=edge"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>My Banner<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="css">
            <span class="hljs-comment">/* Perform the ritual sacrifice to the gods of W3C */</span>
            *, *<span class="hljs-selector-pseudo">::before</span>, *<span class="hljs-selector-pseudo">::after</span> {
                <span class="hljs-attribute">box-sizing</span>: border-box;
            }

            <span class="hljs-selector-class">.banner</span> {
                <span class="hljs-comment">/* Desired width */</span>
                <span class="hljs-attribute">width</span>: <span class="hljs-number">1600px</span>;

                <span class="hljs-comment">/* Desired height */</span>
                <span class="hljs-attribute">height</span>: <span class="hljs-number">840px</span>;

                <span class="hljs-comment">/* A nice looking gradient at a 45deg angle because i'm edgy */</span>
                <span class="hljs-attribute">background</span>: <span class="hljs-built_in">linear-gradient</span>(<span class="hljs-number">45deg</span>, #<span class="hljs-number">12</span>c2e9, #c471ed, #f64f59);

                <span class="hljs-comment">/* White text seems appropriate */</span>
                <span class="hljs-attribute">color</span>: white;

                <span class="hljs-comment">/* Some padding to help text wrap nicely */</span>
                <span class="hljs-attribute">padding</span>: <span class="hljs-number">5rem</span>;

                <span class="hljs-comment">/* Chrome supports Segoe UI out of the box and it's usually good enough for banners */</span>
                <span class="hljs-comment">/* Easy to import a custom font though! */</span>
                <span class="hljs-attribute">font-family</span>: Segoe UI;

                <span class="hljs-comment">/* And finally just use flex-box to center the text vertically */</span>
                <span class="hljs-attribute">display</span>: flex;
                <span class="hljs-attribute">justify-content</span>: center;
                <span class="hljs-attribute">align-items</span>: center;
            }

            <span class="hljs-selector-class">.text</span> {
                <span class="hljs-comment">/* Center the text horizonally too */</span>
                <span class="hljs-attribute">text-align</span>: center;

                <span class="hljs-comment">/* Font size set to whatever looks best */</span>
                <span class="hljs-attribute">font-size</span>: <span class="hljs-number">80px</span>;
            }
        </span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>  <span class="hljs-attr">class</span>=<span class="hljs-string">"banner"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text"</span>&gt;</span>Create <span class="hljs-tag">&lt;<span class="hljs-name">strong</span>&gt;</span>Beautiful<span class="hljs-tag">&lt;/<span class="hljs-name">strong</span>&gt;</span> Banners and Other <span class="hljs-tag">&lt;<span class="hljs-name">strong</span>&gt;</span>Graphics<span class="hljs-tag">&lt;/<span class="hljs-name">strong</span>&gt;</span> Easily Using <span class="hljs-tag">&lt;<span class="hljs-name">strong</span>&gt;</span>HTML<span class="hljs-tag">&lt;/<span class="hljs-name">strong</span>&gt;</span> and <span class="hljs-tag">&lt;<span class="hljs-name">strong</span>&gt;</span>CSS<span class="hljs-tag">&lt;/<span class="hljs-name">strong</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<h1 id="heading-3d-transform-banner">3D Transform Banner</h1>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1662387176501/qrzCNRGA7.png" alt="3D Transform Banner" class="image--center mx-auto" /></p>
<p>Using the power of <code>transform</code> to rotate a <code>div</code> on the <code>x</code> and <code>y</code> axis looks really nice when combined with the <code>perspective</code> function and can create real depth. This example uses the same gradient as before, but you can do what you like! Throw in a background image, and it can look amazing!</p>
<blockquote>
<p>If you use React, check out <a target="_blank" href="https://blog.samdaryl.dev/create-beautiful-3d-perspective-images-easily-using-react-and-css">Create Beautiful 3D Perspective Images Easily Using React and CSS</a> to really have some fun with perspective transforms!</p>
</blockquote>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">http-equiv</span>=<span class="hljs-string">"X-UA-Compatible"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"IE=edge"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>My Banner<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="css">
            *, *<span class="hljs-selector-pseudo">::before</span>, *<span class="hljs-selector-pseudo">::after</span> {
                <span class="hljs-attribute">box-sizing</span>: border-box;
            }

            <span class="hljs-selector-class">.container</span> {
                <span class="hljs-attribute">width</span>: <span class="hljs-number">1600px</span>;
                <span class="hljs-attribute">height</span>: <span class="hljs-number">840px</span>;
                <span class="hljs-attribute">display</span>: flex;
                <span class="hljs-attribute">justify-content</span>: center;
                <span class="hljs-attribute">align-items</span>: center;
            }

            <span class="hljs-selector-class">.banner</span> {
                <span class="hljs-comment">/* Whatever width and height seems good for the card within the banner space */</span>
                <span class="hljs-attribute">width</span>: <span class="hljs-number">1200px</span>;
                <span class="hljs-attribute">height</span>: <span class="hljs-number">680px</span>;
                <span class="hljs-attribute">background</span>: <span class="hljs-built_in">linear-gradient</span>(<span class="hljs-number">45deg</span>, #<span class="hljs-number">12</span>c2e9, #c471ed, #f64f59);
                <span class="hljs-attribute">color</span>: white;
                <span class="hljs-attribute">padding</span>: <span class="hljs-number">5rem</span>;
                <span class="hljs-attribute">font-family</span>: Segoe UI;

                <span class="hljs-attribute">display</span>: flex;
                <span class="hljs-attribute">justify-content</span>: center;
                <span class="hljs-attribute">align-items</span>: center;

                <span class="hljs-comment">/* Perspective magic */</span>
                <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">perspective</span>(<span class="hljs-number">1000px</span>) <span class="hljs-built_in">rotateX</span>(<span class="hljs-number">10deg</span>) <span class="hljs-built_in">rotateY</span>(-<span class="hljs-number">10deg</span>) <span class="hljs-built_in">scale3d</span>(<span class="hljs-number">1</span>,<span class="hljs-number">1</span>,<span class="hljs-number">1</span>);

                <span class="hljs-comment">/* Make it pretty */</span>
                <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">18px</span>;
                <span class="hljs-attribute">box-shadow</span>: <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.07</span>) <span class="hljs-number">0px</span> <span class="hljs-number">1px</span> <span class="hljs-number">2px</span>, <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.07</span>) <span class="hljs-number">0px</span> <span class="hljs-number">2px</span> <span class="hljs-number">4px</span>, <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.07</span>) <span class="hljs-number">0px</span> <span class="hljs-number">4px</span> <span class="hljs-number">8px</span>, <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.07</span>) <span class="hljs-number">0px</span> <span class="hljs-number">8px</span> <span class="hljs-number">16px</span>, <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.07</span>) <span class="hljs-number">0px</span> <span class="hljs-number">16px</span> <span class="hljs-number">32px</span>, <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.07</span>) <span class="hljs-number">0px</span> <span class="hljs-number">32px</span> <span class="hljs-number">64px</span>;

                <span class="hljs-comment">/* Perspective transform can offset the element, this is just to move it back to a more centered origin */</span>
                <span class="hljs-attribute">position</span>: relative;
                <span class="hljs-attribute">left</span>: -<span class="hljs-number">60px</span>;
            }

            <span class="hljs-selector-class">.text</span> {
                <span class="hljs-comment">/* Center the text horizonally too */</span>
                <span class="hljs-attribute">text-align</span>: center;

                <span class="hljs-comment">/* Font size set to whatever looks best */</span>
                <span class="hljs-attribute">font-size</span>: <span class="hljs-number">60px</span>;
            }
        </span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span>  <span class="hljs-attr">class</span>=<span class="hljs-string">"banner"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text"</span>&gt;</span>Create <span class="hljs-tag">&lt;<span class="hljs-name">strong</span>&gt;</span>Beautiful<span class="hljs-tag">&lt;/<span class="hljs-name">strong</span>&gt;</span> Banners and Other <span class="hljs-tag">&lt;<span class="hljs-name">strong</span>&gt;</span>Graphics<span class="hljs-tag">&lt;/<span class="hljs-name">strong</span>&gt;</span> Easily Using <span class="hljs-tag">&lt;<span class="hljs-name">strong</span>&gt;</span>HTML<span class="hljs-tag">&lt;/<span class="hljs-name">strong</span>&gt;</span> and <span class="hljs-tag">&lt;<span class="hljs-name">strong</span>&gt;</span>CSS<span class="hljs-tag">&lt;/<span class="hljs-name">strong</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<h1 id="heading-gradient-glow-banner">Gradient Glow Banner</h1>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1662388300209/I8dU64u80.png" alt="Gradient Glow Banner" class="image--center mx-auto" /></p>
<p>Using <code>::before</code> on the same element, we can use <code>blur</code> filter in CSS to create a glow effect behind the card with the same gradient background! 👍</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">http-equiv</span>=<span class="hljs-string">"X-UA-Compatible"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"IE=edge"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>My Banner<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="css">
            *, *<span class="hljs-selector-pseudo">::before</span>, *<span class="hljs-selector-pseudo">::after</span> {
                <span class="hljs-attribute">box-sizing</span>: border-box;
            }

            <span class="hljs-selector-class">.container</span> {
                <span class="hljs-attribute">width</span>: <span class="hljs-number">1600px</span>;
                <span class="hljs-attribute">height</span>: <span class="hljs-number">840px</span>;
                <span class="hljs-attribute">display</span>: flex;

                <span class="hljs-comment">/* A little padding to make sure the glow is not occluded */</span>
                <span class="hljs-attribute">padding</span>: <span class="hljs-number">30px</span>;
            }

            <span class="hljs-selector-class">.banner</span> {
                <span class="hljs-comment">/* Whatever width and height seems good for the card within the banner space */</span>
                <span class="hljs-attribute">flex</span>: <span class="hljs-number">1</span> <span class="hljs-number">1</span> auto;
                <span class="hljs-attribute">background</span>: <span class="hljs-built_in">linear-gradient</span>(<span class="hljs-number">45deg</span>,#<span class="hljs-number">0575</span>e6,#<span class="hljs-number">00</span>f260);
                <span class="hljs-attribute">color</span>: white;
                <span class="hljs-attribute">padding</span>: <span class="hljs-number">5rem</span>;
                <span class="hljs-attribute">font-family</span>: Segoe UI;

                <span class="hljs-attribute">display</span>: flex;
                <span class="hljs-attribute">justify-content</span>: center;
                <span class="hljs-attribute">align-items</span>: center;

                <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">18px</span>;

                <span class="hljs-comment">/* Explicitly specify relative position so glow::before binds to it as an absolute pseudo element */</span>
                <span class="hljs-attribute">position</span>: relative;
            }

            <span class="hljs-selector-class">.glow</span><span class="hljs-selector-pseudo">::before</span> {
                <span class="hljs-attribute">content</span>: <span class="hljs-string">""</span>;
                <span class="hljs-attribute">position</span>: absolute;
                <span class="hljs-attribute">height</span>: <span class="hljs-number">100%</span>;
                <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
                <span class="hljs-attribute">background</span>: <span class="hljs-built_in">linear-gradient</span>(<span class="hljs-number">45deg</span>,#<span class="hljs-number">0575</span>e6,#<span class="hljs-number">00</span>f260);
                <span class="hljs-attribute">z-index</span>: -<span class="hljs-number">1</span>;
                <span class="hljs-attribute">filter</span>: <span class="hljs-built_in">blur</span>(<span class="hljs-number">20px</span>);
            }

            <span class="hljs-selector-class">.text</span> {
                <span class="hljs-attribute">text-align</span>: center;
                <span class="hljs-attribute">font-size</span>: <span class="hljs-number">70px</span>;
            }
        </span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span>  <span class="hljs-attr">class</span>=<span class="hljs-string">"banner glow"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text"</span>&gt;</span>Create <span class="hljs-tag">&lt;<span class="hljs-name">strong</span>&gt;</span>Beautiful<span class="hljs-tag">&lt;/<span class="hljs-name">strong</span>&gt;</span> Banners and Other <span class="hljs-tag">&lt;<span class="hljs-name">strong</span>&gt;</span>Graphics<span class="hljs-tag">&lt;/<span class="hljs-name">strong</span>&gt;</span> Easily Using <span class="hljs-tag">&lt;<span class="hljs-name">strong</span>&gt;</span>HTML<span class="hljs-tag">&lt;/<span class="hljs-name">strong</span>&gt;</span> and <span class="hljs-tag">&lt;<span class="hljs-name">strong</span>&gt;</span>CSS<span class="hljs-tag">&lt;/<span class="hljs-name">strong</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<h1 id="heading-gradient-blend-mode-banner">Gradient Blend Mode Banner</h1>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1662393637766/mrBLvsYAr.png" alt="Gradient Blend Mode Banner" class="image--center mx-auto" /></p>
<p>This follows on from the glow effect, and extends it to show a white background for the content and uses <code>mix-blend-mode</code> as a mask to show the gradient in the text itself!</p>
<p>This could probably be simplified, but considering it's just a simple banner to generate an image from, it's of little consequence.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">http-equiv</span>=<span class="hljs-string">"X-UA-Compatible"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"IE=edge"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>My Banner<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="css">
            *, *<span class="hljs-selector-pseudo">::before</span>, *<span class="hljs-selector-pseudo">::after</span> {
                <span class="hljs-attribute">box-sizing</span>: border-box;
            }

            <span class="hljs-selector-class">.container</span> {
                <span class="hljs-attribute">width</span>: <span class="hljs-number">1600px</span>;
                <span class="hljs-attribute">height</span>: <span class="hljs-number">840px</span>;
                <span class="hljs-attribute">display</span>: flex;

                <span class="hljs-comment">/* A little padding to make sure the glow is not occluded */</span>
                <span class="hljs-attribute">padding</span>: <span class="hljs-number">50px</span>;
            }

            <span class="hljs-selector-class">.banner</span> {
                <span class="hljs-comment">/* Whatever width and height seems good for the card within the banner space */</span>
                <span class="hljs-attribute">flex</span>: <span class="hljs-number">1</span> <span class="hljs-number">1</span> auto;
                <span class="hljs-attribute">background</span>: <span class="hljs-built_in">linear-gradient</span>(<span class="hljs-number">45deg</span>, #eea2a2 <span class="hljs-number">0%</span>, #bbc1bf <span class="hljs-number">19%</span>, #<span class="hljs-number">57</span>c6e1 <span class="hljs-number">42%</span>, #b49fda <span class="hljs-number">79%</span>, #<span class="hljs-number">7</span>ac5d8 <span class="hljs-number">100%</span>);
                <span class="hljs-comment">/* color: white; */</span>
                <span class="hljs-attribute">font-family</span>: Segoe UI;

                <span class="hljs-attribute">display</span>: flex;
                <span class="hljs-attribute">justify-content</span>: center;
                <span class="hljs-attribute">align-items</span>: center;

                <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">18px</span>;

                <span class="hljs-comment">/* Explicitly specify relative position so glow::before binds to it as an absolute pseudo element */</span>
                <span class="hljs-comment">/* Also for the absolute text element */</span>
                <span class="hljs-attribute">position</span>: relative;
            }

            <span class="hljs-selector-class">.glow</span><span class="hljs-selector-pseudo">::before</span> {
                <span class="hljs-attribute">content</span>: <span class="hljs-string">""</span>;
                <span class="hljs-attribute">position</span>: absolute;
                <span class="hljs-attribute">height</span>: <span class="hljs-number">100%</span>;
                <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
                <span class="hljs-attribute">background</span>: <span class="hljs-built_in">linear-gradient</span>(<span class="hljs-number">45deg</span>, #eea2a2 <span class="hljs-number">0%</span>, #bbc1bf <span class="hljs-number">19%</span>, #<span class="hljs-number">57</span>c6e1 <span class="hljs-number">42%</span>, #b49fda <span class="hljs-number">79%</span>, #<span class="hljs-number">7</span>ac5d8 <span class="hljs-number">100%</span>);
                <span class="hljs-attribute">z-index</span>: -<span class="hljs-number">1</span>;
                <span class="hljs-attribute">filter</span>: <span class="hljs-built_in">blur</span>(<span class="hljs-number">20px</span>);
            }

            <span class="hljs-selector-class">.text</span> {
                <span class="hljs-attribute">display</span>: flex;
                <span class="hljs-attribute">align-items</span>: center;
                <span class="hljs-attribute">text-align</span>: center;

                <span class="hljs-attribute">font-size</span>: <span class="hljs-number">80px</span>;

                <span class="hljs-comment">/* Set the text element to fill its containers space */</span>
                <span class="hljs-attribute">position</span>: absolute;
                <span class="hljs-attribute">inset</span>: <span class="hljs-number">0</span>;

                <span class="hljs-comment">/* Set the same border-radius as the container, overflow may cause issues */</span>
                <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">18px</span>;

                <span class="hljs-comment">/* Set the background color of the text element to hide the gradient background of .banner */</span>
                <span class="hljs-attribute">background-color</span>: white;

                <span class="hljs-comment">/* Set the color to black and then mix-blend-mode to lighten it to the background gradients color */</span>
                <span class="hljs-attribute">color</span>: black;
                <span class="hljs-attribute">mix-blend-mode</span>: lighten;
            }
        </span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span>  <span class="hljs-attr">class</span>=<span class="hljs-string">"banner glow"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>Create <span class="hljs-tag">&lt;<span class="hljs-name">strong</span>&gt;</span>Beautiful<span class="hljs-tag">&lt;/<span class="hljs-name">strong</span>&gt;</span> Banners and Other <span class="hljs-tag">&lt;<span class="hljs-name">strong</span>&gt;</span>Graphics<span class="hljs-tag">&lt;/<span class="hljs-name">strong</span>&gt;</span> Easily Using <span class="hljs-tag">&lt;<span class="hljs-name">strong</span>&gt;</span>HTML<span class="hljs-tag">&lt;/<span class="hljs-name">strong</span>&gt;</span> and <span class="hljs-tag">&lt;<span class="hljs-name">strong</span>&gt;</span>CSS<span class="hljs-tag">&lt;/<span class="hljs-name">strong</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<h1 id="heading-conclusion">Conclusion</h1>
<p>That's it for now! I'll most likely keep adding to this article in the future with some more examples as I create more for my own use cases.</p>
<p>Follow me on <a target="_blank" href="https://twitter.com/SamDarylDev">Twitter</a> to keep up to date with my projects and get notified of new articles like this in the future!</p>
]]></content:encoded></item><item><title><![CDATA[The Best Tool to Accelerate Your Career as a Software Engineer]]></title><description><![CDATA[Introduction
I left university at 23 years old, and got my first job for that same university earning around £23k a year, I have been in full time employment ever since and by the age of 29, was earning over £90k. In the US, that would be graduate sa...]]></description><link>https://blog.samdaryl.dev/the-best-tool-to-accelerate-your-career-as-a-software-engineer</link><guid isPermaLink="true">https://blog.samdaryl.dev/the-best-tool-to-accelerate-your-career-as-a-software-engineer</guid><category><![CDATA[software development]]></category><category><![CDATA[Software Engineering]]></category><category><![CDATA[Career]]></category><category><![CDATA[4articles4weeks]]></category><category><![CDATA[#week2]]></category><dc:creator><![CDATA[Sam Phillips]]></dc:creator><pubDate>Thu, 25 Aug 2022 17:55:17 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1661448038701/JQQk-AR-q.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-introduction">Introduction</h1>
<p>I left university at 23 years old, and got my first job for that same university earning around £23k a year, I have been in full time employment ever since and by the age of 29, was earning over £90k. In the US, that would be graduate salary to 6 figures in 6 years!</p>
<p>I attribute this success to one thing and one thing only, my brain.</p>
<p>(I know that sounds pretentious, but trust me, please keep reading).</p>
<p>I was initially attracted to quick hacks, got sucked into a cycle of trying to make my way through my career, choosing the fasted path to success. The key takeaway I internalized from reading posts like “Move fast to get paid more, the secret to getting a raise as a software engineer”, was to get a different job within 2 years to get your pay increases faster. I applied to many roles that paid more money, went to interviews, and got offered jobs. The only problem with this was that the money they offered was about the same as I was paid now, or I was simply rejected.</p>
<p>I began to realize that the issue wasn't the process, it was me. What I had read and learnt wasn't working. The advice I had taken to heart was probably not good advice.</p>
<p>In this article, I offer my thoughts on what I think can craft a path to success in the shortest time possible, without relying on luck, or anything else other than yourself.</p>
<h1 id="heading-quick-hacks-never-work">Quick hacks never work</h1>
<p>The internet and social media is full of quick hacks, “this one tool can save you time, make you money, get you a job” (okay maybe that last one might help).</p>
<p>People selling guides and courses on how to get rich quick, mastering drop-shipping, etc. These are all things that can be very attractive to software engineers, as there is always the thought in our heads that we could automate that with software. It is true that these processes can be automated, the issue is the processes themselves don't work in the way they advertise.</p>
<p>Courses to master a particular aspect of software development are fine, courses that are created by academic institutions for the purpose of learning are great (Stanford University has a free machine learning course, and it is amazing)!</p>
<p>However, courses that allude to being able to master anything in a short period of time, will probably be too good to be true.</p>
<p>Software boot camps can be great, but the surrounding marketing is very misleading. They focus their messaging around getting you a job very quickly, but miss out the part that they only teach you exactly what you need to get through the door. You will have to learn the fundamentals, and the vast expanse of knowledge required to progress in that job long term, on the go (not that that's especially a bad thing).</p>
<h1 id="heading-take-responsibility-for-yourself">Take responsibility for yourself</h1>
<p>If there is one message you internalize from this article, let it be this one. Take responsibility for yourself. Don't blame others for your shortcomings. Not being able to get a job after getting a degree, is not the universities fault. Not being able to make a sale, is not the Udemy course on closing sales fault. Deploying a bug to production is not the CI/CD pipelines fault, or whoever reviewed the codes fault. It is unequivocally your fault, always, and that's okay!</p>
<p>If you have any habit of laying blame on anything other than yourself for things instigated by you, stop. If you even find yourself subconsciously looking for an excuse, stop. The faster you accept that something you did, didn't pan out, was because of you, the faster you can get on with learning from that mistake.</p>
<p>The better you get at identifying when you could have done better, the faster you will trigger the learning process that comes from it. Without doing this, you will never trigger the learning process, and will never improve.</p>
<h1 id="heading-the-art-of-compounding-knowledge">The art of compounding knowledge</h1>
<p>Just like investment profits that is re-invested into a fund. Experience, and knowledge, compounds over time. It can be hard to explain this, but I will give it a shot.</p>
<p>A lot of knowledge acquisition is driven by the desire to gain that knowledge. When you get stuck during a learning process, you will often get unmotivated, and procrastinate on continuing to learn it. This is simply human nature, and eventually if you are determined, you will pick it back up and push through the hard parts.</p>
<p>Now, let's imagine you want to get better at maths. You are working through a course, but end up dropping it halfway through due to some problem you can't figure out. You start a different course that focuses on other aspects of maths, you hit a similar issue and get demotivated and move on to yet another course. The third course explains a concept that can be used to solve the problems you were stuck on in the previous courses. The light bulb moment hits, and you are immediately hit with dopamine and are suddenly super motivated to continue on with all three courses and complete them.</p>
<p>Now take this concept and apply it to all knowledge you have about everything you know. The more you know, the greater chance there is for learning something new to connect more dots. The more light bulb moments you have, the higher the chance of the next light bulb moment opening more doors.</p>
<blockquote>
<p>If you feel you have a better way of explaining what I have just explained above, please let me know, I don't think this explanation is very good 😂</p>
</blockquote>
<h1 id="heading-reduce-the-noise-when-learning">Reduce the noise when learning</h1>
<p>If you are trying to learn something, give that thing your undivided attention. Having TV on in the background whilst reading an article will distract you enough for the information to go in one ear and out the other.</p>
<p>By making a habit of focusing solely on consuming the information you need to consume, the quality of that information goes through the roof, and you will retain that information for much longer.</p>
<p>It can be very easy to get distracted in today's world, your phone is pinging you every 2 minutes with a text message, or new YouTube video recommendation. It's so easy to divert your attention from what you are reading, even just for a second. Take the time to isolate yourself from these distractions before consuming the information you want to consume.</p>
<p>If you grow tired and demotivated with what you are reading or watching, just stop, and come back to it. Having distractions can make it easier to keep going with what you are trying to consume, but by the end, will you have really consumed, and understood it? Or did you just waste your time?</p>
<h1 id="heading-learning-how-to-learn">Learning how to learn</h1>
<p>This is something that only you can answer. It's important to understand yourself, and how you learn best. If you can watch and understand everything you watch without a break for hours, but can only read a book for 5 minutes without getting distracted, you should focus on visual/auditory learning materials. If you are a bookworm but get restless watching TV, buy books on the topics you are trying to learn.</p>
<p>This may sound simple, but I have found when I really analyze my learning habits, that in some situations, there is no point in trying to learn at all, and I might as well save time and go do something I actually want to do.</p>
<p>Try to pay attention to yourself in different situations and acknowledge when you are excited, or bored, interested or demotivated. Try to analyze why you feel that way in those moments, and capitalize on what you can infer.</p>
<h1 id="heading-master-the-tools-and-skills-at-your-disposal">Master the tools and skills at your disposal</h1>
<p>Everything you do requires a skill set that you may not even think about when you do it. When you read, you use the skill of reading. When you write code, you use the skill of typing, and the toolset provided to you by your text editor.</p>
<p>I have found the speed in which I do things, like writing code, is not limited by my ability to think of what code to write, but my ability to get the code on the screen. I still get frustrated knowing what I need to implement, but can't just make it just appear and need to spend an hour getting it all typed out.</p>
<p>Did you know in VS Code, you can select multiple of the same word with <code>ctrl+d</code>? Did you know if you hold <code>ctrl+alt</code> and press <code>down arrow</code> you can create multiple cursors on multiple lines? Hell, you can do that anywhere just by holding <code>alt</code> and clicking multiple places in the code! These are just a few examples. There are literally hundreds of shortcuts that would take an implementation from hours to minutes. Extensions that provide snippets, so you don't have to write the same boilerplate of a React component ever again. Extensions that auto format your code to your specification every time you save the file. </p>
<p>You get the idea. The faster you can get through the parts where you aren't learning anything, the faster you can get to learning more (if this were a motivational speech, I would start looping back to the art of compounding knowledge, but let's crack on).</p>
<p>Getting even more granular, reading and typing is a skill that, as a software engineer, you use constantly. Have you ever thought to spend time actually honing these skills that underpin everything you do? If you could do these two things twice as fast, would you not be able to do pretty much everything twice as fast?</p>
<p>I try to assign an hour or so a week to enhancing these skills, and it turns out it can be really fun! Personally, I got really addicted to The Typing of The Dead on Steam and ended up just playing it for fun! There are lots of free typing games too!</p>
<p>Just like typing, there are lots of free and paid games and apps out there that aim to help you improve your reading speed. There are also tools to help you read faster by highlighting parts in every word. There are techniques like “Bionic Reading” and chrome extensions like SwiftRead that take alternative approaches. These really do improve reading speed and can help immensely if this is a major flaw for you, like it is for me.</p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>Your brain is the best tool you will ever have, listen to it, and use it to your advantage!</p>
<p>That's it! I hope this helps you to look at yourself, listen to yourself, and hone what's already there to accelerate your career!</p>
<p>Follow me on <a target="_blank" href="https://twitter.com/SamDarylDev">Twitter</a> to keep up to date with my projects and get notified of new articles like this in the future!</p>
]]></content:encoded></item><item><title><![CDATA[Lessons Learned From Conducting Junior Software Engineer Interviews for Small Companies]]></title><description><![CDATA[Introduction
I have worked for smaller software companies most of my career, and from what I can gather, the interview process can range from overly formal, to overly informal. Every small company is different, and generally will conduct interviews b...]]></description><link>https://blog.samdaryl.dev/lessons-learned-from-conducting-junior-software-engineer-interviews-for-small-companies</link><guid isPermaLink="true">https://blog.samdaryl.dev/lessons-learned-from-conducting-junior-software-engineer-interviews-for-small-companies</guid><category><![CDATA[4articles4weeks]]></category><category><![CDATA[week1]]></category><category><![CDATA[Interviews]]></category><category><![CDATA[Junior developer ]]></category><category><![CDATA[software development]]></category><dc:creator><![CDATA[Sam Phillips]]></dc:creator><pubDate>Thu, 18 Aug 2022 15:07:39 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1660835184806/V6HbB5d42.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-introduction">Introduction</h1>
<p>I have worked for smaller software companies most of my career, and from what I can gather, the interview process can range from overly formal, to overly informal. Every small company is different, and generally will conduct interviews based on the direct influence of whoever is actually doing the interview.</p>
<p>However, having conducted interviews for quite a few small companies, I have found amid the vastly varying criteria, there are a few common principles that usually lead to a successful hire. In this article, I will be doing my best to give you an insight into what can be the deciding factor when interviewing for a position at a small company.</p>
<h1 id="heading-why-join-a-small-company">Why join a small company?</h1>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1660839892526/jDRrrGbco.gif" alt="ceo.gif" class="image--center mx-auto" /></p>
<p>Getting a job as a software engineer can be far more fulfilling than working for a larger company, if you find the right fit.</p>
<h2 id="heading-pay-can-be-just-as-high-if-not-more">Pay can be just as high, if not more</h2>
<p>You can be paid just as much as working at a larger company, although you may have to expect a smaller wage packet to start with. Doing well in a small company is far more likely to result in immediate returns in the form of bonuses or pay rises. Whereas in a large company, there will be a far more formal policy in place to review and reward.</p>
<h2 id="heading-you-may-have-more-autonomy">You may have more autonomy</h2>
<p>Depending on the type of work the company does, you may be given a lot more autonomy. This is especially true when given greenfield projects to work on, small companies rely on you taking ownership of your work to move forward quickly.</p>
<h2 id="heading-you-will-most-likely-have-more-impact-on-the-direction-of-projects">You will most likely have more impact on the direction of projects</h2>
<p>With smaller teams, and less management and design overhead, the responsibility of where a product goes, and harvesting user feedback falls to you. This is a great opportunity to sink your teeth into other aspects of the design process by interacting directly with users.</p>
<h2 id="heading-you-may-have-more-creative-freedom">You may have more creative freedom</h2>
<p>Along with autonomy, you may find you are also free to use the technologies and languages you are comfortable with. Or at least have a stronger weight to your opinion on what technologies are best to solve this particular problem.</p>
<h1 id="heading-what-does-a-small-company-look-for-in-a-junior-engineer">What does a small company look for in a junior engineer?</h1>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1660840649013/z41gR4PK2.gif" alt="save.gif" class="image--center mx-auto" /></p>
<p>Unlike larger companies that will usually have a formalized onboarding path for you, smaller companies will most likely play it by ear. The people hiring you will not know for certain what you will need to know before hiring you, so will most likely take a more general approach when it comes to finding out how technically competent you are. You may find that they simply start conversations flowing based on your previous experience that resonates with them.</p>
<p>Technical testing will mostly be informal too, baseline questions to prove you weren't lying on your CV/resume, along with more advanced questions to test you on your claimed experience.</p>
<p>Now, this all may sound like a normal interview at any company, but I assure you a lot of is designed beforehand with a hidden underlying mission. This underlying mission will be slightly different fore every small company, and is usually curated based on experiences they have had hiring poor performing engineers, or people that ended up not being a great culture fit.</p>
<p>Junior developers have so much to learn, and are known to be sponges that can be moulded into what you need them to be. This is why, after trial and error, I found the one thing I required from a candidate when interviewing, was to be interested in learning, that's it.</p>
<p>I would take this as far that I would ask many questions covering a very broad spectrum of technologies, knowing that they couldn't be proficient in all of them. I did this not only to get a gauge of their experience, but to see if they would respond with “I don't know” or “I don't know, what's that?”. There is a massive difference between the two, and consistently asking about the topic I have brought up is what I looked for. If the candidate is eager to understand everything they come across, they are likely to grow quickly and succeed!</p>
<h1 id="heading-what-you-should-look-for-in-a-small-company">What YOU should look for in a small company</h1>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1660840431698/_6JsuHw6G.gif" alt="qualified.gif" class="image--center mx-auto" /></p>
<p>An interview is a two-way street, a double-edged sword. Just as you may not be a good fit for a company, a company may not be a good fit for you! You have to understand this and come to an interview prepared to ask questions that give you an insight into the company culture.</p>
<h2 id="heading-some-questions-to-consider-asking">Some questions to consider asking</h2>
<ul>
<li>Do any employees do anything outside of work together?</li>
</ul>
<p>This lets you get a sense of the company culture, if you are a bookworm that likes to game online, you may not like to work in an environment where you are expected to go binge-drinking with the sales guys twice a week.</p>
<ul>
<li>How many experienced engineers does the company employ?</li>
</ul>
<p>This lets you gauge your growth potential. Self learning can be good for you, but having multiple experienced engineers at your fingertips will catapult your progress.</p>
<ul>
<li>Who would I be interacting with on a daily or weekly basis?</li>
</ul>
<p>This allows you to get a head count of the people you would be working closely with. You will also want to be meeting the majority of them, if not all of them, prior to accepting a job offer, as you may not like the environment otherwise.</p>
<ul>
<li>Who would be training me? If I had a problem I was struggling with, who would I be able to go to for support?</li>
</ul>
<p>Onboarding can be a pretty hectic experience in smaller companies, and knowing that they have already addressed who will on-board you and provide ongoing support will give you some peace of mind that the experience will be a good one.</p>
<ul>
<li>What would I do for me to be considered successful in this role?</li>
</ul>
<p>This one was requested by <a class="user-mention" href="https://hashnode.com/@Eke">Victor Eke </a> and originally proposed by <a class="user-mention" href="https://hashnode.com/@DThompsonDev">Danny Thompson</a>!</p>
<p>This is a great question to ask if you are still unsure about the scope of the roles you would be expected to perform. It may also uncover aspects of the job that you didn't realize were expected of you, and you may not like them!</p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>That's it! I hope this article helps land a job at a smaller company if you are considering it. Some of my best years in the industry have been at small companies! Take the time to consider what you want from your career as a software engineer, and don't just jump onto the first boat you find, because it may already be sinking!</p>
<p>Follow me on <a target="_blank" href="https://twitter.com/SamDarylDev">Twitter</a> to keep up to date with my projects and get notified of new articles like this in the future!</p>
]]></content:encoded></item><item><title><![CDATA[React Hooks You Will Love ♥]]></title><description><![CDATA[Introduction
If there is one this I love, it's doing more, with less. 
useState is the bread and butter of React. And it's simplicity offers many use cases. However it's simplicity comes at the cost of having to implement various complexities outside...]]></description><link>https://blog.samdaryl.dev/react-hooks-you-will-love</link><guid isPermaLink="true">https://blog.samdaryl.dev/react-hooks-you-will-love</guid><category><![CDATA[React]]></category><category><![CDATA[hooks]]></category><category><![CDATA[ReactHooks]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Programming Tips]]></category><dc:creator><![CDATA[Sam Phillips]]></dc:creator><pubDate>Tue, 16 Aug 2022 16:16:20 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1660665420282/lllM8zLLG.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-introduction">Introduction</h1>
<p>If there is one this I love, it's doing more, with less. </p>
<p><code>useState</code> is the bread and butter of React. And it's simplicity offers many use cases. However it's simplicity comes at the cost of having to implement various complexities outside of the hook that could be included in the hook itself.</p>
<p>In this article I offer a few abstractions that you can use and extend to help tackle some of the common use cases you may come across when building an application in React.</p>
<h1 id="heading-usevalue">useValue</h1>
<p><code>useValue</code> is the simplest in this list. All it adds to <code>useState</code> is a utility function that resets the value to whatever you specified as the default value. This however is deceptively useful in situations where you need to clear text boxes and can create a better user experience.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> useValue = <span class="hljs-function">(<span class="hljs-params">defaultValue</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> [value, setValue] = useState(defaultValue);

    <span class="hljs-keyword">const</span> resetValue = <span class="hljs-function">() =&gt;</span> {
        setValue(defaultValue);
    };

    <span class="hljs-keyword">return</span> [value, setValue, resetValue];
};
</code></pre>
<p>Here it is in action:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1660662021055/aCz9Z90q5.gif" alt="1.gif" class="image--center mx-auto" /></p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> [value, setValue, resetValue] = useValue(<span class="hljs-string">"Test"</span>);

<span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
            <span class="hljs-attr">value</span>=<span class="hljs-string">{value}</span>
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(ev)</span> =&gt;</span> setValue(ev.target.value)}
        /&gt;
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{resetValue}</span>&gt;</span>Reset<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
);
</code></pre>
<h1 id="heading-usecounter">useCounter</h1>
<p><code>useCounter</code> does exactly what it says, it counts. However with a little extra logic around allowing the specification of <code>min</code>, <code>max</code> and <code>step</code> parameters, it becomes everything you need to implement paging, or anything that would require incrementing or decrementing a <code>number</code>.</p>
<p>I would use this as a base in a <code>usePaging</code> hook for paging logic that fits my specific use case on that page.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> useCounter = <span class="hljs-function">(<span class="hljs-params">defaultValue, step = <span class="hljs-number">1</span>, min, max</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> [value, setValue] = useState(defaultValue);

    <span class="hljs-keyword">const</span> resetValue = <span class="hljs-function">() =&gt;</span> {
        setValue(defaultValue);
    };

    <span class="hljs-keyword">const</span> setCount = <span class="hljs-function">(<span class="hljs-params">newValue</span>) =&gt;</span> {
        newValue = <span class="hljs-keyword">typeof</span> max === <span class="hljs-string">"number"</span> ? <span class="hljs-built_in">Math</span>.min(newValue, max) : value;
        newValue = <span class="hljs-keyword">typeof</span> min === <span class="hljs-string">"number"</span> ? <span class="hljs-built_in">Math</span>.max(newValue, min) : value;
        setValue(newValue);
    };

    <span class="hljs-keyword">const</span> increment = <span class="hljs-function">() =&gt;</span> {
        setValue(
            <span class="hljs-keyword">typeof</span> max === <span class="hljs-string">"number"</span> ? <span class="hljs-built_in">Math</span>.min(value + step, max) : value + step
        );
    };

    <span class="hljs-keyword">const</span> decrement = <span class="hljs-function">() =&gt;</span> {
        setValue(
            <span class="hljs-keyword">typeof</span> min === <span class="hljs-string">"number"</span> ? <span class="hljs-built_in">Math</span>.max(value - step, min) : value - step
        );
    };

    <span class="hljs-keyword">return</span> [value, setCount, resetValue, increment, decrement];
};
</code></pre>
<p>Here it is in action:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1660662487694/Mxo4CKKoe.gif" alt="2.gif" class="image--center mx-auto" /></p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> [
    count,
    setCount,
    resetCount,
    incrementCount,
    decrementCount
] = useCounter(<span class="hljs-number">1</span>, <span class="hljs-number">5</span>, <span class="hljs-number">0</span>, <span class="hljs-number">400</span>);

<span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>  
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
            <span class="hljs-attr">value</span>=<span class="hljs-string">{count}</span>
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(ev)</span> =&gt;</span> setCount(Number(ev.target.value))}
        /&gt;
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{incrementCount}</span>&gt;</span>Increment Count<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{decrementCount}</span>&gt;</span>Decrement Count<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{resetCount}</span>&gt;</span>Reset Count<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
);
</code></pre>
<h1 id="heading-useobject">useObject</h1>
<p><code>useObject</code> saves so much boilerplate code over time and can be used in some really sophisticated use cases elegantly. The main use case for it is simply filling out a form of many values that you eventually need to validate and send off to an API. I use this constantly and it has saved me so many keystrokes!</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> useObject = <span class="hljs-function">(<span class="hljs-params">defaultObj</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> [obj, setObj] = useState(defaultObj);

    <span class="hljs-keyword">const</span> updateObj = <span class="hljs-function">(<span class="hljs-params">updateObj</span>) =&gt;</span> {
        setObj({ ...obj, ...updateObj });
    };

    <span class="hljs-keyword">const</span> resetObj = <span class="hljs-function">() =&gt;</span> {
        setObj(defaultObj);
    };

    <span class="hljs-keyword">return</span> [obj, setObj, updateObj, resetObj];
};
</code></pre>
<p>Here it is in action:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1660663257318/ww0lSYACC.gif" alt="3.gif" class="image--center mx-auto" /></p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> [
    person,
    <span class="hljs-comment">/* setPerson not needed */</span>,
    updatePerson,
    resetPerson
] = useObject({});

<span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>  
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
            <span class="hljs-attr">value</span>=<span class="hljs-string">{person.name</span> || ""}
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(ev)</span> =&gt;</span> updatePerson({ name: ev.target.value })}
        /&gt;
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
            <span class="hljs-attr">value</span>=<span class="hljs-string">{person.country</span> || ""}
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(ev)</span> =&gt;</span> updatePerson({ country: ev.target.value })}
        /&gt;
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{resetPerson}</span>&gt;</span>Reset<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{JSON.stringify(person, null, 2)}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
);
</code></pre>
<h1 id="heading-usearray">useArray</h1>
<p><code>useArray</code> is another one that blew me away when I first used it! You can extend this hook to expose any array operations you like and never have to do another shallow clone in you component to get the changes to reflect ever again! Need a map function? Throw it in there!</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> useArray = <span class="hljs-function">(<span class="hljs-params">defaultArray</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> [arr, setArr] = useState(defaultArray);

    <span class="hljs-keyword">const</span> push = <span class="hljs-function">(<span class="hljs-params">value</span>) =&gt;</span> {
        setArr([...arr, value]);
    };

    <span class="hljs-keyword">const</span> unshift = <span class="hljs-function">(<span class="hljs-params">value</span>) =&gt;</span> {
        setArr([value, ...arr]);
    };

    <span class="hljs-keyword">const</span> pop = <span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">const</span> current = [...arr];
        <span class="hljs-keyword">const</span> deleted = current.pop();
        setArr(current);
        <span class="hljs-keyword">return</span> deleted;
    };

    <span class="hljs-keyword">const</span> shift = <span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">const</span> current = [...arr];
        <span class="hljs-keyword">const</span> deleted = current.shift();
        setArr(current);
        <span class="hljs-keyword">return</span> deleted;
    };

    <span class="hljs-keyword">const</span> concat = <span class="hljs-function">(<span class="hljs-params">newArr</span>) =&gt;</span> {
        setArr([...arr, ...newArr]);
    };

    <span class="hljs-keyword">const</span> inverseConcat = <span class="hljs-function">(<span class="hljs-params">newArr</span>) =&gt;</span> {
        setArr([...newArr, ...arr]);
    };

    <span class="hljs-keyword">const</span> splice = <span class="hljs-function">(<span class="hljs-params">index</span>) =&gt;</span> {
        <span class="hljs-keyword">const</span> current = [...arr];
        current.splice(index, <span class="hljs-number">1</span>);
        setArr(current);
    };

    <span class="hljs-keyword">const</span> reset = <span class="hljs-function">() =&gt;</span> {
        setArr(defaultArray);
    };

    <span class="hljs-keyword">return</span> [
        arr,
        setArr,
        {
            push,
            unshift,
            pop,
            shift,
            concat,
            inverseConcat,
            splice,
            reset
        }
    ];
};
</code></pre>
<p>Here it is in action:</p>
<blockquote>
<p>Note the use of <code>useValue</code> for the <code>input</code> allowing me to easily clear it when <code>push</code> or <code>Unshift</code> are clicked 😉</p>
</blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1660664000876/-uZhI9M8T.gif" alt="4.gif" class="image--center mx-auto" /></p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> [
    people,
    <span class="hljs-comment">/* setPeople not needed */</span>,
    {
        <span class="hljs-attr">push</span>: pushPeople,
        <span class="hljs-attr">unshift</span>: unshiftPeople,
        <span class="hljs-attr">pop</span>: popPeople,
        <span class="hljs-attr">shift</span>: shiftPeople,
        <span class="hljs-attr">reset</span>: resetPeople,
        <span class="hljs-attr">splice</span>: splicePeople
    }
] = useArray([]);

<span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>  
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
                <span class="hljs-attr">value</span>=<span class="hljs-string">{name}</span>
                <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Name"</span>
                <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(ev)</span> =&gt;</span> setName(ev.target.value)}
            /&gt;
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> {
                    pushPeople(name);
                    resetName();
                }}
            &gt;
                Push
            <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> {
                    unshiftPeople(name);
                    resetName();
                }}
            &gt;
                Unshift
            <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> popPeople()}&gt;Pop<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> shiftPeople()}&gt;Shift<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> resetPeople()}&gt;Reset<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">ol</span>&gt;</span>
            {people.map((p, i) =&gt; (
                <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{i}</span>&gt;</span>
                    {p}{" "}
                    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> splicePeople(i)}&gt;
                        Delete
                    <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
            ))}
        <span class="hljs-tag">&lt;/<span class="hljs-name">ol</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
);
</code></pre>
<h1 id="heading-conclusion">Conclusion</h1>
<p>That's it! I hope this article helps you reduce the code you need to write, and gets you thinking about how you can use custom hooks for elegant abstractions 👍</p>
<p>Follow me on <a target="_blank" href="https://twitter.com/SamDarylDev">Twitter</a> to keep up to date with my projects and get notified of new articles like this in the future!</p>
]]></content:encoded></item><item><title><![CDATA[Create Beautiful 3D Perspective Images Easily Using React and CSS]]></title><description><![CDATA[Introduction
Perspective transform looks great and creates a really nice experience for the user. When using a framework like React, implementing something like this becomes super simple only using a few CSS styles 👍

Setup
Lets start with a simple ...]]></description><link>https://blog.samdaryl.dev/create-beautiful-3d-perspective-images-easily-using-react-and-css</link><guid isPermaLink="true">https://blog.samdaryl.dev/create-beautiful-3d-perspective-images-easily-using-react-and-css</guid><category><![CDATA[React]]></category><category><![CDATA[CSS]]></category><category><![CDATA[transform]]></category><category><![CDATA[HTML5]]></category><category><![CDATA[Design]]></category><dc:creator><![CDATA[Sam Phillips]]></dc:creator><pubDate>Mon, 15 Aug 2022 15:57:13 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1660578684009/LxyYN10gL.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-introduction">Introduction</h1>
<p>Perspective transform looks great and creates a really nice experience for the user. When using a framework like React, implementing something like this becomes super simple only using a few CSS styles 👍</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1660574689677/upBf52L3m.gif" alt="complete.gif" class="image--center mx-auto" /></p>
<h1 id="heading-setup">Setup</h1>
<p>Lets start with a simple <code>Image</code> component:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> Image = <span class="hljs-function">(<span class="hljs-params">{ width, height, src, alt }</span>) =&gt;</span> {
    <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">width</span>=<span class="hljs-string">{width}</span> <span class="hljs-attr">height</span>=<span class="hljs-string">{height}</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{src}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">{alt}</span> /&gt;</span></span>;
};
</code></pre>
<p>This just takes our basic props and applies them to an <code>img</code> element.</p>
<p>Now let's add our base styles ready for manipulation, along with the state we will need:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> Image = <span class="hljs-function">(<span class="hljs-params">{ width, height, src, alt }</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> [scale, setScale] = useState(<span class="hljs-number">1</span>);
    <span class="hljs-keyword">const</span> [rx, setRx] = useState(<span class="hljs-number">0</span>);
    <span class="hljs-keyword">const</span> [ry, setRy] = useState(<span class="hljs-number">0</span>);

    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">img</span>
            <span class="hljs-attr">width</span>=<span class="hljs-string">{width}</span>
            <span class="hljs-attr">height</span>=<span class="hljs-string">{height}</span>
            <span class="hljs-attr">src</span>=<span class="hljs-string">{src}</span>
            <span class="hljs-attr">alt</span>=<span class="hljs-string">{alt}</span>
            <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span>
                <span class="hljs-attr">transition:</span> "<span class="hljs-attr">transform</span> <span class="hljs-attr">150ms</span> <span class="hljs-attr">linear</span>",
                <span class="hljs-attr">transform:</span> `<span class="hljs-attr">perspective</span>(<span class="hljs-attr">1000px</span>) <span class="hljs-attr">rotateX</span>(${<span class="hljs-attr">ry</span>}<span class="hljs-attr">deg</span>) <span class="hljs-attr">rotateY</span>(${<span class="hljs-attr">rx</span>}<span class="hljs-attr">deg</span>) <span class="hljs-attr">scale3d</span>(${<span class="hljs-attr">scale</span>},${<span class="hljs-attr">scale</span>},${<span class="hljs-attr">scale</span>})`
            }}
        /&gt;</span></span>
    );
};
</code></pre>
<p>It may look a little intimidating at first! But it's really not that complex. First we defined <code>scale</code>, <code>rx</code> and <code>ry</code> state variables to handle the state changes we are yet to implement.</p>
<p>Then we added two styles. <code>transition: "transform 150ms linear"</code> applies an animation to any changes on the <code>transform</code> style over <code>150ms</code> using the <code>ease-out</code> timing function. We also added <code>transform</code> which is where the magic happens. Let's break it down.</p>
<p>The <code>transform</code> style is performing 4 operations. <code>perspective(1000px)</code> is what gives the 3d perspective effect to the image. Without it, the rest of the operations would still apply but it wouldn't give an appearance of depth. The value of <code>1000px</code> is generally a good value to use and looks good, you can play around with this value to see what it does and can make some crazy effects by setting it really low 😂. <code>rotateX(${ry}deg)</code> is injecting the <code>ry</code> value telling the image to rotate on the x axis, we inverse the x and y axis when applying the values as rotating the x axis tilts the image back and forth not left to right, so its intuitive to the user when moving the mouse over it to inverse these values. The same goes for <code>rotateY(${rx}deg)</code>. <code>scale3d(${scale},${scale},${scale})</code> is applying <code>scale</code> to all 3 axis, this will give a nicer effect when we add our math to make the image a little larger whilst the users cursor is hovering over it.</p>
<p>In most browsers, changing the perspective of an element won't work without specifying a <code>scale3d()</code> function. I'm not sure if this is intentional or not, but for now, even if we don't want to scale an element, we still have to set <code>scale3d(1,1,1)</code>.</p>
<h1 id="heading-a-little-math">A Little Math</h1>
<p>Let's add in our event handlers and do a little math!</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> Image = <span class="hljs-function">(<span class="hljs-params">{ width, height, src, alt }</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> imgRef = useRef();
    <span class="hljs-keyword">const</span> [scale, setScale] = useState(<span class="hljs-number">1</span>);
    <span class="hljs-keyword">const</span> [rx, setRx] = useState(<span class="hljs-number">0</span>);
    <span class="hljs-keyword">const</span> [ry, setRy] = useState(<span class="hljs-number">0</span>);

    <span class="hljs-keyword">const</span> onMouseMove = <span class="hljs-function">(<span class="hljs-params">ev</span>) =&gt;</span> {
        <span class="hljs-comment">// Get the bounding rect for the image</span>
        <span class="hljs-keyword">const</span> rect = imgRef.current.getBoundingClientRect();

        <span class="hljs-comment">// Get the X and Y position of the cursor relative to the image</span>
        <span class="hljs-keyword">const</span> x = ev.clientX - rect.left;
        <span class="hljs-keyword">const</span> y = ev.clientY - rect.top;

        <span class="hljs-comment">// Funky math to normalize the x/y position of the cursor</span>
        <span class="hljs-comment">// to between -20 and 20</span>
        <span class="hljs-comment">// For the effect to work as expected, the X axis need to be inversed</span>
        <span class="hljs-keyword">const</span> nX = <span class="hljs-number">40</span> - (x * <span class="hljs-number">40</span>) / rect.width - <span class="hljs-number">20</span>;
        <span class="hljs-keyword">const</span> nY = (y * <span class="hljs-number">40</span>) / rect.height - <span class="hljs-number">20</span>;

        <span class="hljs-comment">// Set rx and ry</span>
        setRx(nX);
        setRy(nY);

        <span class="hljs-comment">// Set the scale to 1.1 shilst the cursor is over the image</span>
        setScale(<span class="hljs-number">1.1</span>);
    };

    <span class="hljs-keyword">const</span> onMouseLeave = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-comment">// When the cursor leaves the image, reset the state back to default values</span>
        setRx(<span class="hljs-number">0</span>);
        setRy(<span class="hljs-number">0</span>);
        setScale(<span class="hljs-number">1</span>);
    };

    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">img</span>
            <span class="hljs-attr">ref</span>=<span class="hljs-string">{imgRef}</span>
            <span class="hljs-attr">width</span>=<span class="hljs-string">{width}</span>
            <span class="hljs-attr">height</span>=<span class="hljs-string">{height}</span>
            <span class="hljs-attr">src</span>=<span class="hljs-string">{src}</span>
            <span class="hljs-attr">alt</span>=<span class="hljs-string">{alt}</span>
            <span class="hljs-attr">onMouseMove</span>=<span class="hljs-string">{onMouseMove}</span>
            <span class="hljs-attr">onMouseLeave</span>=<span class="hljs-string">{onMouseLeave}</span>
            <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span>
                <span class="hljs-attr">transition:</span> "<span class="hljs-attr">transform</span> <span class="hljs-attr">150ms</span> <span class="hljs-attr">linear</span>",
                <span class="hljs-attr">transform:</span> `<span class="hljs-attr">perspective</span>(<span class="hljs-attr">1000px</span>) <span class="hljs-attr">rotateX</span>(${<span class="hljs-attr">ry</span>}<span class="hljs-attr">deg</span>) <span class="hljs-attr">rotateY</span>(${<span class="hljs-attr">rx</span>}<span class="hljs-attr">deg</span>) <span class="hljs-attr">scale3d</span>(${<span class="hljs-attr">scale</span>},${<span class="hljs-attr">scale</span>},${<span class="hljs-attr">scale</span>})`
            }}
        /&gt;</span></span>
    );
};
</code></pre>
<p>Its Alive!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1660574317260/QFdyoCRz_.gif" alt="base.gif" class="image--center mx-auto" /></p>
<p>We added an <code>onMouseMove</code> event to handle getting the position of the cursor relative to the image element, and normalized those x/y values to between <strong>-20</strong> and <strong>20</strong>. This allows us to simply apply those values to the <code>rotateX</code> and <code>rotateY</code> transform functions by setting them into <code>rx</code>and <code>ry</code>!</p>
<p><code>onMouseLeave</code> simply resets the state for <code>rx</code>, <code>ry</code> and <code>scale</code> to their default values and returns the image to it's default state.</p>
<h1 id="heading-a-little-more-flare">A Little More Flare</h1>
<p>This looks great but another great feature that can be used in tandem with all this is <code>box-shadow</code> as perspective transforms render the shadow as well! Better yet, we can swap the shadow out for a glow effect when the user starts hovering over the image to really make it pop 🎉</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> BASE_SHADOW = <span class="hljs-string">"rgba(0, 0, 0, 0.4) 0px 12px 28px -10px"</span>;
<span class="hljs-keyword">const</span> GLOW_SHADOW = <span class="hljs-string">"rgb(113,199,236) 0px 0px 15px 5px"</span>;

<span class="hljs-keyword">const</span> Image = <span class="hljs-function">(<span class="hljs-params">{ width, height, src, alt }</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> imgRef = useRef();
    <span class="hljs-keyword">const</span> [scale, setScale] = useState(<span class="hljs-number">1</span>);
    <span class="hljs-keyword">const</span> [rx, setRx] = useState(<span class="hljs-number">0</span>);
    <span class="hljs-keyword">const</span> [ry, setRy] = useState(<span class="hljs-number">0</span>);
    <span class="hljs-keyword">const</span> [shadow, setShadow] = useState(BASE_SHADOW);

    <span class="hljs-keyword">const</span> onMouseMove = <span class="hljs-function">(<span class="hljs-params">ev</span>) =&gt;</span> {
        <span class="hljs-comment">// Get the bounding rect for the image</span>
        <span class="hljs-keyword">const</span> rect = imgRef.current.getBoundingClientRect();

        <span class="hljs-comment">// Get the X and Y position of the cursor relative to the image</span>
        <span class="hljs-keyword">const</span> x = ev.clientX - rect.left;
        <span class="hljs-keyword">const</span> y = ev.clientY - rect.top;

        <span class="hljs-comment">// Funky math to normalize the x/y position of the cursor</span>
        <span class="hljs-comment">// to between -20 and 20</span>
        <span class="hljs-comment">// For the effect to work as expected, the X axis need to be inversed</span>
        <span class="hljs-keyword">const</span> nX = <span class="hljs-number">40</span> - (x * <span class="hljs-number">40</span>) / rect.width - <span class="hljs-number">20</span>;
        <span class="hljs-keyword">const</span> nY = (y * <span class="hljs-number">40</span>) / rect.height - <span class="hljs-number">20</span>;

        <span class="hljs-comment">// Set rx and ry</span>
        setRx(nX);
        setRy(nY);

        <span class="hljs-comment">// Set the scale to 1.1 shilst the cursor is over the image</span>
        setScale(<span class="hljs-number">1.1</span>);

        <span class="hljs-comment">// Set the glow shadow effect</span>
        setShadow(GLOW_SHADOW);
    };

    <span class="hljs-keyword">const</span> onMouseLeave = <span class="hljs-function">() =&gt;</span> {
        <span class="hljs-comment">// When the cursor leaves the image, reset the state back to default values</span>
        setRx(<span class="hljs-number">0</span>);
        setRy(<span class="hljs-number">0</span>);
        setScale(<span class="hljs-number">1</span>);
        setShadow(BASE_SHADOW);
    };

    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">img</span>
            <span class="hljs-attr">ref</span>=<span class="hljs-string">{imgRef}</span>
            <span class="hljs-attr">width</span>=<span class="hljs-string">{width}</span>
            <span class="hljs-attr">height</span>=<span class="hljs-string">{height}</span>
            <span class="hljs-attr">src</span>=<span class="hljs-string">{src}</span>
            <span class="hljs-attr">alt</span>=<span class="hljs-string">{alt}</span>
            <span class="hljs-attr">onMouseMove</span>=<span class="hljs-string">{onMouseMove}</span>
            <span class="hljs-attr">onMouseLeave</span>=<span class="hljs-string">{onMouseLeave}</span>
            <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span>
                <span class="hljs-attr">boxShadow:</span> <span class="hljs-attr">shadow</span>,
                <span class="hljs-attr">transition:</span> "<span class="hljs-attr">all</span> <span class="hljs-attr">150ms</span> <span class="hljs-attr">linear</span>",
                <span class="hljs-attr">transform:</span> `<span class="hljs-attr">perspective</span>(<span class="hljs-attr">1000px</span>) <span class="hljs-attr">rotateX</span>(${<span class="hljs-attr">ry</span>}<span class="hljs-attr">deg</span>) <span class="hljs-attr">rotateY</span>(${<span class="hljs-attr">rx</span>}<span class="hljs-attr">deg</span>) <span class="hljs-attr">scale3d</span>(${<span class="hljs-attr">scale</span>},${<span class="hljs-attr">scale</span>},${<span class="hljs-attr">scale</span>})`
            }}
        /&gt;</span></span>
    );
};
</code></pre>
<p>And here is the final result!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1660574689677/upBf52L3m.gif" alt="complete.gif" class="image--center mx-auto" /></p>
<p>We set a couple of constant values <code>BASE_SHADOW</code> and <code>GLOW_SHADOW</code>, added a new  <code>shadow</code> state variable and switched between them in the same way as the other state values. We also added the <code>boxShadow</code> style on the <code>img</code> element, applying <code>shadow</code>.</p>
<blockquote>
<p>Notice a small change was made to <code>transition</code> from <code>transform 150ms linear</code> to <code>all 150ms linear</code>, this ensure that the transition animation is also applied to the <code>box-shadow</code> and not just the <code>transition</code> style.</p>
</blockquote>
<h1 id="heading-it-doesnt-have-to-be-an-image">It Doesn't Have to be an Image!</h1>
<p>Since this is just using CSS transforms, it can be applied to anything! Here is the same component edited to use a <code>div</code> with some text in it 👍</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1660575384345/QfZJZDUZB.gif" alt="card.gif" class="image--center mx-auto" /></p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>That's it! I hope this article helped you do fancy things with CSS transforms.</p>
<p>Follow me on <a target="_blank" href="https://twitter.com/SamDarylDev">Twitter</a> to keep up to date with my projects and get notified of new articles like this in the future!</p>
]]></content:encoded></item><item><title><![CDATA[Use setTimeout in React to Defer Logic]]></title><description><![CDATA[Introduction
setTimeout is a very commonly used JavaScript function. It is very useful for many things, such as timing how long an alert should show, or debouncing a button to prevent double clicks.
However when using higher level rendering framework...]]></description><link>https://blog.samdaryl.dev/use-settimeout-in-react-to-defer-logic</link><guid isPermaLink="true">https://blog.samdaryl.dev/use-settimeout-in-react-to-defer-logic</guid><category><![CDATA[SetTimeout]]></category><category><![CDATA[React]]></category><category><![CDATA[tips]]></category><category><![CDATA[Tutorial]]></category><category><![CDATA[tricks]]></category><dc:creator><![CDATA[Sam Phillips]]></dc:creator><pubDate>Sun, 14 Aug 2022 12:19:02 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1660478846007/Wk09COufP.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-introduction">Introduction</h1>
<p><code>setTimeout</code> is a very commonly used JavaScript function. It is very useful for many things, such as timing how long an alert should show, or debouncing a button to prevent double clicks.</p>
<p>However when using higher level rendering frameworks like React, Angular, Vue etc, it can give you control over the JavaScript runtime itself to make your life easier!</p>
<h1 id="heading-a-simple-problem">A simple problem</h1>
<p>Let's take this simple app as an example:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [text, setText] = useState(<span class="hljs-string">"This is some text"</span>);
  <span class="hljs-keyword">const</span> [pWidth, setPWidth] = useState(<span class="hljs-number">0</span>);
  <span class="hljs-keyword">const</span> pRef = useRef();

  <span class="hljs-keyword">const</span> onTextChange = <span class="hljs-function">(<span class="hljs-params">changedText</span>) =&gt;</span> {
    setText(changedText);
    setPWidth(<span class="hljs-built_in">Math</span>.round(pRef.current.getBoundingClientRect().width));
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{text}</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(ev)</span> =&gt;</span> onTextChange(ev.target.value)} /&gt;
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">{pRef}</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">display:</span> "<span class="hljs-attr">inline</span>" }}&gt;</span>{text}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{pWidth}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
}
</code></pre>
<p>This app contains an <code>input</code> that when changed, runs a function to update the <code>text</code> state variable and uses <code>pRef</code> to extract the current width of the <code>p</code> element and set <code>pWidth</code>.</p>
<p>This renders the following:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1660475793906/Slxpo94fZ.png" alt="image.png" class="image--center mx-auto" /></p>
<p><code>pWidth</code> is only going to be set when we change the text, so lets delete the text and we should see a width of <code>0</code>:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1660477118476/MufWJ0oXc.gif" alt="test.gif" class="image--center mx-auto" /></p>
<p>Huh? That's not right! It's showing the width of the <code>p</code> element when it had text in it!</p>
<p>This is because when we update <code>text</code> via <code>setText</code>, React hasn't had a chance to set the text in the <code>p</code> element, meaning the width of the <code>p</code> element hasn't changed before we set its width using <code>setPWidth</code>!</p>
<h1 id="heading-settimeout-to-the-rescue">setTimeout to the rescue!</h1>
<p>We can fix this using setTimeout!</p>
<p>Let's change this line:</p>
<pre><code class="lang-jsx">setPWidth(<span class="hljs-built_in">Math</span>.round(pRef.current.getBoundingClientRect().width));
</code></pre>
<p>To this:</p>
<pre><code class="lang-jsx"><span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> {
  setPWidth(<span class="hljs-built_in">Math</span>.round(pRef.current.getBoundingClientRect().width));
});
</code></pre>
<p>And check out output when we clear the input:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1660477203377/4oJmYtZnu.gif" alt="test.gif" class="image--center mx-auto" /></p>
<p>And like magic it works as expected!</p>
<h1 id="heading-why-does-this-work">Why does this work?</h1>
<p>As we have already ascertained, the issue was that we needed to wait until React had actually rendered the text in the <code>p</code> element before setting the <code>p</code> elements width.</p>
<p><code>setTimeout</code> solves this problem by <strong>deferring</strong> setting the width of the <code>p</code> element to the next JavaScript runtime cycle, ensuring that the React has rendered the changes from the previous runtime cycle before running our pending <code>setTimeout</code> call-back function.</p>
<h1 id="heading-using-asyncawait">Using async/await</h1>
<p>This technique can also be used in async functions with the use of a utility function such as:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> waitForRender = <span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function"><span class="hljs-params">res</span> =&gt;</span> <span class="hljs-built_in">setTimeout</span>(res));
</code></pre>
<p>Using the example above, <code>waitForRender</code> could be used like this:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> onTextChange = <span class="hljs-keyword">async</span> (changedText) =&gt; {
  setText(changedText);
  <span class="hljs-keyword">await</span> waitForRender();
  setPWidth(pRef.current.getBoundingClientRect().width);
};
</code></pre>
<p>This produces the same output!</p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>That's it! I hope this helped you learn a new technique to add to your toolset when tackling edge case problems that require waiting for a rendering cycle to pass.</p>
<p>Follow me on <a target="_blank" href="https://twitter.com/SamDarylDev">Twitter</a> to keep up to date with my projects and get notified of new articles like this in the future!</p>
]]></content:encoded></item><item><title><![CDATA[Tailwind CSS Tips to Make Your Life Easier]]></title><description><![CDATA[Introduction
Tailwind CSS has won me over, and now if I can get away with using it, I will. However with great power comes great responsibility, and with Tailwind, that mean writing classes in a way that gets you what you need, with as few classes as...]]></description><link>https://blog.samdaryl.dev/tailwind-css-tips-to-make-your-life-easier</link><guid isPermaLink="true">https://blog.samdaryl.dev/tailwind-css-tips-to-make-your-life-easier</guid><category><![CDATA[CSS]]></category><category><![CDATA[Tailwind CSS]]></category><category><![CDATA[HTML5]]></category><category><![CDATA[tips]]></category><category><![CDATA[Tailwind CSS Tutorial]]></category><dc:creator><![CDATA[Sam Phillips]]></dc:creator><pubDate>Fri, 12 Aug 2022 15:45:58 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1660317878184/y0RR3c3Fi.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-introduction">Introduction</h1>
<p>Tailwind CSS has won me over, and now if I can get away with using it, I will. However with great power comes great responsibility, and with Tailwind, that mean writing classes in a way that gets you what you need, with as few classes as possible.</p>
<h1 id="heading-general-tips">General Tips</h1>
<p>Here are some tips I've slowly migrated to using regularly that have made mine and others lives easier, and hopefully now yours too!</p>
<blockquote>
<p>You can use <a target="_blank" href="https://play.tailwindcss.com/">Tailwind CSS Playground</a> to experiment with any of these examples 👍</p>
</blockquote>
<h2 id="heading-xy-axis">X/Y axis</h2>
<p>Most of the time when using padding or margins, the spacing you are creating will be the same top and bottom, as it is left and right, so if you see:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"pl-4 pr-4 pt-2 pb-2"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Change it to:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"px-4 py-2"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>If all 4 directions need to be the same, just use <code>p</code></p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"p-4"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<h2 id="heading-only-vertical-margins">Only vertical margins</h2>
<p>Margins are great as it allows you to create space around an element without creating a needless parent with padding. But in complex UI structures, setting <code>margin-left</code> or <code>margin-right</code> can cause all kinds of hell later on as things change as it can push elements causing them to overflow their parent.</p>
<p>Vertical margins on the other hand are usually fine and very rarely cause this issue. So if you see:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"mx-4 my-4"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>If possible, changing it to:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"px-4"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"my-4"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>May save you a headache in the future.</p>
<h2 id="heading-use-inset">Use inset</h2>
<p>When positioning an element using <code>position: absolute</code> or <code>position: fixed</code> and expanding it to fill its parent, its very common to see something like:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"absolute top-0 bottom-0 left-0 right-0"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>A shorthand for setting each directional anchor is using <code>inset</code>:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"absolute inset-0"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>This does the exact same thing and saves needless classes!</p>
<h2 id="heading-responsive-grid">Responsive grid</h2>
<p>Many people still use <code>flex-box</code> for almost all layouts, which can get pretty complex fast. You can use grid to layout the top level responsiveness of key sections/elements in your site, leaving <code>flex-box</code> to deal with the smaller, more manageable elements in isolation.</p>
<p>Here is a simple example of a making a row of 4 <code>div</code>s responsive using only the parent:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"grid sm:grid-cols-2 lg:grid-cols-4"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"h-24"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"h-24"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"h-24"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"h-24"</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Using <code>sm:</code> and <code>lg:</code> modifiers (which simply relate to pre-configured media queries) you can elegantly define how many columns should be in this grid row. Larger screen widths (more than 1024px under the hood) will show 4 in a row, smaller screen widths (less than 1024px and larger than 640px) will show 2 rows of 2, and finally anything less than 640px will show all 4 <code>div</code>s top to bottom.</p>
<p>Sometimes you may see a default setting defining 1 column for the smallest screen widths:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4"</span>&gt;</span>
</code></pre>
<p>In this case defining <code>grid grid-cols-1</code> has the exact same effect as simply defining <code>grid</code>, as its default column setting is 1. This means using <code>grid-cols-1</code> is pointless and can be removed.</p>
<h2 id="heading-selecting-children-from-a-parent-tag-using-custom-selectors">Selecting children from a parent tag using custom selectors</h2>
<p>Let's take a look at the previous example:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"grid sm:grid-cols-2 lg:grid-cols-4"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"h-24"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"h-24"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"h-24"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"h-24"</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>It's using grid which is great, but defining <code>class="h-24"</code> on every child <code>div</code> is cumbersome.</p>
<p>Tailwind CSS 3.1+ to the rescue! If you make sure you are on at least version 3.1, you can do this!</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"grid sm:grid-cols-2 lg:grid-cols-4 [&amp;&gt;div]:h-24"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>This does the same thing! You can use <code>[]</code> to define a selector and target all children that match to apply a class to them! In this case we used <code>[&amp;&gt;div]</code>. The <code>&amp;</code> denotes the current element that you are defining the class on. The <code>&gt;</code> is used in CSS selectors to denote direct children, and in this case, we needed to target direct <code>div</code> children.</p>
<h2 id="heading-change-elevation-on-hover">Change elevation on hover</h2>
<p>Tailwind makes elevation super easy and provides nice looking <code>shadow</code> classes out of the box.</p>
<p>Elevated elements are great on their own to show key content in cards etc, adding an extra slightly higher elevation to the element on <code>hover:</code> really makes a users experience that bit more engaging:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"grid sm:grid-cols-3 gap-3"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"h-32 w-32 hover:scale-110 border rounded-md shadow-md hover:shadow-xl transition-all"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"h-32 w-32 hover:scale-110 border rounded-md shadow-md hover:shadow-xl transition-all"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"h-32 w-32 hover:scale-110 border rounded-md shadow-md hover:shadow-xl transition-all"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1660239776488/al6tqtgbD.gif" alt="shadow.gif" class="image--center mx-auto" /></p>
<p>In this example we have a simple <code>div</code> with <code>border</code>, <code>rounded-md</code> and <code>shadow-md</code>. But as you can see, increasing the elevation using <code>hover:shadow-xl</code> and the size using <code>hover:scale-110</code> dramatically changes the user experience. And as always, we use <code>transition-all</code> to allow those changes to be animated smoothly instead of changing instantly. 3 classes to drastically improve the user engagement seems worth it to me!</p>
<blockquote>
<p>NOTE: Always try to change the size of an element with it's elevation. It's just common sense that if the elevation increases and makes an element look like it's further away from the page, that it would also appear larger to the user!</p>
</blockquote>
<h1 id="heading-honourable-mention">Honourable mention</h1>
<p>Although this goes beyond a general tip and is more of a fully-fledged pattern, I thought I would share this with you as I find my self using it again and again!</p>
<h2 id="heading-elegantly-responsive-modal-overlay">Elegantly responsive modal / overlay</h2>
<p>Below is an example of a containing <code>div</code> that represents an overlay, with child <code>div</code> that is responsively centred and even becomes scrollable if there is not enough space to show all of it's content!</p>
<p>This example also uses <code>backdrop-blur-sm</code> to blur the pages content if the browser supports it, bringing even more focus to the modals content 👍</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"fixed inset-0 bg-[rgba(0,0,0,0.4)] backdrop-blur-sm"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[calc(100%_-_30px)] max-w-lg max-h-[calc(100%_-_30px)] overflow-y-auto rounded bg-white p-4"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"h-64"</span>&gt;</span>The standard chunk of Lorem Ipsum used since the 1500s is reproduced below for those interested. Sections 1.10.32 and 1.10.33 from "de Finibus Bonorum et Malorum" by Cicero are also reproduced in their exact original form, accompanied by English versions from the 1914 translation by H. Rackham.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<h1 id="heading-conclusion">Conclusion</h1>
<p>That's it! I hope this article helped you in some way when using Tailwind CSS, and please let me know if there is anything you would like me to add, especially if it can be done better! 👍</p>
<p>Follow me on <a target="_blank" href="https://twitter.com/SamDarylDev">Twitter</a> to keep up to date with my projects and get notified of new articles like this in the future!</p>
]]></content:encoded></item><item><title><![CDATA[Create Beautiful Banners and Other Graphics Easily Using HTML and CSS]]></title><description><![CDATA[Introduction
If you are like me, you like to create graphics using the tools you already know. If I need a banner or graphic for something, I don't want to spend 2 weeks learning Photoshop, Canva, or some other graphic design tool to create a single,...]]></description><link>https://blog.samdaryl.dev/create-beautiful-banners-and-other-graphics-easily-using-html-and-css</link><guid isPermaLink="true">https://blog.samdaryl.dev/create-beautiful-banners-and-other-graphics-easily-using-html-and-css</guid><category><![CDATA[HTML]]></category><category><![CDATA[CSS]]></category><category><![CDATA[HTML5]]></category><category><![CDATA[CSS3]]></category><category><![CDATA[Google Chrome]]></category><dc:creator><![CDATA[Sam Phillips]]></dc:creator><pubDate>Thu, 04 Aug 2022 16:47:18 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1659631027347/j2XX4QLHM.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-introduction">Introduction</h1>
<p>If you are like me, you like to create graphics using the tools you already know. If I need a banner or graphic for something, I don't want to spend 2 weeks learning Photoshop, Canva, or some other graphic design tool to create a single, simple image for a specific purpose.</p>
<p>Here is a simple way to create any image or graphic you need using the tools you already know, HTML and CSS. I made the banner for this blog post using this very method! And I will use it as an example in this article.</p>
<h1 id="heading-create-an-empty-html-document">Create an Empty HTML Document</h1>
<p>First create a HTML document, doesn't need anything other than enough to open it in chrome and see its content.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">http-equiv</span>=<span class="hljs-string">"X-UA-Compatible"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"IE=edge"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Document<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>

    <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>You don't need the meta tags, they just get generated when using the VS Code <code>doc</code> snippet.</p>
<h1 id="heading-create-a-banner">Create a Banner</h1>
<p>Next let's create a <code>div</code> with a <code>class</code> to set things up along with some CSS styles for what we need, a cover image for a hashnode blog post is 1600x840 so that's what we will specify for its <code>width</code> and <code>height</code>.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">http-equiv</span>=<span class="hljs-string">"X-UA-Compatible"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"IE=edge"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Document<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="css">
            <span class="hljs-selector-class">.banner</span> {
                <span class="hljs-comment">/* Desired width */</span>
                <span class="hljs-attribute">width</span>: <span class="hljs-number">1600px</span>;

                <span class="hljs-comment">/* Desired height */</span>
                <span class="hljs-attribute">height</span>: <span class="hljs-number">840px</span>;

                <span class="hljs-comment">/* A nice looking gradient at a 45deg angle because i'm edgy */</span>
                <span class="hljs-attribute">background</span>: <span class="hljs-built_in">linear-gradient</span>(<span class="hljs-number">45deg</span>, #<span class="hljs-number">12</span>c2e9, #c471ed, #f64f59);

                <span class="hljs-comment">/* White text seems appropriate */</span>
                <span class="hljs-attribute">color</span>: white;

                <span class="hljs-comment">/* Some padding to help text wrap nicely */</span>
                <span class="hljs-attribute">padding</span>: <span class="hljs-number">4rem</span>;

                <span class="hljs-comment">/* Chrome supports Segoe UI out of the box and it's usually good enough for banners */</span>
                <span class="hljs-comment">/* Easy to import a custom font though! */</span>
                <span class="hljs-attribute">font-family</span>: Segoe UI;

                <span class="hljs-comment">/* And finally just use flex-box to center the text vertically */</span>
                <span class="hljs-attribute">display</span>: flex;
                <span class="hljs-attribute">align-items</span>: center;
            }

            <span class="hljs-selector-class">.text</span> {
                <span class="hljs-comment">/* Center the text horizonally too */</span>
                <span class="hljs-attribute">text-align</span>: center;

                <span class="hljs-comment">/* Font size set to whatever looks best */</span>
                <span class="hljs-attribute">font-size</span>: <span class="hljs-number">80px</span>;
            }
        </span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>  <span class="hljs-attr">class</span>=<span class="hljs-string">"banner"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text"</span>&gt;</span>Create Beautiful Banners and Other Graphics Easily Using HTML and CSS<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>And here we have it!
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1659629123209/3QG3P3IaD.png" alt="banner2.png" class="image--center mx-auto" /></p>
<p>You can do so much with so little, here it is with an image and text stroke:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.banner</span> {
    <span class="hljs-attribute">background</span>: <span class="hljs-built_in">url</span>(./background.jpg);
    <span class="hljs-attribute">background-size</span>: cover;
}

<span class="hljs-selector-class">.text</span> {
    <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">500</span>;
    <span class="hljs-attribute">-webkit-text-stroke</span>: <span class="hljs-number">1px</span> black;
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1659630275586/O0eKeMHoM.png" alt="banner2-1.png" class="image--center mx-auto" /></p>
<p>You get the point, you can get as fancy as you like, with minimal effort using HTML and CSS, and you aren't constrained by any tooling, pay walls, or forced sign ups.</p>
<h1 id="heading-save-it-as-an-image">Save it as an Image!</h1>
<p>Chrome makes it <strong>SUPER</strong> easy to create an image from what you've made. Once you are happy with your design, you can right-click and inspect the <code>div</code> element to find it in the <code>Chrome Dev Tools Inspector</code>. Chrome gives you an option if you right click the div in the inspector to <code>Capture node screenshot</code>. This saves the div as it's rendered as a PNG image. Done!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1659630901759/0cDZx-wne.gif" alt="save.gif" class="image--center mx-auto" /></p>
<h1 id="heading-examples">Examples</h1>
<p>I created a second article dipping into this further, showing some more cool tricks you can use to create some really beautiful banners!</p>
<p><a target="_blank" href="https://blog.samdaryl.dev/create-beautiful-banners-and-other-graphics-easily-using-html-and-css-examples">Create Beautiful Banners and Other Graphics Easily Using HTML and CSS - Examples</a></p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>Use the tools you already know and a little trick in chrome to make your life easier 👍</p>
<p>I hope this helps you save time creating graphics to add a little flare to the content you create.</p>
<p>Follow me on <a target="_blank" href="https://twitter.com/SamDarylDev">Twitter</a> to keep up to date with my projects and get notified of new articles like this in the future!</p>
]]></content:encoded></item><item><title><![CDATA[Create a Reusable Button Component in React]]></title><description><![CDATA[Introduction
Following good practices allows you to write better code, React is no exception, and after writing button components for every project I have worked on, this is, in my opinion, the best approach for a reusable button component.

NOTE: Th...]]></description><link>https://blog.samdaryl.dev/create-a-reusable-button-component-in-react</link><guid isPermaLink="true">https://blog.samdaryl.dev/create-a-reusable-button-component-in-react</guid><category><![CDATA[React]]></category><category><![CDATA[TypeScript]]></category><category><![CDATA[react componets]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[button]]></category><dc:creator><![CDATA[Sam Phillips]]></dc:creator><pubDate>Wed, 03 Aug 2022 16:59:17 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1659539985905/ORtKHIz1z.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-introduction">Introduction</h1>
<p>Following good practices allows you to write better code, React is no exception, and after writing button components for every project I have worked on, this is, in my opinion, the best approach for a reusable button component.</p>
<blockquote>
<p>NOTE: The examples below are written in TypeScript. If you don't use Typescript, it's easy to get started, alternatively simply ignore any <code>type</code> definitions, <code>: string</code> notations after variables, and anything like <code>&lt;ButtonProps&gt;</code> etc.</p>
</blockquote>
<h2 id="heading-what-makes-a-react-component-perfectly-reusable">What makes a React component perfectly reusable</h2>
<ul>
<li>Having default styles to allow for quick prototyping</li>
<li>Styling should be completely configurable by its parent</li>
<li>Should have no dependencies, just drop in and go</li>
<li>Should use as few props as possible, to reduce complexity of use</li>
<li>Functionality should be split out, allowing for use only if needed</li>
</ul>
<p>So, let's start with a simple button component and work to satisfy these constraints.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">export</span> type ButtonProps = {
    <span class="hljs-attr">label</span>: string;
    onClick?: <span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">void</span>;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> Button: React.FC&lt;ButtonProps&gt; = <span class="hljs-function">(<span class="hljs-params">{ label, onClick }</span>) =&gt;</span> {
    <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{onClick}</span>&gt;</span>{label}<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>;
};
</code></pre>
<p>This renders something like this:
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1659524096418/YaL_V1fG1.png" alt="image.png" class="image--center mx-auto" /></p>
<p>Let's get rid of the base styles and add our own simple styles to make it consistent across browsers: </p>
<pre><code class="lang-css"><span class="hljs-selector-class">.button-compatibility-styles</span> {
    <span class="hljs-attribute">outline</span>: none;
    <span class="hljs-attribute">border</span>: none;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">0</span>;
    <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
    <span class="hljs-attribute">background</span>: none;
    <span class="hljs-attribute">fontSize</span>: <span class="hljs-number">1em</span>;
};
</code></pre>
<p>Now let's add some simple base styles in case none are provided:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.button-base-styles</span> {
    <span class="hljs-attribute">color</span>: black;
    <span class="hljs-attribute">background</span>: lightgray;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">0.4em</span> <span class="hljs-number">1em</span>;
    <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">0.2em</span>;
    <span class="hljs-attribute">cursor</span>: pointer;
}
</code></pre>
<p>And add them to our component:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> Button: React.FC&lt;ButtonProps&gt; = <span class="hljs-function">(<span class="hljs-params">{ label, onClick }</span>) =&gt;</span> {
    <span class="hljs-keyword">let</span> buttonClasses = [<span class="hljs-string">"button-compatibility-styles"</span>, <span class="hljs-string">"button-base-styles"</span>];

    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{buttonClasses.join(</span>" ")} <span class="hljs-attr">onClick</span>=<span class="hljs-string">{onClick}</span>&gt;</span>
            {label}
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
    );
};
</code></pre>
<p>This doesn't allow for overriding the base styles though, so let's add styles and <code>className</code> props, and conditionally apply it to our component, providing the base styles if none are supplied:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">export</span> type ButtonProps = {
    <span class="hljs-attr">label</span>: string;
    onClick?: <span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">void</span>;
    style?: string;
    className?: string;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> Button: React.FC&lt;ButtonProps&gt; = <span class="hljs-function">(<span class="hljs-params">{
    label,
    style,
    className,
    onClick
}</span>) =&gt;</span> {
    <span class="hljs-comment">// Always set the compatibility styles</span>
    <span class="hljs-keyword">let</span> buttonClasses = [<span class="hljs-string">"button-compatibility-styles"</span>];

    <span class="hljs-comment">// If className is provided, append it</span>
    <span class="hljs-keyword">if</span> (className) buttonClasses.push(className);

    <span class="hljs-comment">// If no styles are provided, provide base styles</span>
    <span class="hljs-keyword">if</span> (!style &amp;&amp; !className) buttonClasses.push(<span class="hljs-string">"button-base-styles"</span>);

    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span>
            <span class="hljs-attr">style</span>=<span class="hljs-string">{style}</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">{buttonClasses.join(</span>" ")}
            <span class="hljs-attr">onClick</span>=<span class="hljs-string">{onClick}</span>
        &gt;</span>
            {label}
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
    );
};
</code></pre>
<p>We provide the compatibility styles as a <strong>CSS class</strong>, because if we provided them as React style objects, they would not be able to be overridden by a parent component specifying <code>className</code>!</p>
<p>After all this setup, we have a button that looks about the same as before! 😂
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1659525667571/TqwT2b-6X.png" alt="image.png" class="image--center mx-auto" /></p>
<h1 id="heading-extra-functionality">Extra Functionality</h1>
<p>Now that we have our base button component, we can add extra functionality that is commonly needed from a button component. However, we want to enable this functionality only if it is specified by the parent component, and allow the parent to override its styling without affecting the rest of the button. We can do this using child components.</p>
<h2 id="heading-loading-spinner">Loading Spinner</h2>
<p>A loading spinner is a very common requirement for a button and allows for the user to show that something is happening.</p>
<p>A loading spinner should:</p>
<ul>
<li>Be visible once the user clicks the button</li>
<li>Prevent the user from clicking the button whilst its shown</li>
<li>Not force the parent component to maintain the state of the loading spinner</li>
<li>Not have any dependencies to show the spinner</li>
</ul>
<p>To do this we need to create a component that renders the spinner:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.svg-loading-spinner</span> {
    <span class="hljs-attribute">width</span>: <span class="hljs-number">1em</span>;
    <span class="hljs-attribute">height</span>: <span class="hljs-number">1em</span>;
    <span class="hljs-attribute">position</span>: absolute;
    <span class="hljs-attribute">inset</span>: <span class="hljs-number">0</span>;
    <span class="hljs-attribute">margin</span>: auto;

    <span class="hljs-attribute">animation</span>: spin <span class="hljs-number">1s</span> linear infinite;
}
</code></pre>
<pre><code class="lang-jsx"><span class="hljs-keyword">export</span> type ButtonLoadingSpinnerProps = {
    style?: CSSProperties;
    className?: string;
    color?: string;
    backgroundColor?: string;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> ButtonLoadingSpinner: React.FC&lt;ButtonLoadingSpinnerProps&gt; = <span class="hljs-function">(<span class="hljs-params">{
    style,
    className,
    color,
    backgroundColor
}</span>) =&gt;</span> {
    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">svg</span>
            <span class="hljs-attr">style</span>=<span class="hljs-string">{style}</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">svg-loading-spinner</span> ${<span class="hljs-attr">className</span>}`}
            <span class="hljs-attr">viewBox</span>=<span class="hljs-string">"0 0 40 40"</span>
        &gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">circle</span>
                <span class="hljs-attr">cx</span>=<span class="hljs-string">"20"</span>
                <span class="hljs-attr">cy</span>=<span class="hljs-string">"20"</span>
                <span class="hljs-attr">r</span>=<span class="hljs-string">"16"</span>
                <span class="hljs-attr">fill</span>=<span class="hljs-string">"none"</span>
                <span class="hljs-attr">strokeWidth</span>=<span class="hljs-string">{6}</span>
                <span class="hljs-attr">stroke</span>=<span class="hljs-string">{backgroundColor</span> || "<span class="hljs-attr">darkgray</span>"}
            /&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">path</span>
                <span class="hljs-attr">d</span>=<span class="hljs-string">"M3,20 a1,1 0 0,0 34,0"</span>
                <span class="hljs-attr">fill</span>=<span class="hljs-string">"none"</span>
                <span class="hljs-attr">strokeWidth</span>=<span class="hljs-string">{6}</span>
                <span class="hljs-attr">stroke</span>=<span class="hljs-string">{color</span> || "<span class="hljs-attr">black</span>"}
            /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">svg</span>&gt;</span></span>
    );
};
</code></pre>
<p>This is a simple SVG that is spins via a simple CSS animation. It also allows for the parent to override its <code>style</code>, <code>className</code>, <code>color</code>, and <code>backgroundColor</code>.</p>
<h1 id="heading-putting-it-all-together">Putting it all together</h1>
<p>Now we just need to provide the component to our <code>Button</code> component, and render it accordingly. We need to do this in a way that facilitates a loading state so its only shown when clicked. BUT:</p>
<ul>
<li>Should use as few props as possible, to reduce complexity of use</li>
</ul>
<p>We could create a <code>loading</code> prop, and have the parent implement a loading state, but from my experience, this is always used in the same manner, so instead, we are going to extend the <code>Button</code> to dynamically switch to a loading state internally if a loading component is provided, and the onClick returns a promise! 🔥</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">export</span> type ButtonProps = {
    <span class="hljs-attr">label</span>: string;
    onClick?: <span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">void</span> | <span class="hljs-built_in">Promise</span>&lt;<span class="hljs-keyword">void</span>&gt;;
    style?: CSSProperties;
    className?: string;
    loadingComponent?: React.ReactNode;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> Button: React.FC&lt;ButtonProps&gt; = <span class="hljs-function">(<span class="hljs-params">{
    label,
    loadingComponent,
    style,
    className,
    onClick
}</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> [loading, setLoading] = useState&lt;boolean&gt;(<span class="hljs-literal">false</span>);

    <span class="hljs-comment">// Always set the compatibility styles</span>
    <span class="hljs-keyword">let</span> buttonClasses = [<span class="hljs-string">"compatibility-styles"</span>];

    <span class="hljs-comment">// If className is provided, append it</span>
    <span class="hljs-keyword">if</span> (className) buttonClasses.push(className);

    <span class="hljs-comment">// If no styles are provided, provide base styles</span>
    <span class="hljs-keyword">if</span> (!style &amp;&amp; !className) buttonClasses.push(<span class="hljs-string">"base-styles"</span>);

    <span class="hljs-keyword">const</span> onClickInternal = <span class="hljs-keyword">async</span> () =&gt; {
        <span class="hljs-keyword">if</span> (!onClick || loading) <span class="hljs-keyword">return</span>;

        <span class="hljs-keyword">const</span> prom = onClick();
        <span class="hljs-keyword">if</span> (prom &amp;&amp; loadingComponent) {
            setLoading(<span class="hljs-literal">true</span>);
            <span class="hljs-keyword">await</span> prom;
            setLoading(<span class="hljs-literal">false</span>);
        }
    };

    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span>
            <span class="hljs-attr">style</span>=<span class="hljs-string">{style}</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">{buttonClasses.join(</span>" ")}
            <span class="hljs-attr">onClick</span>=<span class="hljs-string">{onClickInternal}</span>
        &gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">visibility:</span> <span class="hljs-attr">loading</span> ? "<span class="hljs-attr">hidden</span>" <span class="hljs-attr">:</span> "<span class="hljs-attr">visible</span>" }}&gt;</span>
                {label}
            <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
            {loading &amp;&amp; loadingComponent}
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
    );
};
</code></pre>
<p>Here we have added a <code>loadingComponent</code> prop and wrapped the <code>label</code> in <code>&lt;span&gt;</code>. This lets us toggle its visibility based on our new <code>loading</code> state <code>boolean</code>. We also conditionally show the <code>loadingComponent</code> only if <code>loading</code> is <code>true</code>.</p>
<p>We also added a check that <code>returns</code> when calling <code>onClickInternal</code> if we are already in a <code>loading</code> state, preventing clicks whilst it's loading.</p>
<p>We have also added <code>onClickInternal</code> which wraps the provided <code>onClick</code> prop. If we have <code>onClick</code>, we call it. If it is an <code>async</code> function and it returned a <code>Promise</code>, and we have a <code>loadingComponent</code>, we set <code>loading</code> to <code>true</code>, <code>await</code> the <code>Promise</code>, and finally set <code>loading</code> to <code>false</code> again.</p>
<h1 id="heading-lets-test-it">Let's test it!</h1>
<p>Just defining the button:</p>
<pre><code class="lang-jsx">&lt;Button label=<span class="hljs-string">"My Button"</span> /&gt;
</code></pre>
<p>Gives us:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1659537420712/an9yu7msV.png" alt="image.png" class="image--center mx-auto" /></p>
<p>As we might expect. Let's try providing the loading spinner, and an <code>async onClick</code> that resolves after 2 seconds:</p>
<pre><code class="lang-jsx"> &lt;Button
    label=<span class="hljs-string">"My Button"</span>
    onClick={<span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">res</span>) =&gt;</span> <span class="hljs-built_in">setTimeout</span>(res, <span class="hljs-number">2000</span>))}
    loadingComponent={<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ButtonLoadingSpinner</span> /&gt;</span></span>}
/&gt;
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1659537845489/FkpFfuRg_.gif" alt="button.gif" class="image--center mx-auto" /></p>
<p>Great! Looks like its working nicely, and most importantly:</p>
<ul>
<li>All styles can be overridden to create any button we like, including the <code>ButtonLoadingSpinner</code></li>
<li>The <code>ButtonLoadingSpinner</code> can be completely replaced with a completely different indicator if needed</li>
<li>We are not requiring the parent component to needlessly manage any state</li>
<li>We are minimizing the props required to perform the expected functionality</li>
</ul>
<p>Lastly, let's add a little style to the button and jazz it up a bit:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">button</span><span class="hljs-selector-class">.my-custom-button</span> {
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">0.4rem</span> <span class="hljs-number">0.8rem</span>;
    <span class="hljs-attribute">font-weight</span>: bold;
    <span class="hljs-attribute">background-color</span>: lightblue;
    <span class="hljs-attribute">color</span>: <span class="hljs-number">#424242</span>;
    <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">4px</span>;
    <span class="hljs-attribute">cursor</span>: pointer;

    <span class="hljs-attribute">transition</span>: all <span class="hljs-number">0.2s</span> linear;
}

<span class="hljs-selector-tag">button</span><span class="hljs-selector-class">.my-custom-button</span><span class="hljs-selector-pseudo">:hover</span> {
    <span class="hljs-attribute">background-color</span>: <span class="hljs-built_in">rgb</span>(<span class="hljs-number">109</span>, <span class="hljs-number">199</span>, <span class="hljs-number">230</span>);
    <span class="hljs-attribute">color</span>: <span class="hljs-number">#424242</span>;
    <span class="hljs-attribute">box-shadow</span>: <span class="hljs-number">0px</span> <span class="hljs-number">5px</span> <span class="hljs-number">8px</span> <span class="hljs-number">0px</span> <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.4</span>);
}
</code></pre>
<pre><code class="lang-jsx"> &lt;Button
    label=<span class="hljs-string">"My Button"</span>
    className=<span class="hljs-string">"my-custom-button"</span>
    onClick={<span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">res</span>) =&gt;</span> <span class="hljs-built_in">setTimeout</span>(res, <span class="hljs-number">2000</span>))}
    loadingComponent={
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ButtonLoadingSpinner</span>
            <span class="hljs-attr">color</span>=<span class="hljs-string">"#424242"</span>
            <span class="hljs-attr">backgroundColor</span>=<span class="hljs-string">"lightblue"</span>
        /&gt;</span></span>
    }
/&gt;
</code></pre>
<p>This produces:
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1659539403267/3WTZxktNV.gif" alt="space.gif" class="image--center mx-auto" /></p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>That's it! I hope this article helped you get a sense of how components can be made reusable in react.</p>
<p>Follow me on <a target="_blank" href="https://twitter.com/samdaryldev">Twitter</a> to keep up to date with my projects and get notified of new articles like this in the future!</p>
]]></content:encoded></item></channel></rss>