<?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[Ebugo writes]]></title><description><![CDATA[Ebugo writes]]></description><link>https://blog.ebugo.me</link><generator>RSS for Node</generator><lastBuildDate>Sun, 19 Apr 2026 14:31:36 GMT</lastBuildDate><atom:link href="https://blog.ebugo.me/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Forms that Work for Everyone (Screen Readers, Labels, Errors)]]></title><description><![CDATA[TLDR;
If you're building for the web and your forms don't work for everyone, they simply do not work. Designing forms to be inclusive is foundational for good UX and accessibility, and not just a nice-to-have feature.
Most of the time, we treat forms...]]></description><link>https://blog.ebugo.me/forms-that-work-for-everyone-screen-readers-labels-errors</link><guid isPermaLink="true">https://blog.ebugo.me/forms-that-work-for-everyone-screen-readers-labels-errors</guid><category><![CDATA[Web Development]]></category><category><![CDATA[Accessibility]]></category><category><![CDATA[forms]]></category><category><![CDATA[form validation]]></category><category><![CDATA[screen readers]]></category><category><![CDATA[ASSISTIVE TECHNOLGY]]></category><dc:creator><![CDATA[Gospel Chinyereugo]]></dc:creator><pubDate>Mon, 08 Sep 2025 04:22:42 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/YDe0nOZyLHI/upload/aac99ad4f9d7b4d853a13cdcc23c0f49.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-tldr"><strong>TLDR;</strong></h2>
<p>If you're building for the web and your forms don't work for everyone, they simply do not work. Designing forms to be inclusive is foundational for good UX and accessibility, and not just a nice-to-have feature.</p>
<p>Most of the time, we treat forms as a mere visual task. What do I mean?</p>
<p>We align fields nicely, slap a button on the end, and maybe even throw in a toast message for submission warnings/errors. But then we fail to think about users who navigate the web with screen readers or with just the keyboard. And even for most parts, we forget about the cognitive load*, or error recovery* of our users?</p>
<p>In this article, we’ll explore how to create forms that work for everyone, whether they use screen readers, assistive devices, or just keyboard navigation.</p>
<p>What we'll cover:</p>
<ul>
<li><p>Semantic HTML and structure.</p>
</li>
<li><p>The role of labels and descriptions.</p>
</li>
<li><p>Managing focus and keyboard flows.</p>
</li>
<li><p>Accessible error handling.</p>
</li>
<li><p>Live regions, validation feedback, and assistive technology considerations.</p>
</li>
</ul>
<p>Now, let’s get right to it! 😉</p>
<h2 id="heading-use-the-right-semantic-html-always">Use the Right Semantic HTML Always</h2>
<p>Always start with a solid base: HTML. I don’t even know how you’d want to survive without that! 😅</p>
<p>Avoid throwing in the div element all over the place. Do your best to use the right elements designed for form controls all the time.</p>
<p>For instance;</p>
<p>Instead of</p>
<pre><code class="lang-xml"><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>Email address<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">name</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">required</span> /&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">"clickHandler()"</span>&gt;</span>Subscribe<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>
</code></pre>
<p>Why not do?</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">onsubmit</span>=<span class="hljs-string">"handleSubmit(event)"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"email"</span>&gt;</span>Email address<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">required</span> /&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Subscribe<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
</code></pre>
<p>Why does this matter?</p>
<ul>
<li><p><code>&lt;label&gt;</code> explicitly ties text to an input.</p>
</li>
<li><p><code>&lt;input&gt;</code> is natively focusable and announced by screen readers.</p>
</li>
<li><p><code>&lt;button&gt;</code> has default keyboard interaction (Enter/Space), unlike a div.</p>
</li>
</ul>
<h2 id="heading-labels-are-non-negotiable-use-them">Labels Are Non-Negotiable, Use Them!</h2>
<p>Every input needs a visible and accessible label. Not just a placeholder text, and definitely not just ARIA attributes. A real, on-screen label.</p>
<p>For instance;</p>
<p>Instead of</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"tel"</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Phone number"</span> /&gt;</span>
</code></pre>
<p>Why not do?</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"phone"</span>&gt;</span>Phone number<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"phone"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"tel"</span> /&gt;</span>
</code></pre>
<p>This is because, Placeholders;</p>
<ul>
<li><p>disappear on focus,</p>
</li>
<li><p>are hard to read with low contrast,</p>
</li>
<li><p>are not announced as labels by many screen readers, and many more!</p>
</li>
</ul>
<p>If there’s any reason at all that’d make you want to use just placeholders for your inputs, for instance when the visual space is tight, then I suggest you consider other more intuitive ways of displaying your form labels. For example, you could consider using floating labels (like can be seen in MUI’s text field).</p>
<p>In all, always use a proper <code>&lt;label&gt;</code> under the hood.</p>
<h2 id="heading-grouping-and-context-in-forms-fieldset-vs-legend">Grouping and Context in Forms: <code>fieldset</code> vs <code>legend</code></h2>
<p>When you have related fields in your forms, like address, gender, or payment info, it’s always good practice to wrap them in a <code>&lt;fieldset&gt;</code> with a <code>&lt;legend&gt;</code>.</p>
<p>For instance;</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">fieldset</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">legend</span>&gt;</span>Payment Method<span class="hljs-tag">&lt;/<span class="hljs-name">legend</span>&gt;</span>

  <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"radio"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"payment"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"card"</span> /&gt;</span>
    Credit Card
  <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>

  <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"radio"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"payment"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"paypal"</span> /&gt;</span>
    PayPal
  <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">fieldset</span>&gt;</span>
</code></pre>
<p>This way, screen readers will announce the legend as context before reading out each input. This helps build comprehension, especially for users navigating by audio, and makes the user experience worthwhile.</p>
<h2 id="heading-keyboard-navigation-and-focus-management">Keyboard Navigation and Focus Management</h2>
<p>The order in which users navigate through form elements using the Tab key is very important for ensuring a smooth and intuitive experience. When designing forms, it's necessary to structure them so that the tab order follows a logical progression that mirrors the visual layout. This means arranging input fields, buttons, and other interactive elements in a sequence that users would naturally follow, thus allowing users to move efficiently from one part of the form to another without unnecessary jumps or confusion.</p>
<p>To achieve this, ensure that all interactive elements are included in the tabbing sequence and that the focus moves in a sensible direction, typically top to bottom and left to right (or right to left, as the case may be). Use HTML to properly arrange elements in the DOM, and avoid using CSS alone to change the visual order, as it can disrupt the natural tab flow. Additionally, use the <code>tabindex</code> attribute to control the focus order without overriding the default flow unless absolutely necessary.</p>
<p>Users who rely on keyboards should be able to move through the form linearly using <code>Tab</code>, <code>Shift + Tab</code>, <code>Enter</code>, and <code>Space</code>.</p>
<ul>
<li><p>Do NOT remove <code>outline</code> styles with CSS. If you must style them, replace them meaningfully.</p>
</li>
<li><p>Avoid <code>tabindex="0"</code> on non-focusable elements unless necessary.</p>
</li>
<li><p>Never use <code>tabindex</code> to "fake" tab order. It often breaks assistive technology.</p>
</li>
</ul>
<p>If you're building custom modals/dialogs/popups or dynamically-injected fields:</p>
<ul>
<li><p>Always trap focus within modals. Do not allow items outside of the modal to be focused on while the modal is still open and active.</p>
</li>
<li><p>Return focus to the trigger (modal opener) when the modal closes.</p>
</li>
<li><p>Auto-focus the first input responsibly.</p>
</li>
</ul>
<h2 id="heading-handling-errors-accessibly">Handling Errors Accessibly</h2>
<h3 id="heading-visual-feedback-isnt-enough">Visual Feedback Isn't Enough</h3>
<p>Red borders and inline error messages are helpful for sighted (and non-color blind) users, but not for screen reader users. We need to go further.</p>
<p>Use <code>aria-describedby</code> to associate error text with the input.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"username"</span>&gt;</span>Username<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"username"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"username"</span> <span class="hljs-attr">aria-describedby</span>=<span class="hljs-string">"username-error"</span> <span class="hljs-attr">required</span> /&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"username-error"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"error"</span>&gt;</span>Username is required<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
</code></pre>
<p>Screen readers will now announce the error message alongside the field when focus lands on it.</p>
<h3 id="heading-use-clear-language">Use Clear Language</h3>
<p>Avoid vague errors like:</p>
<ul>
<li><p>"Invalid input"</p>
</li>
<li><p>"Something went wrong"</p>
</li>
</ul>
<p>Instead, use:</p>
<ul>
<li><p>"Username must be at least 6 characters"</p>
</li>
<li><p>"Email address is required"</p>
</li>
</ul>
<p>Always be specific and human in your feedback. This way, your users get to easily understand what they’re doing wrong.</p>
<h2 id="heading-live-validation-feedback-with-aria">Live Validation Feedback (with ARIA)</h2>
<p>If you're validating fields on input or blur, notify users using ARIA live regions.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"password-feedback"</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"alert"</span> <span class="hljs-attr">aria-live</span>=<span class="hljs-string">"assertive"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Update this region dynamically when the validation state changes. This ensures that screen readers announce the changes as soon as they occur.</p>
<p>Also, while live regions are very useful, avoid overusing them as they can become noisy and overwhelming. Use them only when information must be passed across to the users in real time.</p>
<h2 id="heading-handling-custom-components">Handling Custom Components</h2>
<p>If you’re building your own form elements (eg; select dropdowns, date pickers, toggles, etc), you take on the responsibility of replicating all native behaviors.</p>
<p>For example:</p>
<ul>
<li><p>A custom select should be operable via keyboard</p>
</li>
<li><p>It should announce expanded/collapsed state</p>
</li>
<li><p>It must be focusable and labeled correctly</p>
</li>
</ul>
<p>This is not as easy as it looks. So, if you can, make use of native elements. Else, if you must go custom, then you need to study the WAI-ARIA (Web Accessibility Initiative - Accessible Rich Internet Applications) Authoring Practices Guide here: <a target="_blank" href="https://www.w3.org/WAI/ARIA/apg/">https://www.w3.org/WAI/ARIA/apg/</a></p>
<h2 id="heading-do-not-guess-test-with-screen-readers">Do not Guess. Test with Screen Readers :)</h2>
<p>The truth is that you’d never have any idea how your form behaves for 10 to 20% of your users if you’ve not tested your form with a screen reader.</p>
<p>You should try these out for a start:</p>
<ul>
<li><p>VoiceOver (Mac users): ⌘ + F5</p>
</li>
<li><p><a target="_blank" href="https://www.nvaccess.org/download/">NVDA screen reading software</a> (Windows users): Free, powerful, open-source</p>
</li>
<li><p><a target="_blank" href="https://support.freedomscientific.com/Downloads/JAWS">JAWS screen reading software</a> (Windows users): Industry-standard</p>
</li>
<li><p><a target="_blank" href="https://chromewebstore.google.com/detail/hnjkeajcokeekolbfiniekmanfidmkhd?utm_source=item-share-cb">Chrome VoX extension</a> (in-browser): Voice recognition tool for dictation</p>
</li>
</ul>
<p>Go through your form and answer these questions:</p>
<ul>
<li><p>Can you tell what each field is for?</p>
</li>
<li><p>Can you hear error messages?</p>
</li>
<li><p>Does it follow logical order?</p>
</li>
</ul>
<p>When you do this, you’ll most likely spot UX bugs that sighted users will never report.</p>
<h2 id="heading-in-conclusion"><strong>In Conclusion</strong></h2>
<p>It's very important for us to note that accessibility isn’t just about compliance. It’s about building with empathy and respect for the people behind the screens. When your forms work for everyone, your product becomes more usable, more inclusive, and ultimately more successful and useful.</p>
<blockquote>
<p>A form isn’t complete when it looks right. It’s only complete when it <em>feels</em> right for every user, on every device, and in every context.</p>
</blockquote>
<p>Let’s build better and more accessible UIs!</p>
<h2 id="heading-references-amp-further-reading">References <strong>&amp; Further Reading</strong></h2>
<ul>
<li><p><a target="_blank" href="https://www.w3.org/WAI/tutorials/forms/">W3C Forms Tutorial</a></p>
</li>
<li><p><a target="_blank" href="https://www.w3.org/WAI/ARIA/apg/">ARIA Authoring Practices Guide</a></p>
</li>
<li><p><a target="_blank" href="https://inclusive-components.design/">Inclusive Components – Forms</a></p>
</li>
<li><p><a target="_blank" href="https://design-system.service.gov.uk/patterns/">Gov.uk Design System – Forms</a></p>
</li>
<li><p><a target="_blank" href="https://www.smashingmagazine.com/2021/01/accessible-html-forms/">Smashing Magazine – Accessible Forms</a></p>
</li>
<li><p><a target="_blank" href="https://webaim.org/techniques/forms/">WebAIM – Form Accessibility</a></p>
</li>
<li><p><a target="_blank" href="https://mui.com/material-ui/react-text-field/">MUI Text Field</a> (example of floating label)</p>
</li>
</ul>
<p>* Cognitive load refers to the amount of mental effort being used in the working memory. When designing forms, it's crucial to consider how much information and how many tasks we are asking users to process at once. If a form is too complex or asks for too much information at once, it can overwhelm users, especially those with cognitive disabilities or those who are unfamiliar with the content. By paying attention to cognitive load, we can create forms that are not only more accessible but also more user-friendly for everyone.</p>
<p>* Error recovery is an essential aspect of form design that ensures users can easily correct mistakes and complete their tasks without frustration. When a user encounters an error, the form should clearly indicate what went wrong and provide guidance on how to fix it via error messages displayed near the field where the error occurred. Effective error recovery means creating a supportive and inclusive environment where all users, regardless of their abilities, can complete forms successfully and with ease.</p>
]]></content:encoded></item><item><title><![CDATA[Enhancing Accessibility: Why Focus Outlines Matter]]></title><description><![CDATA[Intro
You don’t have to disable the “Focus” outlines on your HTML elements. Yes, you heard me right. Your users deserve better and I’ll tell you why 😇.
This is a trap that is so so easy to fall into. I promise you I have done this a lot of times tha...]]></description><link>https://blog.ebugo.me/enhancing-accessibility-why-focus-outlines-matter</link><guid isPermaLink="true">https://blog.ebugo.me/enhancing-accessibility-why-focus-outlines-matter</guid><category><![CDATA[a11y]]></category><category><![CDATA[Accessibility]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[web]]></category><category><![CDATA[CSS]]></category><dc:creator><![CDATA[Gospel Chinyereugo]]></dc:creator><pubDate>Sat, 19 Jul 2025 10:04:38 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1752918163998/8beabfc2-8031-454c-af6f-218920c97a5a.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-intro">Intro</h2>
<p>You don’t have to disable the “Focus” outlines on your HTML elements. Yes, you heard me right. Your users deserve better and I’ll tell you why 😇.</p>
<p>This is a trap that is so so easy to fall into. I promise you I have done this a lot of times than I’m proud to announce, hahaha.</p>
<p>You’re wrapping up a UI, and making it as sleek and as pixel-perfect as ever, only for you to tab through the page and then you notice those ugly blue outlines appear. By default you just find yourself running to your global CSS file to add this style;</p>
<pre><code class="lang-css">*<span class="hljs-selector-pseudo">:focus</span> {
  <span class="hljs-attribute">outline</span>: none;
}
</code></pre>
<p>Problem solved? Nahhh, far from it. It isn’t just bad practice when you disable focus outlines. You end up excluding a lot of users from accessing your web app with ease.</p>
<p>In this article, we’ll get to understand why those button outlines matter, what happens when you remove them, and how to improve focus styles the right way.</p>
<h2 id="heading-what-are-focus-outlines-and-who-needs-them">What Are Focus Outlines and Who Needs Them?</h2>
<p>Focus outlines are visual indicators that show which element is currently in focus, typically when navigating a site with a keyboard (<code>tab</code>, <code>shift</code>+<code>tab</code>, etc.).</p>
<p>Usually, browsers show these outlines as dotted or solid blue rings around buttons or links with the main purpose of aiding accessibility (a11y) and showing when a button or link is focused on.</p>
<p>You may not use the <code>tab</code> key to move through a page, but millions of users do, for instance:</p>
<ul>
<li><p>Users with motor impairments who rely on keyboards or assistive switches.</p>
</li>
<li><p>Users with low vision who use screen magnifiers and need a visible target.</p>
</li>
<li><p>Power users who navigate faster with keyboard shortcuts.</p>
</li>
<li><p>Developers testing keyboard accessibility.</p>
</li>
</ul>
<p>When you remove focus outlines, you end up making your site unusable for these users.</p>
<h2 id="heading-the-damage-caused-by-outline-none-and-how-to-fix">The Damage Caused by <code>outline: none</code> and How to Fix</h2>
<p>When you hide focus outlines like this:</p>
<pre><code class="lang-css">*<span class="hljs-selector-pseudo">:focus</span> {
  <span class="hljs-attribute">outline</span>: none;
}
</code></pre>
<p>You end up creating an invisible barrier without knowing it, thus limiting the ability of your users to use your web app. For instance, users try to move through your interface with the <code>tab</code> key but can't see where they are. Imagine trying to fill out a form without knowing which field you are in. That's what the experience feels like when people are using your app.</p>
<p>Worthy to note also is that, taking away focus outlines without adding something else is an accessibility violation under <a target="_blank" href="https://www.w3.org/TR/WCAG21/#focus-visible">WCAG 2.1</a>. This could affect your users, harm your reputation, or even cause legal issues for your company.</p>
<p>You can also try to press the <code>tab</code> button repeatedly on your app to move through the UI, and confirm if you can see where the focus is.</p>
<p>Instead of taking off the focus ring entirely, or even just leaving the default focus ring, you can make it more elegant and accessible by applying custom styles.</p>
<p>Here’s the right approach:</p>
<h3 id="heading-1-customize-do-not-remove">1. <strong>Customize, Do NOT Remove</strong></h3>
<p>You can style the focus ring to match your brand without eliminating it:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">button</span><span class="hljs-selector-pseudo">:focus</span> {
  <span class="hljs-attribute">outline</span>: <span class="hljs-number">2px</span> solid <span class="hljs-built_in">var</span>(--brand-color);
  <span class="hljs-attribute">outline-offset</span>: <span class="hljs-number">2px</span>;
}
</code></pre>
<p>While doing this though, make sure it’s visible against your background and maintains at least a 3:1 contrast ratio.</p>
<h3 id="heading-2-use-focus-visible-for-smarter-styling">2. <strong>Use</strong> <code>:focus-visible</code> for Smarter Styling</h3>
<p>Modern browsers support <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible"><code>:focus-visible</code></a>, which is a property that distinguishes between mouse and keyboard focus.</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">button</span><span class="hljs-selector-pseudo">:focus</span> {
  <span class="hljs-attribute">outline</span>: none;
}

<span class="hljs-selector-tag">button</span><span class="hljs-selector-pseudo">:focus-visible</span> {
  <span class="hljs-attribute">outline</span>: <span class="hljs-number">2px</span> solid <span class="hljs-built_in">var</span>(--outline-color);
}
</code></pre>
<p>This means that mouse users won’t see the ring, but keyboard users will still get a clear focus style. It’s the best of both worlds.</p>
<p>PS: Don’t forget to add a fallback for browsers that don’t support <code>:focus-visible</code>. There’s also a <a target="_blank" href="https://github.com/WICG/focus-visible">polyfill</a> available if needed 🙂.</p>
<h2 id="heading-why-you-as-a-designerdeveloper-should-not-remove-it">Why You as a Designer/Developer Should Not Remove It</h2>
<p>Most designers and developers remove the default browser outline because it clashes with their custom design systems. But the hard truth is that it’s just a short-term visual fix with long-term usability costs.</p>
<p>On the other hand, a well-designed focus indicator would:</p>
<ul>
<li><p>Reinforce your brand.</p>
</li>
<li><p>Show attention to accessibility.</p>
</li>
<li><p>Make your interface more predictable.</p>
</li>
</ul>
<p>While working on your UI, you can cross-check these bullet points to ensure you’re on the right path:</p>
<ul>
<li><p>All interactive elements (buttons, links, form inputs) must show focus.</p>
</li>
<li><p>The focus indicator must be clearly visible on all backgrounds and themes.</p>
</li>
<li><p>You may use <code>:focus-visible</code> to conditionally show outlines for keyboard navigation.</p>
</li>
<li><p>Never hide focus styles globally.</p>
</li>
<li><p>Test keyboard navigation e2e before tagging any page as completed.</p>
</li>
</ul>
<h2 id="heading-using-utility-class-for-focus-styling">Using Utility Class for Focus Styling</h2>
<p>If you use Tailwind or similar utility-first CSS frameworks, you can define a reusable focus class:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.focus-ring</span> {
  <span class="hljs-attribute">outline</span>: <span class="hljs-number">2px</span> solid <span class="hljs-built_in">var</span>(--outline-color);
  <span class="hljs-attribute">outline-offset</span>: <span class="hljs-number">2px</span>;
}
</code></pre>
<p>Or with Tailwind directly:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"focus:outline-none focus-visible:outline focus-visible:outline-blue-500 focus-visible:outline-2 focus-visible:outline-offset-2"</span>&gt;</span>
  Submit
<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
</code></pre>
<h2 id="heading-in-conclusion">In Conclusion</h2>
<p>Don’t disable focus outlines just because they don’t match your brand. Create designs around them. Reinvent, customize, but never eliminate them. Always remember that how users use or are able to find their way around your web app is very important.</p>
<p>Focus indicators are lifelines for users who navigate differently from you, and their experience can be made good or bad by even a single line of CSS that you decide to add.</p>
<p>So the next time it crosses your mind to use <code>outline: none</code>, remember that it’s not just about the design. The experience of your users is key to building a great product!</p>
<h3 id="heading-references-amp-further-reading">References &amp; Further Reading</h3>
<ul>
<li><p><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible">MDN on :focus-visible</a></p>
</li>
<li><p><a target="_blank" href="https://www.w3.org/WAI/WCAG21/Understanding/focus-visible.html">WCAG 2.1 on Focus Visible</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Optimizing Images for Speed and Smarter Delivery]]></title><description><![CDATA[Intro
Images are often times the heaviest of assets on web pages, and ironically, they're also the most neglected in performance workflows.
We spend a lot of time cleaning up our code, fine-tuning our scripts, bundling our CSS, and taking part in lon...]]></description><link>https://blog.ebugo.me/optimizing-images-for-speed-and-smarter-delivery</link><guid isPermaLink="true">https://blog.ebugo.me/optimizing-images-for-speed-and-smarter-delivery</guid><category><![CDATA[Web Development]]></category><category><![CDATA[web]]></category><category><![CDATA[optimization]]></category><category><![CDATA[images]]></category><category><![CDATA[image optimization ]]></category><dc:creator><![CDATA[Gospel Chinyereugo]]></dc:creator><pubDate>Tue, 15 Jul 2025 18:15:23 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1752318824263/c4b728c1-8a9a-4eee-8426-475a9060f185.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-intro">Intro</h2>
<p>Images are often times the heaviest of assets on web pages, and ironically, they're also the most neglected in performance workflows.</p>
<p>We spend a lot of time cleaning up our code, fine-tuning our scripts, bundling our CSS, and taking part in long debates about web rendering strategies but overlook the kilobytes (and in so many cases, megabytes) hiding in oversized jpegs or unnecessary image requests. If you're serious about Core Web Vitals, good user experience, and real-world performance, image optimization has to be a core part of your frontend workflow.</p>
<p>In this post, I’ll walk you through modern image optimization techniques majorly in these areas:</p>
<ul>
<li><p>Next-gen formats like AV1 Image File Format (AVIF).</p>
</li>
<li><p>Lazy loading strategies (native and JavaScript-based).</p>
</li>
<li><p>Best practices for responsive image delivery.</p>
</li>
<li><p>CDN and tooling tips that actually move the needle.</p>
</li>
</ul>
<h2 id="heading-why-does-image-optimization-matter">Why Does Image Optimization Matter?</h2>
<p>Let’s look at this from the numbers angle:</p>
<ul>
<li><p>Images account for approximately 50% of the total page weight on the average.</p>
</li>
<li><p>Poorly optimized images increase the time to Largest Contentful Paint (LCP).</p>
</li>
<li><p>They contribute heavily to Cumulative Layout Shift (CLS) if dimensions aren’t properly handled, as the pages will always tend to move once an iimage loads completely with it’s full dimensions.</p>
</li>
</ul>
<p>We don’t just save bytes each time we make sure that images are optimized on our web pages and apps. We directly affect the user experience (especially on slow networks), perceived load time and also the bounce rate and SEO of our web apps.</p>
<h2 id="heading-image-optimization-techniques">Image Optimization Techniques</h2>
<h3 id="heading-1-av1-image-file-format-avif">1. AV1 Image File Format (AVIF):</h3>
<p>AVIF is a modern image format that offers superior compression compared to JPEG, PNG, and even WebP. It’s based on the AV1 video codec, and it supports HDR, transparency, and animations.</p>
<p>AVIF is really great and gets the job done, as can be seen below;</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Format</strong></td><td><strong>Compression Efficiency</strong></td><td><strong>Transparency</strong></td><td><strong>Animation</strong></td><td><strong>Browser Support</strong></td></tr>
</thead>
<tbody>
<tr>
<td>JPEG</td><td>Good</td><td>❌</td><td>❌</td><td>✅</td></tr>
<tr>
<td>PNG</td><td>Poor</td><td>✅</td><td>❌</td><td>✅</td></tr>
<tr>
<td>WebP</td><td>Better</td><td>✅</td><td>✅</td><td>✅</td></tr>
<tr>
<td>AVIF</td><td>Excellent</td><td>✅</td><td>✅</td><td>✅ (modern browsers)</td></tr>
</tbody>
</table>
</div><p>On the average, AVIF reduces image size by 30 to 50% compared to WebP, and even more compared to JPEG, without any noticeable loss in quality.</p>
<h4 id="heading-how-to-use-avif-in-html">How to Use AVIF in HTML</h4>
<p>Always use the <code>&lt;picture&gt;</code> element for graceful fallback to a more compatible image format:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">picture</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">source</span> <span class="hljs-attr">srcset</span>=<span class="hljs-string">"/assets/banner.avif"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"image/avif"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">source</span> <span class="hljs-attr">srcset</span>=<span class="hljs-string">"/assets/banner.webp"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"image/webp"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"/assets/banner.jpg"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"Banner"</span> <span class="hljs-attr">width</span>=<span class="hljs-string">"1200"</span> <span class="hljs-attr">height</span>=<span class="hljs-string">"600"</span> <span class="hljs-attr">loading</span>=<span class="hljs-string">"lazy"</span> <span class="hljs-attr">decoding</span>=<span class="hljs-string">"async"</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">picture</span>&gt;</span>
</code></pre>
<p>PS: Always include width and height to prevent CLS.</p>
<h3 id="heading-2-lazy-loading-images">2. Lazy Loading Images:</h3>
<p>The simplest way to defer offscreen images is by using the native <code>loading="lazy"</code> attribute in our html code. It helps us to load only what’s crucial and visible first.</p>
<p>Lazy loading is supported by all modern browsers (including Chrome, Edge, Firefox, Safari ≥16).</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"/assets/gallery1.jpg"</span> <span class="hljs-attr">loading</span>=<span class="hljs-string">"lazy"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"Gallery image"</span>&gt;</span>
</code></pre>
<h4 id="heading-when-to-use-javascript-based-lazy-loading">When to Use JavaScript-Based Lazy Loading</h4>
<p>If you need:</p>
<ul>
<li><p>Custom thresholds (e.g., preload 500px before viewport)</p>
</li>
<li><p>Fade-in animations on scroll</p>
</li>
<li><p>Compatibility with older browsers</p>
</li>
</ul>
<p>You can use the <code>IntersectionObserver</code> API:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> images = <span class="hljs-built_in">document</span>.querySelectorAll(<span class="hljs-string">'img[data-src]'</span>);

<span class="hljs-keyword">const</span> observer = <span class="hljs-keyword">new</span> IntersectionObserver(<span class="hljs-function">(<span class="hljs-params">entries, obs</span>) =&gt;</span> {
  entries.forEach(<span class="hljs-function"><span class="hljs-params">entry</span> =&gt;</span> {
    <span class="hljs-keyword">if</span> (entry.isIntersecting) {
      <span class="hljs-keyword">const</span> img = entry.target;
      img.src = img.dataset.src;
      img.removeAttribute(<span class="hljs-string">'data-src'</span>);
      obs.unobserve(img);
    }
  });
}, {
  <span class="hljs-attr">rootMargin</span>: <span class="hljs-string">'200px'</span>
});

images.forEach(<span class="hljs-function"><span class="hljs-params">img</span> =&gt;</span> observer.observe(img));
</code></pre>
<p>PS: IntersectionObserver is not compatible on older broswers. You can check <a target="_blank" href="https://caniuse.com/intersectionobserver">here on caniuse</a>.</p>
<p>Also worthy of note;</p>
<p>You can also set the <code>decoding</code> attribute of the image tag to “async”. It helps reduce render-blocking assets and improve paint times, by telling the browser to decode images asynchronously.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"..."</span> <span class="hljs-attr">decoding</span>=<span class="hljs-string">"async"</span> <span class="hljs-attr">loading</span>=<span class="hljs-string">"lazy"</span> /&gt;</span>
</code></pre>
<h3 id="heading-3-serving-responsive-images">3. Serving Responsive Images</h3>
<p>Alternatively, you can also use <code>srcset</code> and <code>sizes</code> to deliver images of different formats/quality based on the screen width.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">img</span>
  <span class="hljs-attr">src</span>=<span class="hljs-string">"/images/photo.jpg"</span>
  <span class="hljs-attr">srcset</span>=<span class="hljs-string">"
    /images/photo-480w.avif 480w,
    /images/photo-800w.avif 800w,
    /images/photo-1200w.avif 1200w"</span>
  <span class="hljs-attr">sizes</span>=<span class="hljs-string">"(max-width: 600px) 480px, (max-width: 900px) 800px, 1200px"</span>
  <span class="hljs-attr">alt</span>=<span class="hljs-string">"Team photo"</span>
  <span class="hljs-attr">loading</span>=<span class="hljs-string">"lazy"</span>
  <span class="hljs-attr">decoding</span>=<span class="hljs-string">"async"</span>
/&gt;</span>
</code></pre>
<p>What happens is that the browser selects the best image based on device width and device pixel ratio (DPR). So, in essence, users on smaller or slower devices don’t download large unnecessary assets thus saving them a lot of time to fully load the page.</p>
<h3 id="heading-4-utilizing-a-content-delivery-network-cdn">4. Utilizing a Content Delivery Network (CDN)</h3>
<p>A Content Delivery Network, commonly referred to as a CDN, is an essential component in modern web development for optimizing the delivery of content to users. By distributing copies of your website's static assets, such as images, stylesheets, and scripts, across a network of geographically dispersed servers, a CDN significantly reduces the physical distance between the server and the user. This results in faster load times, as the data travels a shorter distance.</p>
<p>You should use a CDN that supports Image Transformation. Some popular options include;</p>
<ul>
<li><p>Cloudflare: Easy auto-resizing and AVIF support.</p>
</li>
<li><p>Vercel / Netlify (for Next.js/Gatsby projects): Built-in image optimization with AVIF + WebP fallback.</p>
</li>
<li><p>Cloudinary: Image and video APIs for fast and scalable media management.</p>
</li>
<li><p>Imgix: On-the-fly format conversion and smart cropping.</p>
</li>
<li><p>ImageKit: Real-time image resizing, global CDN.</p>
</li>
</ul>
<p>Example with ImageKit:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://domain.imagekit.io/your-id/image.jpg?tr=w-800,f-avif"</span> /&gt;</span>
</code></pre>
<h3 id="heading-5-dev-workflow-amp-tooling">5. Dev Workflow &amp; Tooling</h3>
<p>You can also use these tools to optimize your assets locally;</p>
<ul>
<li><p>Squoosh (<a target="_blank" href="https://squoosh.app">https://squoosh.app</a>): Great for manual optimization + AVIF/WebP conversion.</p>
</li>
<li><p>Sharp (Node.js): Useful in build scripts</p>
<pre><code class="lang-typescript">  <span class="hljs-keyword">import</span> sharp <span class="hljs-keyword">from</span> <span class="hljs-string">'sharp'</span>;
  sharp(<span class="hljs-string">'image.jpg'</span>)
    .resize(<span class="hljs-number">800</span>)
    .toFormat(<span class="hljs-string">'avif'</span>)
    .toFile(<span class="hljs-string">'image.avif'</span>);
</code></pre>
</li>
<li><p>Next.js <code>&lt;Image /&gt;</code> component: This handles all your AVIF/WebP conversion, resizing, lazy loading, out of the box! Also, you can install <code>sharp</code> and Nextjs will automatically use it to optimize your images during build.</p>
</li>
</ul>
<h3 id="heading-6-accessibility-amp-seo-considerations">6. Accessibility &amp; SEO Considerations</h3>
<p>Most importantly, let’s not forget our SEO and a11y considerations:</p>
<ul>
<li><p>Always add width/height attributes or use aspect-ratio containers to prevent CLS.</p>
</li>
<li><p>Always add <code>alt</code> text for screen readers.</p>
</li>
<li><p>Use descriptive filenames (for instance, <code>company-logo.avif</code> vs <code>image1.avif</code>)</p>
</li>
</ul>
<h2 id="heading-in-conclusion">In Conclusion</h2>
<p>Image optimization is not just a "nice-to-have" as some may think. It is a foundational step in delivering fast, accessible, and exciting experiences to our users, especially for those on slow networks say in remote areas, or thise using mobile devices.</p>
<p>Whether you're working with static sites, SPAs, or full-blown server-rendered apps, getting your image strategy right will pay off in Core Web Vitals, SEO rankings, and real-world UX.</p>
<p>In summary, If you're not optimizing your images, you're leaving performance gains on the table!</p>
]]></content:encoded></item><item><title><![CDATA[Understanding The Core Web Vitals]]></title><description><![CDATA[As frontend developers, we don’t just care about features but we also care a whole lot about user experience. This is because it can get really frustrating to a user when a page looks so beautiful but behaves weirdly during user interaction like page...]]></description><link>https://blog.ebugo.me/understanding-the-core-web-vitals</link><guid isPermaLink="true">https://blog.ebugo.me/understanding-the-core-web-vitals</guid><category><![CDATA[FID]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[web]]></category><category><![CDATA[Core Web Vitals]]></category><category><![CDATA[CLS]]></category><category><![CDATA[LCP]]></category><dc:creator><![CDATA[Gospel Chinyereugo]]></dc:creator><pubDate>Sat, 12 Jul 2025 08:58:44 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/_Lnid7JAWFQ/upload/7b300e8165ae6d683ce6262c1aa52b91.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>As frontend developers, we don’t just care about features but we also care a whole lot about user experience. This is because it can get really frustrating to a user when a page looks so beautiful but behaves weirdly during user interaction like page scroll, responds late to user input, or animations don’t play smoothly. These micro-frustrations are what the Core Web Vitals (CWV) aim to measure and eliminate.</p>
<p>For instance, if you have ever wondered:</p>
<ul>
<li><p>Why is my Lighthouse score so low?</p>
</li>
<li><p>Why did Google Search Console flag my site for poor performance?</p>
</li>
<li><p>How do I actually fix the layout shift on my page?</p>
</li>
</ul>
<p>This article aims to break these all down for you, with real examples, and actionable tips. 😉</p>
<h2 id="heading-so-what-really-are-core-web-vitals">So, What Really Are Core Web Vitals?</h2>
<p>Core Web Vitals are important metrics that help us measure the user experience (UX) of a website or page, so we can have an idea of how good or bad the UX is. They focus on three main areas; loading performance, interactivity, and visual stability. These metrics help ensure that websites are fast, responsive, and visually stable for users.</p>
<p>They include:</p>
<ul>
<li><p>LCP (Largest Contentful Paint): this measures how fast the page takes to load.</p>
</li>
<li><p>FID (First Input Delay): this measures how quickly a page becomes interactive.</p>
</li>
<li><p>CLS (Cumulative Layout Shift): this measures the visual stability of a page.</p>
</li>
</ul>
<p>These metrics aren’t just random. They represent actual user pain points such as these for the cases above respectively:</p>
<ul>
<li><p><strong>LCP:</strong> “The page took too long to load”.</p>
</li>
<li><p><strong>FID:</strong> “I tapped on a button but nothing happened”.</p>
</li>
<li><p><strong>CLS:</strong> “The page layout keeps jumping/skipping”.</p>
</li>
</ul>
<h2 id="heading-and-why-do-they-matter">And, Why Do They Matter?</h2>
<ul>
<li><p><strong>Ranking factor:</strong> Google uses Core Web Vitals for Search Engine Optimization (SEO). Pages with low scores might rank lower.</p>
</li>
<li><p><strong>Perception:</strong> A page that "feels" fast performs better, even if it isn't technically faster.</p>
</li>
<li><p><strong>Retention &amp; UX:</strong> Poor scores means higher bounce rate, which also means a long list of users will most likely be lost.</p>
</li>
</ul>
<h2 id="heading-lets-go">Let’s Go!</h2>
<h3 id="heading-1-largest-contentful-paint-lcp">1. Largest Contentful Paint (LCP)</h3>
<p>LCP measures how long it takes for the biggest content element at the top of the page (like a main image, <code>&lt;h1&gt;</code>, or video thumbnail) to load completely.</p>
<p>To achieve a good LCP score, aim for under 2.5 seconds load time, measured at the 75th percentile across both mobile and desktop.</p>
<p>PS: It’s not when the page starts loading, but when it feels meaningfully loaded.</p>
<h4 id="heading-what-counts-as-contentful">What Counts as “Contentful”?:</h4>
<p>The largest visible element/tag within the viewport:</p>
<ul>
<li><p><code>&lt;img&gt;</code></p>
</li>
<li><p><code>&lt;video&gt;</code></p>
</li>
<li><p><code>&lt;h1&gt;</code> or any large text block</p>
</li>
<li><p>Background images via <code>url()</code> (excluding CSS gradients or pseudo-elements)</p>
</li>
</ul>
<p>For instance, if your homepage has a large hero image and title, and that image takes 4 seconds to appear due to render-blocking CSS or JS, your LCP is 4s. That is too slow to even imagine, for real.</p>
<h4 id="heading-how-to-improve-lcp">How to Improve LCP:</h4>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Issue</strong></td><td><strong>Fix</strong></td></tr>
</thead>
<tbody>
<tr>
<td>Slow server response (or Time to First Byte; TTFB)</td><td>Use Server-Side Rendering (SSR) or Edge rendering, CDN, HTTP/2</td></tr>
<tr>
<td>Unoptimized images</td><td>Serve WebP/AVIF, compress asset, set responsive <code>sizes</code></td></tr>
<tr>
<td>Render-blocking CSS/JS</td><td>Inline critical CSS, defer non-critical JS</td></tr>
<tr>
<td>Client-side hydration delay (can be seen in React/Next.js)</td><td>Use static/SSR for the top part of the page, load non-essential parts after hydration.</td></tr>
<tr>
<td>Too many web fonts</td><td>Use <code>font-display: swap</code>, preload key fonts</td></tr>
</tbody>
</table>
</div><h4 id="heading-tools-to-measure">Tools to Measure:</h4>
<ul>
<li><p>Chrome DevTools (LCP marker, under the Performance tab)</p>
</li>
<li><p>Lighthouse (Performance tab)</p>
</li>
<li><p>PageSpeed Insights</p>
</li>
<li><p>Web Vitals extension</p>
</li>
<li><p><code>web-vitals</code> npm package</p>
</li>
</ul>
<h3 id="heading-2-first-input-delay-fid">2. First Input Delay (FID)</h3>
<p>FID measures the time between user interaction and the browser responding.</p>
<ul>
<li><p>Applies to first interaction, for instance, tap, click, or keypress (excluding scroll).</p>
</li>
<li><p>It’s not about visual feedback. It’s about when the JavaScript event handler starts.</p>
</li>
</ul>
<p>To achieve a good FID score, aim for under 100 milliseconds.</p>
<h4 id="heading-why-does-it-matter">Why Does It Matter?:</h4>
<p>Just imagine that your page looks ready, but the JS thread is still blocked and parsing about 1mb of bundled code. Then a user taps the “Add to Cart” button but nothing happens for a full second.</p>
<p>Now that’s a really poor FID, which would in essence translate to poor UX.</p>
<h4 id="heading-how-to-improve-fid">How to Improve FID:</h4>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Issue</strong></td><td><strong>Fix</strong></td></tr>
</thead>
<tbody>
<tr>
<td>Long JavaScript tasks</td><td>Break tasks using <code>requestIdleCallback</code>, <code>setTimeout</code></td></tr>
<tr>
<td>Heavy main thread blocking tasks</td><td>Use Web Workers, reduce bundle size</td></tr>
<tr>
<td>Too much third-party JS</td><td>Defer or lazy-load scripts like analytics, chat widgets, and other non-essential scripts</td></tr>
<tr>
<td>Too many event listeners</td><td>Debounce listeners, use delegation</td></tr>
<tr>
<td>Large hydration window</td><td>Use progressive hydration, avoid blocking scripts during hydration</td></tr>
</tbody>
</table>
</div><h4 id="heading-tools-to-measure-1">Tools to Measure:</h4>
<p>FID can only be measured in real-world situations and is not available in lab tools like Lighthouse. To measure, use Real User Monitoring (RUM) tools designed to capture real-world user interactions and provide insights into how users experience your website, or Web Vitals API to track it in production.</p>
<h3 id="heading-3-cumulative-layout-shift-cls">3. Cumulative Layout Shift (CLS)</h3>
<p>CLS measures how much the page layout shifts during the entire lifespan of the page, especially while it’s still loading. It quantifies unexpected movement of elements.</p>
<p>For instance, think of:</p>
<ul>
<li><p>Images loading and pushing content down.</p>
</li>
<li><p>Ads injecting a weird space on a page.</p>
</li>
<li><p>Fonts swapping and resizing.</p>
</li>
</ul>
<p>To achieve a good CLS score, aim for under 0.1.</p>
<h4 id="heading-imagine-if">Imagine if:</h4>
<p>A user gets on a page with the intention of tapping a “Pay Now” button, but just before they tap the button, the page jumps because an image or banner loaded. And then, they accidentally click the “Subscribe to newsletter” button. As simple as it sounds, it is really bad and can even get worse!</p>
<h4 id="heading-how-to-fix-cls">How to Fix CLS:</h4>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Cause</strong></td><td><strong>Fix</strong></td></tr>
</thead>
<tbody>
<tr>
<td>Images without dimensions</td><td>Always set <code>width</code> and <code>height</code> or use aspect-ratio</td></tr>
<tr>
<td>Dynamic ads/content</td><td>Reserve space with CSS or skeleton loaders</td></tr>
<tr>
<td>Web fonts causing reflow</td><td>Use <code>font-display: swap</code>, preload fonts</td></tr>
<tr>
<td>Lazy loading above-the-fold content</td><td>Preload or use <code>priority</code> in Next.js <code>&lt;Image&gt;</code></td></tr>
<tr>
<td>DOM injected banners/modals</td><td>Animate into reserved space or load off-screen</td></tr>
</tbody>
</table>
</div><h4 id="heading-cls-components">CLS Components:</h4>
<p>Cumulative Layout Shift is calculated as the sum of all layout shift scores that occur throughout the entire lifespan of a page. This metric is crucial for understanding how much the page layout changes unexpectedly while the page is loading or even after it has fully loaded.</p>
<p>To break it down further, a single shift score is determined by multiplying two factors: the impact fraction and the distance fraction.</p>
<ul>
<li><p>Impact fraction represents the portion of the viewport that is affected by the shift. For example, if the shift impacts 25% of the viewport, the impact fraction would be 0.25.</p>
</li>
<li><p>Distance fraction measures how far the elements on the page have moved relative to the viewport.</p>
</li>
</ul>
<p>Mathematically;</p>
<ul>
<li><p>CLS = sum of all layout shift scores.</p>
</li>
<li><p>A single shift score = impact fraction × distance fraction.</p>
</li>
</ul>
<p>By understanding and addressing these components, developers can effectively reduce CLS and improve user experience. It is important to ensure that all elements on a page load smoothly and predictably, minimizing any unexpected movements that could disrupt user interactions.</p>
<h2 id="heading-how-to-measure-core-web-vitals">How to Measure Core Web Vitals</h2>
<h4 id="heading-lab-tools-good-for-debugging">Lab Tools (Good for Debugging)</h4>
<ul>
<li><p>Chrome Lighthouse (DevTools)</p>
</li>
<li><p>WebPageTest</p>
</li>
<li><p>PageSpeed Insights</p>
</li>
<li><p>Lighthouse CI for CI/CD pipelines</p>
</li>
</ul>
<p>PS: I wrote about lighthouse <a target="_blank" href="https://blog.ebugo.me/using-lighthouse-to-audit-performance-and-a11y">here</a> and the DevTools <a target="_blank" href="https://blog.ebugo.me/mastering-chrome-devtools-for-frontend-development-and-debugging">here</a>.</p>
<h4 id="heading-field-tools-good-for-real-user-monitoring">Field Tools (Good for Real User Monitoring)</h4>
<ul>
<li><p>Core Web Vitals report in the Google Search Console.</p>
</li>
<li><p>Chrome UX Report (CrUX).</p>
</li>
<li><p>Web-vitals JS Library (<code>npm i web-vitals</code> or <code>yarn add web-vitals</code>).</p>
</li>
<li><p>Analytics tools: GA4, SpeedCurve, New Relic, Datadog, Vercel Analytics.</p>
</li>
</ul>
<h2 id="heading-cwv-in-frameworks-like-nextjs-react">CWV in Frameworks Like Next.js (React)</h2>
<p>If you’re using Next.js, you can measure Core Web Vitals natively with the <code>reportWebVitals</code> function llike this:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// _app.tsx</span>
<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">reportWebVitals</span>(<span class="hljs-params">metric</span>) </span>{
  <span class="hljs-keyword">if</span> (metric.name === <span class="hljs-string">'LCP'</span> || metric.name === <span class="hljs-string">'FID'</span> || metric.name === <span class="hljs-string">'CLS'</span>) {
    fetch(<span class="hljs-string">'/analytics'</span>, {
      method: <span class="hljs-string">'POST'</span>,
      body: <span class="hljs-built_in">JSON</span>.stringify(metric),
    });
  }
}
</code></pre>
<p>You can also hook this into your analytics or logging dashboard.</p>
<h2 id="heading-in-conclusion">In Conclusion</h2>
<p>As frontend developers, our job doesn’t stop at pushing pixel perfect screens. We are always tasked with delivering great user experiences, and have a very important role to play in user retention at any business we find ourselves in. If our pages shift, lag, or behave weirdly, users would always notice and would be scared away.</p>
<p>So let’s stop guessing and start measuring! Let’s build fast, ship smooth, and think like our users always.</p>
<p>It’s customer first! 😇💪</p>
<h3 id="heading-references-amp-further-reading">References &amp; Further Reading</h3>
<ul>
<li><p><a target="_blank" href="https://blog.ebugo.me/mastering-chrome-devtools-for-frontend-development-and-debugging">Mastering Chrome DevTools for Frontend Development and Debugging</a></p>
</li>
<li><p><a target="_blank" href="https://blog.ebugo.me/using-lighthouse-to-audit-performance-and-a11y">Using Lighthouse to Audit Performance &amp; A11y</a></p>
</li>
<li><p><a target="_blank" href="https://web.dev/articles/vitals">Web Vitals</a></p>
</li>
<li><p><a target="_blank" href="https://web.dev/articles/cls">Cumulative Layout Shift (CLS)</a></p>
</li>
<li><p><a target="_blank" href="https://developers.google.com/search/docs/monitor-debug/search-console-start">Get started with Google Search Console</a></p>
</li>
<li><p><a target="_blank" href="https://pagespeed.web.dev/">PageSpeed Insights</a></p>
</li>
<li><p><a target="_blank" href="https://github.com/GoogleChrome/web-vitals">web-vitals JS package</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Using Lighthouse to Audit Performance & A11y]]></title><description><![CDATA[When building for the web, you’re not just writing code that looks good, you’re building experiences which can be good or poor.
You want your user experiences (UX) to be fast, accessible, and reliable though. Hence, the need for tools like Lighthouse...]]></description><link>https://blog.ebugo.me/using-lighthouse-to-audit-performance-and-a11y</link><guid isPermaLink="true">https://blog.ebugo.me/using-lighthouse-to-audit-performance-and-a11y</guid><category><![CDATA[Lighthouse]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[web]]></category><category><![CDATA[audit]]></category><category><![CDATA[debugging]]></category><dc:creator><![CDATA[Gospel Chinyereugo]]></dc:creator><pubDate>Mon, 07 Jul 2025 16:07:33 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1751883534089/bad7a99e-6f3e-4a47-8f9d-a41ed5eef9b5.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When building for the web, you’re not just writing code that looks good, you’re building experiences which can be good or poor.</p>
<p>You want your user experiences (UX) to be fast, accessible, and reliable though. Hence, the need for tools like <strong>Lighthouse</strong>. Whether you're refining your Core Web Vitals or ensuring your product is usable by everyone (including those relying on screen readers or keyboard navigation), Lighthouse is a developer’s flashlight into the dark corners of user experience.</p>
<h2 id="heading-what-then-is-lighthouse">What then is Lighthouse?</h2>
<p>Lighthouse is an open-source auditing tool built to help you automated tool to help you improve the quality of your web apps. It lets you run tests against any webpage at all, and returns a detailed report with scores on:</p>
<ul>
<li><p>Performance</p>
</li>
<li><p>Accessibility (A11y)</p>
</li>
<li><p>Best Practices</p>
</li>
<li><p>SEO</p>
</li>
<li><p>Progressive Web App (PWA) readiness</p>
</li>
</ul>
<p>Each section gives a numeric score out of 100, but more importantly, it tells you <em>why</em> something is lacking and how to fix it.</p>
<p>Lighthouse can be run in the Chrome DevTools, as a node module, or from the command line. Let’s check them out;</p>
<h4 id="heading-1-chrome-devtools">1: Chrome DevTools</h4>
<ul>
<li><p>Navigate to your site in Google Chrome browser.</p>
</li>
<li><p>Right-click on anywhere on the page, and then click on “Inspect”. Click on the “<strong>Lighthouse”</strong> tab at the top panel.</p>
</li>
<li><p>Choose the categories you want to audit the site in. This could be performance, accessibility, best practices and/or SEO.</p>
</li>
<li><p>Click "<strong>Analyze page load</strong>” button.</p>
</li>
<li><p>Wait a few seconds for the analysis to complete, and then check out your full report.</p>
</li>
</ul>
<h4 id="heading-2-command-line">2: Command Line</h4>
<p>If you want more control or to automate audits, you can use:</p>
<pre><code class="lang-bash">npm install -g lighthouse
lighthouse https://your-site.com --view
</code></pre>
<p>This gives you a local HTML report in your browser which you can then proceed to review.</p>
<h2 id="heading-auditing-performance-with-lighthouse">Auditing Performance with Lighthouse</h2>
<p>Performance isn’t just about speed. It’s also about interactivity. Lighthouse looks at metrics like:</p>
<ul>
<li><p><strong>First Contentful Paint (FCP)</strong> – how fast the first element shows.</p>
</li>
<li><p><strong>Largest Contentful Paint (LCP)</strong> – how quickly the main content loads.</p>
</li>
<li><p><strong>Time to Interactive (TTI)</strong> – how long it takes before the page responds to user input.</p>
</li>
<li><p><strong>Total Blocking Time (TBT)</strong> – the length of time the page is unresponsive due to heavy JS.</p>
</li>
<li><p><strong>Cumulative Layout Shift (CLS)</strong> – how visually stable the page is.</p>
</li>
</ul>
<h3 id="heading-common-fixes">Common Fixes:</h3>
<ul>
<li><p>Compress and lazy-load assets like images, gifs, videos, etc.</p>
</li>
<li><p>Minify CSS and JS files.</p>
</li>
<li><p>Use a Content Delivery Network (CDN) to store and fetch assets.</p>
</li>
<li><p>Code-split your bundles.</p>
</li>
<li><p>Preload only assets that are critical to the page functionality</p>
</li>
</ul>
<p>Lighthouse runs its audits against the current page and then opens up the results of the report in the DevTool tab. These results come with recommendations/suggestions which would go a long way to help you rank up the scores. Take note of each report and fix in your codebase, one at a time.</p>
<h2 id="heading-auditing-accessibility-a11y-with-lighthouse">Auditing Accessibility (A11y) with Lighthouse</h2>
<p>The importance of accessibility (or A11y), a very important pillar in frontend development, is so commonly overlooked by a lot of engineers today. Yet, it’s one of the most critical things to factor in when building for great UX.</p>
<p>Lighthouse helps us run checks to answer questions like:</p>
<ul>
<li><p>Are buttons and links labeled?</p>
</li>
<li><p>Do images have <code>alt</code> text?</p>
</li>
<li><p>Is the contrast ratio sufficient?</p>
</li>
<li><p>Can the page be navigated with a keyboard?</p>
</li>
<li><p>Are ARIA (Accessible Rich Internet Applications) roles properly used?</p>
</li>
</ul>
<p>These aren’t just technical checkboxes but are properties that when not properly checked, can directly impact the experience of users with disabilities.</p>
<h3 id="heading-recommended-workflow">Recommended Workflow:</h3>
<p>To maximize Lighthouse, you can follow these steps;</p>
<ol>
<li><p>Run a Lighthouse audit on <strong>Accessibility</strong> for a start.</p>
</li>
<li><p>Fix low-hanging issues like color contrast or missing labels.</p>
</li>
<li><p>Use <strong>tab navigation</strong> to test the keyboard navigation flow.</p>
</li>
<li><p>Run a screen reader (like VoiceOver or NVDA if you have access to one) to simulate non-visual access.</p>
</li>
<li><p>Re-run Lighthouse and aim for a 90+ score.</p>
</li>
</ol>
<p>PS: Passing Lighthouse doesn’t mean your site is fully accessible, it’s just a starting point. Always test manually as it matters a lot.</p>
<h2 id="heading-integrating-lighthouse-into-your-dev-process">Integrating Lighthouse Into Your Dev Process</h2>
<p>If you’re building at scale or on a team, then you should do these:</p>
<ul>
<li><p><strong>CI Integration</strong>: Use Lighthouse CI to catch regressions during builds.</p>
</li>
<li><p><strong>Custom Configs</strong>: Tailor Lighthouse runs with custom configs to align with your team’s goals.</p>
</li>
<li><p><strong>Performance Budgets</strong>: Set performance thresholds and fail builds that exceed them.</p>
</li>
</ul>
<h2 id="heading-in-conclusion">In Conclusion</h2>
<p>Lighthouse isn’t just a tool. It goes a long way to help you spot real issues, track progress, and build empathy for anyone using your site. It always has a way to force you to think about quality across the board in any page/site you’re building by giving really helpful recommendations.</p>
<p>Do not fail to also test manually to ensure your users always have a great experience!</p>
<h3 id="heading-references-amp-further-reading">References &amp; Further Reading</h3>
<ul>
<li><p><a target="_blank" href="https://developer.chrome.com/docs/lighthouse/overview/">Lighthouse on Chrome DevTools Docs</a></p>
</li>
<li><p><a target="_blank" href="https://web.dev/measure/">Google Web.dev: Measure Performance</a></p>
</li>
<li><p><a target="_blank" href="https://accessibilityinsights.io/">Accessibility Insights Developer Tools</a></p>
</li>
<li><p><a target="_blank" href="https://github.com/GoogleChrome/lighthouse-ci">Using Lighthouse CI</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Mastering Chrome DevTools for Frontend Development and Debugging]]></title><description><![CDATA[If you’re building anything on the web and not using your browser’s developer tools, then you might as well be running blindly. I think this way because the dev tools are there to help with developers’ experience, and make it so easy to find a bug an...]]></description><link>https://blog.ebugo.me/mastering-chrome-devtools-for-frontend-development-and-debugging</link><guid isPermaLink="true">https://blog.ebugo.me/mastering-chrome-devtools-for-frontend-development-and-debugging</guid><category><![CDATA[Web Development]]></category><category><![CDATA[web]]></category><category><![CDATA[#chrome_devtools]]></category><category><![CDATA[devtools]]></category><category><![CDATA[debugging]]></category><dc:creator><![CDATA[Gospel Chinyereugo]]></dc:creator><pubDate>Mon, 07 Jul 2025 16:06:15 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/KrYbarbAx5s/upload/7a51ec593525fa24685cf3ae2643a004.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you’re building anything on the web and not using your browser’s developer tools, then you might as well be running blindly. I think this way because the dev tools are there to help with developers’ experience, and make it so easy to find a bug and nip it from its root source.</p>
<p>In this article I’d be speaking mainly to the Chrome DevTools as it’s my favorite and go to anytime anyday! I love the Chrome DevTools because it has a lot of potential, and as you may also have observed, gets new features so much frequently than a lot of, if not all, other browsers.</p>
<p>Over time, with more than half a decade spent on building responsive and intuitive web applications, I’ve come to rely a lot on Chrome DevTools not just to inspect elements or observe warnings and errors in the console, but to really debug logical flows, styles and performance of my apps. Whether it’s an element that just refuses to center or a page that overflows or behaves weirdly during scroll, DevTools has the answers you need if you know where to look.</p>
<p>I will do my best to break down how I use Chrome DevTools to debug my projects from a real-world developer’s lens.</p>
<h2 id="heading-debugging-styles-the-element-panel-is-your-best-friend">Debugging Styles?: The Element Panel is Your Best Friend</h2>
<p>Let’s say I’m working on a page and the layout breaks, or something just seems off. The “Elements” panel is my first stop.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751690106580/d1b5793d-8fbf-4910-b071-d3b60966eb66.png" alt class="image--center mx-auto" /></p>
<ol>
<li><h4 id="heading-inspect-the-dom">Inspect the DOM</h4>
</li>
</ol>
<ul>
<li><p>Right-click any part of the UI and then click on <code>Inspect</code>.</p>
</li>
<li><p>Make sure you’re in the Elements tab in the developer tools section.</p>
</li>
<li><p>You should see a live view of the DOM with the ability to expand and collapse nodes, like your JSX or HTML, depending on what you’re building with.</p>
</li>
</ul>
<ol start="2">
<li><h4 id="heading-style-live-editing">Style Live-Editing</h4>
</li>
</ol>
<ul>
<li><p>Just below or on the right of the Elements tab (depending on how your dev tools is aligned), under the <strong>"Styles"</strong> tab, you can:</p>
<ul>
<li><p>View <strong>applied CSS</strong>, <strong>inherited rules</strong>, and <strong>overridden styles</strong> (crossed out).</p>
</li>
<li><p>Directly <strong>edit styles</strong>, <strong>toggle declarations</strong>, or <strong>add new rules</strong> and see their effects play out in real time.</p>
</li>
</ul>
</li>
<li><p>Hover over any property in the DevTools, and you’d see <strong>visual guides</strong> like padding, margins, etc., in real-time on the page.</p>
</li>
</ul>
<ol start="3">
<li><h4 id="heading-box-model-visualizer">Box Model Visualizer</h4>
</li>
</ol>
<ul>
<li><p>Scroll to the bottom of the Styles tab, and you’d see the <strong>Box Model</strong>. It gives you access to a visual breakdown of the margin, border, padding, and content dimensions.</p>
</li>
<li><p>Also, hovering over each part of the box model shows you visual guides on the page in real time.</p>
</li>
<li><p>this helps me quickly spot issues with spacing or overflow.</p>
</li>
</ul>
<ol start="4">
<li><h4 id="heading-computed-styles">Computed Styles</h4>
</li>
</ol>
<ul>
<li><p>Most of the time, styles are deeply nested or dynamically applied, hence “computed”.</p>
</li>
<li><p>This "Computed" tab shows the final rendered value for every CSS property and is great for confirming what’s actually being used in rendering the components.</p>
</li>
</ul>
<h2 id="heading-debugging-performance-the-lighthouse-and-performance-tabs">Debugging Performance?: The Lighthouse and Performance Tabs</h2>
<p>Now, if your app feels sluggish or slow, it’s time to switch gears and speed things up!</p>
<ol>
<li><h4 id="heading-run-a-lighthouse-report">Run a Lighthouse Report</h4>
</li>
</ol>
<p>Start with an audit:</p>
<ul>
<li><p>Open the DevTools and go to the “Lighthouse” tab.</p>
</li>
<li><p>Generate a report for <strong>performance, accessibility, best practices,</strong> and <strong>SEO</strong> categories by clicking on the “Analyze page load” button.</p>
</li>
<li><p>It would give you a quick snapshot of the following metrics:</p>
<ul>
<li><p>First Contentful Paint (FCP)</p>
</li>
<li><p>Largest Contentful Paint (LCP)</p>
</li>
<li><p>Total Blocking Time (TBT)</p>
</li>
<li><p>Cumulative Layout Shift (CLS)</p>
</li>
<li><p>Speed Index (SI)</p>
</li>
</ul>
</li>
<li><p>Also, you’d get insights on how to optimize for these:</p>
<ul>
<li><p>Time to Interactivity</p>
</li>
<li><p>Javascripts minification</p>
</li>
<li><p>Unused JavaScript or CSS</p>
</li>
<li><p>Image optimization tips</p>
</li>
<li><p>Third party usage</p>
</li>
</ul>
</li>
</ul>
<p>This isn’t just about scores. I use it to find low-hanging fruits that I can touch up easily to help speed up my UI and give better experiences to my users.</p>
<ol start="2">
<li><h4 id="heading-record-a-performance-trace">Record a Performance Trace</h4>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751639653899/224dbdf4-9860-4124-ac1a-7a67a151521d.png" alt class="image--center mx-auto" /></p>
</li>
</ol>
<p>For more indepth debugging, you’d need to:</p>
<ul>
<li><p>Click on the “Performance” tab.</p>
</li>
<li><p>Then, click <strong>Record</strong>, interact with your page, and then <strong>stop recording</strong>.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751639947459/b51015d5-4f09-4067-a7ba-e3592808e814.png" alt class="image--center mx-auto" /></p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751640050507/052add1c-2672-436d-bf63-5be0b43a3941.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>You’ll get a <strong>frame-by-frame timeline</strong> of the following:</p>
<ul>
<li><p>Scripting, rendering, painting activities</p>
</li>
<li><p><strong>Long tasks</strong> (usually caused by expensive JS execution)</p>
</li>
<li><p><strong>FPS (frames per second)</strong> and dropped frames</p>
</li>
</ul>
</li>
</ul>
<p>This helps me track down why a button takes 2 seconds to respond or why animations feel broken.</p>
<p>You can also control the <strong>Environment settings</strong> such as the CPU and network speed just to test for those scenarios.</p>
<ol start="3">
<li><h4 id="heading-layout-shift-debugging">Layout Shift Debugging</h4>
</li>
</ol>
<p>Want to check if things jump around while loading?</p>
<ul>
<li><p>The <strong>Performance tab</strong> highlights <strong>Cumulative Layout Shifts (CLS)</strong>.</p>
</li>
<li><p>You’ll literally see when and where a layout reflow happened.</p>
</li>
</ul>
<h2 id="heading-other-tools-i-also-use-frequently">Other Tools I Also Use Frequently</h2>
<ul>
<li><p><strong>Network tab</strong>: Here, you can check what’s loading, what’s slow, what’s failing, etc. You can filter the network requests by a couple of flags like <strong>Fetch/XHR</strong> requests, <strong>CSS</strong>, <strong>JS</strong>, <strong>Font</strong>, etc. I also throttle the network speed so as to test how my app performs on slower network speeds.</p>
<p>  Another thing I also do is to enable the “Preserve log” checkbox. This helps me refresh the page without having to worry about losing any of the logs from previous loads.<br />  Then, sometimes, I disable cache just to be sure I’m getting fresh requests loaded.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751692246420/c049d9cb-e820-4579-9753-ccfcac72b6d8.png" alt class="image--center mx-auto" /></p>
</li>
<li><p><strong>Application tab</strong>: I use this to view the localStorage, sessionStorage, cookies, IndexedDB, shared and cached storages, Essentially, you can view everything storage here, lol, which is so helpful for debugging auth and caching. Service workers and background services are also accessible here.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751692594298/cf308d71-d7c6-48c5-88e4-dc081b80a839.png" alt class="image--center mx-auto" /></p>
</li>
<li><p><strong>Rendering tab</strong>: You can access a list of stats and emulations here, by clicking on the 3 dots at the top right and then “Run command”. You can enable <strong>Paint flashing</strong>, <strong>Layout shift regions</strong>, <strong>FPS meter</strong> for live visual insights, etc.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751690825850/1bb847da-f099-463f-a182-e447fbd2129d.png" alt class="image--center mx-auto" /></p>
</li>
<li><p><strong>Console tab</strong>: This tab is definitely one of every developer’s favorite, lol. You get to log anything to the browser console <code>(console.log)</code> and see the logs here. This helps a lot with verifying what is and what is not.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751692848725/90695443-4210-489f-8b0c-8a31777f09a6.png" alt class="image--center mx-auto" /></p>
</li>
<li><p><strong>AI assistance tab</strong>: You get to ask questions here, as much as you’d like. Although it’s still experimental, this tab can be very useful.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751692928604/282e087f-c18c-432c-bd58-c39a45c96030.png" alt class="image--center mx-auto" /></p>
<p>  You can select any item at all in either of the listed tabs and ask AI about them. For instance, you can do this in the network tab;</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751693047800/613359aa-2839-4118-a118-42854fda2c75.png" alt class="image--center mx-auto" /></p>
</li>
</ul>
<h2 id="heading-in-conclusion">In Conclusion</h2>
<p>The DevTools is more than an inspector, it’s an amazing tool for debugging your web apps. And now, with AI, the DevTools has got even more resourceful with AI insights and “Ask AI” features. Once you get comfortable using it intentionally, you’ll start solving UI issues faster, with more confidence, and fewer logs to the console. 😉</p>
<p>If you’re just getting started, don’t feel overwhelmed. Start by inspecting and editing styles live. Then build up to using the Performance tab and Lighthouse. It’s one of those skills that compound over time.</p>
<p>And remember, the best way to learn how to use the DevTools is to break stuff and fix it using the DevTools. 😄</p>
<p>Up next, I will be writing about how to use some other browser extensions like the React Developer Tools, Redux DevTools, etc to supercharge your browser DevTools. These would give you access to other features that’d help you inspect and profile the behaviour of your components and redux states.</p>
<p>See you in the next one! 💪</p>
]]></content:encoded></item><item><title><![CDATA[What Really Happens When You Load a Web Page?]]></title><description><![CDATA[Intro
Growing up, everyone around me noticed I had a deep level of curiosity, which increased as I became older. A good number of the gadgets in the house then didn’t have the opportunity to stay whole long enough to see me grow up, because I had dis...]]></description><link>https://blog.ebugo.me/what-really-happens-when-you-load-a-web-page</link><guid isPermaLink="true">https://blog.ebugo.me/what-really-happens-when-you-load-a-web-page</guid><dc:creator><![CDATA[Gospel Chinyereugo]]></dc:creator><pubDate>Sat, 28 Jun 2025 23:34:54 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/bMvuh0YQQ68/upload/38fc5c7eabf31a07a982d7f45f77ee82.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-intro">Intro</h3>
<p>Growing up, everyone around me noticed I had a deep level of curiosity, which increased as I became older. A good number of the gadgets in the house then didn’t have the opportunity to stay whole long enough to see me grow up, because I had dismantled them one way or the other just out of curiosity to see how they really worked and if I could assemble them again. And of course, I couldn’t assemble all successfully. I still remember that big radio, and really hope my dad doesn’t come across this post. 😆</p>
<p>One of the curiosities I also noticed had grown in me as I found myself in the tech space was how the web really worked. One thing I was really sure of was that it isn’t magic at all even though it felt and still feels almost magical!</p>
<p>I mean, come to think of it; you just get to type a web address, hit enter, and in milliseconds, a web page appears.</p>
<p><strong>PS:</strong> A web or website address is essentially the address of a resource or set of files on the internet. It’s called a Uniform Resource Locator (or URL for short).</p>
<p>As a frontend engineer too, understanding the steps behind loading a web page helps you level up and gives you a clearer picture of performance issues, rendering strategies, browser behavior, and even security implications.</p>
<p>I’ll do my best to break down this process in as much simple terms as I can. Don’t worry at all, I’ve got you covered 😇💪</p>
<h3 id="heading-step-1-you-type-a-url-or-web-address-into-your-browsers-address-bar-and-then-hit-enter">Step 1. <strong>You type a URL or web address into your browser’s address bar and then hit enter</strong></h3>
<p>Let’s say you visit: <a target="_blank" href="https://example.com"><code>https://example.com</code></a></p>
<p>This is not just a random string, as you may have guessed rightly. Every part of it has its own function. Let’s break this down even more;</p>
<h4 id="heading-1-https-scheme-protocol">1. <code>https</code> : <em>Scheme / Protocol</em></h4>
<ul>
<li><p>This part tells the browser what protocol it should use to access the resource.</p>
</li>
<li><p>In this case, the browser is to use the <strong>HTTPS</strong> (HyperText Transfer Protocol Secure), which is basically a secure version of the HTTP (HyperText Transfer Protocol → <code>http://</code>); or in more technical terms, HTTP with encryption via <strong>TLS (Transport Layer Security)</strong>.</p>
<p>  <strong>PS:</strong> HTTP is a set of rules that govern how web browsers and servers communicate, enabling the display of web pages and other content (*more info at the references section).</p>
</li>
<li><p>It ensures the data being shared or looked up is:</p>
<ul>
<li><p><strong>Encrypted</strong> (no eavesdropping by a 3rd party)</p>
</li>
<li><p><strong>Authenticated</strong> (you’re talking to the real site, even though this is not a 100% assurance today 🥲)</p>
</li>
<li><p><strong>Tamper-proof</strong> (the data can't be altered in transit)</p>
</li>
</ul>
</li>
</ul>
<h4 id="heading-2-examplecomhttpexamplecom-domain-name">2. <a target="_blank" href="http://example.com"><code>example.com</code></a> : <em>Domain Name</em></h4>
<ul>
<li><p>This is the <strong>hostname</strong> or <strong>domain</strong>, which users can remember and type easily.</p>
</li>
<li><p>The domain is mapped to an IP address via a <strong>DNS lookup</strong> (*more info in next step).</p>
</li>
</ul>
<p>Let’s break it down even further:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Subsection</td><td>Meaning</td></tr>
</thead>
<tbody>
<tr>
<td><code>example</code></td><td><strong>Second-level domain</strong> (unique to the site you’re visiting)</td></tr>
<tr>
<td><code>.com</code></td><td><strong>Top-level domain</strong> (TLD; example: <code>.com</code>, <code>.org</code>, <code>.ng</code>, etc.)</td></tr>
</tbody>
</table>
</div><blockquote>
<p>Combined, <a target="_blank" href="http://example.com"><code>example.com</code></a> is the <strong>fully qualified domain name (FQDN)</strong>.</p>
</blockquote>
<p>A full URL actually goes way beyond just the above. It can include the following:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Section</td><td>Name</td><td>Description</td></tr>
</thead>
<tbody>
<tr>
<td><code>https://</code></td><td>Scheme/Protocol</td><td>Connection rule.</td></tr>
<tr>
<td><code>www.</code></td><td>Subdomain</td><td>Optional; <a target="_blank" href="http://www.example.com"><code>www.example.com</code></a> is different from <a target="_blank" href="http://example.com"><code>example.com</code></a>.</td></tr>
<tr>
<td><a target="_blank" href="http://example.com"><code>example.com</code></a></td><td>Domain name</td><td>The registered domain.</td></tr>
<tr>
<td><code>:443</code></td><td>Port</td><td>Default for HTTPS is 443, while for HTTP it is 80.</td></tr>
<tr>
<td><code>/about</code></td><td>Path</td><td>Refers to a specific resource/page on the website/app. By default urls like <a target="_blank" href="https://example.com"><code>https://example.com</code></a> have a <code>/</code> at the end like this <a target="_blank" href="https://example.com"><code>https://example.com/</code></a> which points to the home resource/page.</td></tr>
<tr>
<td><code>?user=gospel</code></td><td>Query string</td><td>Provides parameters to the backend (<code>key=value</code> pairs), and can also be used to manipulate the view on the frontend/web.</td></tr>
<tr>
<td><code>#section</code></td><td>Fragment (hash)</td><td>Points to an internal section on the page (not sent to the server). Can be used to scroll up/down to a specific section of the page.</td></tr>
</tbody>
</table>
</div><p>When all put together this gives us an even longer URL:</p>
<pre><code class="lang-http"><span class="hljs-attribute">https://www.example.com:443/about?user=gospel#section</span>
</code></pre>
<h3 id="heading-step-2-dns-lookup-translating-the-domain-to-the-actual-address">Step 2. <strong>DNS Lookup: Translating the domain to the actual address</strong></h3>
<p>Let’s just say the domain name (web address) above you typed into your search bar (<a target="_blank" href="http://example.com"><code>example.com</code></a>) is the name of a utility store. Computers do not understand what names are, and so do not know what <a target="_blank" href="http://example.com"><code>example.com</code></a> is. What they understand is numbers, and hence we need to map the domain to a number (also known as an IP address). The IP (Internet Protocol) address can be said to be the store’s real street address. The computer needs this street address to get to the store you’re searching for.</p>
<p>In essence, your browser asks a <strong>DNS</strong> (Domain Name System) server (like a phonebook) to resolve the domain to an IP address, e.g., <code>93.184.216.34</code>.</p>
<p>*The IP addresses associated with <a target="_blank" href="http://example.com"><code>example.com</code></a> are: <code>93.184.216.34</code> and <code>2606:2800:220:1:248:1893:25c8:1946</code>. These are the IPv4 and IPv6 addresses respectively.</p>
<p>Worthy of note: There’s a term called DNS prefetching. It’s a process that you can use to speed up DNS look up for known domains.</p>
<h3 id="heading-step-3-establishing-a-tcp-connection-with-tls-if-https">Step 3. <strong>Establishing a TCP connection (with TLS if HTTPS)</strong></h3>
<p>On getting the IP address, your browser establishes a <strong>TCP</strong> (Transmission Control Protocol) connection with the server hosting the website. TCP is a fundamental protocol that ensures reliable and ordered delivery of data over the internet. This step is very important because it sets up a communication channel between your device and the server, allowing data to be exchanged accurately.</p>
<p>The process begins with a three-way handshake, which is a series of steps that both your browser and the server must complete to establish a connection. First, your browser sends a SYN (synchronize) packet to the server to initiate the connection. The server then responds with a SYN-ACK (synchronize-acknowledge) packet to acknowledge the request. Finally, your browser sends an ACK (acknowledge) packet back to the server, confirming that the connection is established and ready for data transmission.</p>
<p>If you’re using <code>https://</code>, then an additional of security is added through TLS (Transport Layer Security). This involves exchanging cryptographic keys and certificates to encrypt the data being transmitted, ensuring that sensitive information remains secure and private.</p>
<p>This step is often overlooked, but it can add latency or delays especially on mobile or slow networks.</p>
<h3 id="heading-step-4-sending-the-http-request">Step 4. <strong>Sending the HTTP request</strong></h3>
<p>Now the browser finally sends an <strong>HTTP GET request</strong> for <code>/</code>.</p>
<p>Example:</p>
<pre><code class="lang-http"><span class="hljs-keyword">GET</span> <span class="hljs-string">/</span> HTTP/1.1
<span class="hljs-attribute">Host</span>: example.com
<span class="hljs-attribute">User-Agent</span>: Chrome/124
</code></pre>
<p>This includes headers with info like cookies, cache rules, accepted formats, and authentication tokens.</p>
<h3 id="heading-step-5-the-server-responds">Step 5. <strong>The server responds</strong></h3>
<p>The server then receives the request, processes it (maybe querying a database or rendering just HTML which is short for HyperText Markup Language), and finally sends back a response to your browser. This HTML document is the backbone of the web page, containing the structure and content that the browser will render for the user.</p>
<p>Example:</p>
<pre><code class="lang-http">HTTP/1.1 <span class="hljs-number">200</span> OK
<span class="hljs-attribute">Content-Type</span>: text/html
</code></pre>
<p>The response body includes the raw HTML of the page. This is where the browser begins to display the web page.</p>
<h3 id="heading-step-6-your-browser-renders-the-html-dom-creation">Step 6. Your <strong>browser renders the HTML (DOM creation)</strong></h3>
<p>As your browser receives the requested web page as HTML data, it parses content line by line, thereby building the <strong>DOM</strong> (Document Object Model). The DOM is a tree-like structure that represents the web page's content and structure. This process helps the browser understand how to display the page.</p>
<p>Also, along with the HTML content, the browser receives external resources (like CSS - Cascading Style Sheets, JS - JavaScript, fonts, images, etc.) which it adds to the list of resources for download.</p>
<p><strong>PS:</strong> The browser might stop rendering if it comes across CSS or synchronous JS, which can delay the web page from loading in time.</p>
<h3 id="heading-step-7-cssom-and-render-tree-construction">Step 7. <strong>CSSOM and Render Tree construction</strong></h3>
<p>In this step;</p>
<ul>
<li><p>The browser parses all CSS into the <strong>CSSOM</strong> (CSS Object Model).</p>
</li>
<li><p>Then combines it with the DOM to form the <strong>Render Tree.</strong></p>
</li>
<li><p>This tells the browser <em>what</em> to draw and <em>how</em> to draw it.</p>
</li>
</ul>
<h3 id="heading-step-8-layout-and-paint">Step 8. <strong>Layout and paint</strong></h3>
<p>Now with the render tree ready:</p>
<ul>
<li><p>The browser calculates where each element goes → <strong>Layout.</strong></p>
</li>
<li><p>Then it paints pixels to the screen → <strong>Paint.</strong></p>
</li>
<li><p>The GPU (Graphics Processing Unit) in your device may then start working to put together layers and handle animations.</p>
</li>
</ul>
<h3 id="heading-step-9-javascript-execution-amp-event-binding">Step 9. <strong>JavaScript execution &amp; event binding</strong></h3>
<p>JS files execute during or after parsing, depending on whether they’re <code>defer</code>, <code>async</code>, or blocking.</p>
<p>Also, these take place;</p>
<ul>
<li><p>Event listeners are attached.</p>
</li>
<li><p>Components are initialized (React, Vue, etc.).</p>
</li>
<li><p>Client-side rendering (CSR) may then start here.</p>
</li>
</ul>
<h3 id="heading-step-10-the-page-becomes-interactive-domcontentloaded-amp-load-events">Step 10. <strong>The page becomes interactive (DOMContentLoaded &amp; Load Events)</strong></h3>
<ul>
<li><p><code>DOMContentLoaded</code>: When HTML and DOM are fully parsed.</p>
</li>
<li><p><code>load</code>: When everything including images and styles are fully loaded.</p>
</li>
</ul>
<p>This is the final step and at this point the web page has completely loaded and is fully interactive. At this point you now have access to the full contents of the web page you requested on your browser. ☺️</p>
<h3 id="heading-so-what-can-slow-it-down-for-devs">So, what can slow it down? (For devs 😀👌)</h3>
<p>How long it takes to load a web page completely play very important roles to how good or bad the experiences of your users/customers turns out. This can be affected by;</p>
<ul>
<li><p><strong>Large CSS or JS files</strong>; these block render, especially when they are not deferred.</p>
</li>
<li><p><strong>Unoptimized images</strong>; these increase the web page’s load time due to the longer time it takes the broswer to download the content.</p>
</li>
<li><p><strong>Third-party scripts</strong>; these delay interactivity, as the scripts have to run from top to bottom.</p>
</li>
<li><p><strong>Multiple server requests</strong>; these add latency.</p>
</li>
</ul>
<p><strong>TIP:</strong> You can use <a target="_blank" href="https://chromewebstore.google.com/detail/blipmdconlkpinefehnmjammfjpmpbjk?utm_source=item-share-cb"><strong>Lighthouse</strong></a> or <a target="_blank" href="https://pagespeed.web.dev/">PageSpeed</a> to audit or check the performance of your web pages and optimize based on the recommendations.</p>
<h2 id="heading-in-conclusion">In Conclusion</h2>
<p>A whole lot goes into achieving this “magic” of looking up website addresses and giving us web pages with content that bring value to us. 🔥</p>
<p>Also, for frontend web engineers, understanding how the web works and how to easily optimize for the best user experience (UX) can give us the knowledge we need to build faster, more accessible, and more resilient web apps.</p>
<p>So the next time someone says that a web page is slow, you’ll know exactly where to look! ☺️</p>
<h3 id="heading-references-and-further-reading">References and Further Reading</h3>
<ul>
<li><p><a target="_blank" href="https://www.techtarget.com/whatis/definition/HTTP-Hypertext-Transfer-Protocol#:~:text=Published:%20Feb%2003%2C%202025,of%20the%20modern%2Dday%20internet.">What is HTTP and how does it work?</a></p>
</li>
<li><p><a target="_blank" href="https://www.kaspersky.com/resource-center/definitions/what-is-an-ip-address">What is an IP Address – Definition and Explanation</a></p>
</li>
<li><p><a target="_blank" href="https://aws.amazon.com/route53/what-is-dns">What is DNS?</a></p>
</li>
<li><p><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model">Document Object Model (DOM)</a></p>
</li>
<li><p><a target="_blank" href="https://css-tricks.com/an-introduction-and-guide-to-the-css-object-model-cssom">An Introduction and Guide to the CSS Object Model (CSSOM)</a></p>
</li>
<li><p><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Execution_model">JavaScript execution model</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Web Rendering Strategies Explained: CSR, SSR, SSG, ISR]]></title><description><![CDATA[TLDR;
Making a choice, when it comes to the right rendering strategy to use, all depends on context or use case.
Ask yourself:

How often does this content change?

Who needs to see it; users, crawlers, or both?

What’s more important; speed, SEO, or...]]></description><link>https://blog.ebugo.me/web-rendering-strategies-explained-csr-ssr-ssg-isr</link><guid isPermaLink="true">https://blog.ebugo.me/web-rendering-strategies-explained-csr-ssr-ssg-isr</guid><category><![CDATA[Web Development]]></category><category><![CDATA[web]]></category><category><![CDATA[webdev]]></category><category><![CDATA[TypeScript]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Rendering]]></category><category><![CDATA[Next.js]]></category><category><![CDATA[SSR]]></category><category><![CDATA[ssg]]></category><category><![CDATA[isr]]></category><category><![CDATA[csr]]></category><dc:creator><![CDATA[Gospel Chinyereugo]]></dc:creator><pubDate>Thu, 26 Jun 2025 17:26:16 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/JySoEnr-eOg/upload/6cf448a66ff9aa384bbdffb8405551bd.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-tldr">TLDR;</h2>
<p>Making a choice, when it comes to the right rendering strategy to use, all depends on context or use case.</p>
<p>Ask yourself:</p>
<ul>
<li><p>How often does this content change?</p>
</li>
<li><p>Who needs to see it; users, crawlers, or both?</p>
</li>
<li><p>What’s more important; speed, SEO, or freshness?</p>
</li>
</ul>
<p>Once you have the answers to these questions, then the right strategy to use at that point in time presents itself. No need to over-engineer. KISS!</p>
<h2 id="heading-you-are-not-alone">You are not alone! 😇</h2>
<p>If you’ve tried building or optimizing a frontend web app and felt overwhelmed by all the rendering options (CSR, SSR, SSG, ISR) thrown at you, I’m here to promise you that you are not alone. 😄</p>
<p>This list sounds intimidating at first but once you understand them, their strengths, tradeoffs, and use cases, they become your secret weapon for performance, SEO optimization, and good user experience.</p>
<p>Let’s take a deep dive and get you closer to shipping better web experiences! 😉👍</p>
<h2 id="heading-what-is-web-rendering">What is Web Rendering?</h2>
<p>Web rendering refers to how the content of your web app or site is bundled into HTML and delivered to the user; either by the browser, the server, or during build.</p>
<p>Different strategies affect performance, SEO, caching, and the user experience as a whole. These strategies include:</p>
<h2 id="heading-1-client-side-rendering-csr">1. Client-Side Rendering (CSR)</h2>
<p><strong>What:</strong><br />In this strategy, the entire web app is rendered with JavaScript by the browser. The browser loads a page that is blank or has little content, then JavaScript kicks in, fetches data, and renders everything.</p>
<p><strong>When to use:</strong></p>
<ul>
<li><p>Your content is <strong>private or personalized</strong> (e.g. dashboards, admin panels).</p>
</li>
<li><p>SEO <strong>doesn't matter</strong> much (e.g. internal tools, web apps behind auth).</p>
</li>
<li><p>You want <strong>fast initial page loads after the first visit</strong> (thanks to caching).</p>
</li>
</ul>
<p><strong>Cons:</strong></p>
<ul>
<li><p>Slower initial load (especially on low-end devices).</p>
</li>
<li><p>SEO-unfriendly (unless paired with dynamic rendering or pre-rendering hacks).</p>
</li>
</ul>
<p><strong>Example (Next.js):</strong></p>
<pre><code class="lang-typescript"><span class="hljs-string">'use client'</span>;

<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">DashboardPage</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [data, setData] = useState([]);
  useEffect(<span class="hljs-function">() =&gt;</span> {
    fetch(<span class="hljs-string">'/api/data'</span>).then(<span class="hljs-function"><span class="hljs-params">res</span> =&gt;</span> res.json()).then(setData);
  }, []);

  <span class="hljs-keyword">return</span> &lt;div&gt;{<span class="hljs-comment">/* render data */</span>}&lt;/div&gt;;
}
</code></pre>
<p><strong>PS:</strong> CSR is generally not recommended for good SEO.</p>
<h2 id="heading-2-server-side-rendering-ssr">2. Server-Side Rendering (SSR)</h2>
<p><strong>What:</strong><br />Here, HTML is generated on the server-side at the time of request by a user. The server fetches the data needed and returns fully rendered HTML to the client.</p>
<p><strong>When to use:</strong></p>
<ul>
<li><p>You need <strong>up-to-date content</strong> on every visit.</p>
</li>
<li><p>SEO is important <strong>and</strong> the data changes frequently (e.g. product pages with live inventory).</p>
</li>
<li><p>You’re dealing with <strong>user-specific content</strong> visible to crawlers (e.g. account previews).</p>
</li>
</ul>
<p><strong>Cons:</strong></p>
<ul>
<li><p>Slower response compared to static pages.</p>
</li>
<li><p>Server load increases with traffic; the higher the number of active users, the higher the load on the server.</p>
</li>
</ul>
<p><strong>Example (Next.js):</strong></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// pages/products.tsx (Pages Router)</span>

<span class="hljs-keyword">type</span> Product = {
  id: <span class="hljs-built_in">string</span>;
  name: <span class="hljs-built_in">string</span>;
  description: <span class="hljs-built_in">string</span>;
};

<span class="hljs-keyword">type</span> Props = {
  products: Product[];
};

<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">ProductListPage</span>(<span class="hljs-params">{ products }: Props</span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;div&gt;
      &lt;h1&gt;Product List&lt;/h1&gt;
      &lt;ol&gt;
        {products.map(<span class="hljs-function"><span class="hljs-params">item</span> =&gt;</span> (
          &lt;li key={item.id}&gt;{item.name}: ${item.description}.&lt;/li&gt;
        ))}
      &lt;/ol&gt;
    &lt;/div&gt;
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getServerSideProps</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'https://example.com/api/v1/products'</span>);
  <span class="hljs-keyword">const</span> products = <span class="hljs-keyword">await</span> response.json();

  <span class="hljs-keyword">return</span> { props: { products } };
}
</code></pre>
<h2 id="heading-3-static-site-generation-ssg">3. Static Site Generation (SSG)</h2>
<p><strong>What:</strong><br />In this case, the HTML is pre-rendered during build. It’s fast, SEO-friendly, and is great for pages that don’t change often.</p>
<p><strong>When to use:</strong></p>
<ul>
<li><p>Your content is <strong>mostly static</strong> (e.g. blog posts, landing pages).</p>
</li>
<li><p>You want a really <strong>fast performance</strong> with CDN-level caching.</p>
</li>
<li><p>You don’t mind rebuilding your site each time you want updates to reflect.</p>
</li>
</ul>
<p><strong>Cons:</strong></p>
<ul>
<li>Not great for real-time data unless paired with revalidation or client-side fetching. This can be seen in the next rendering strategy (ISR).</li>
</ul>
<p><strong>Example (Next.js):</strong></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// pages/posts.tsx (Pages Router)</span>

<span class="hljs-keyword">type</span> Post = {
  id: <span class="hljs-built_in">string</span>;
  title: <span class="hljs-built_in">string</span>;
};

<span class="hljs-keyword">type</span> Props = {
  posts: Post[];
};

<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">BlogPostsPage</span>(<span class="hljs-params">{ posts }: Props</span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;div&gt;
      &lt;h1&gt;Blog Posts&lt;/h1&gt;
      &lt;ol&gt;
        {posts.map(<span class="hljs-function"><span class="hljs-params">item</span> =&gt;</span> (
          &lt;li key={item.id}&gt;{item.title}&lt;/li&gt;
        ))}
      &lt;/ol&gt;
    &lt;/div&gt;
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getStaticProps</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'https://example.com/api/v1/blog-posts'</span>);
  <span class="hljs-keyword">const</span> posts = <span class="hljs-keyword">await</span> response.json();

  <span class="hljs-keyword">return</span> { props: { posts } };
}
</code></pre>
<h2 id="heading-4-incremental-static-regeneration-isr">4. Incremental Static Regeneration (ISR)</h2>
<p><strong>What:</strong><br />This is a hybrid approach for rendering web pages. The pages are generated statically at build time, and then updated under the hood after a set intervals (or when needed).</p>
<p><strong>When to use:</strong></p>
<ul>
<li><p>You want the speed of SSG but with <strong>updatable content</strong>.</p>
</li>
<li><p>SEO matters, but you don’t want to rebuild your whole site each time you want changes to reflect.</p>
</li>
<li><p>You're working with CMS-driven or eCommerce content (like product details).</p>
</li>
</ul>
<p><strong>Cons:</strong></p>
<ul>
<li><p>Slightly complex when it comes to handling stale vs. fresh data.</p>
</li>
<li><p>More difficult to debug when compared to pure SSG or SSR.</p>
</li>
</ul>
<p><strong>Example (Next.js):</strong></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// pages/posts.tsx (Pages Router)</span>

<span class="hljs-keyword">type</span> Post = {
  id: <span class="hljs-built_in">string</span>;
  title: <span class="hljs-built_in">string</span>;
};

<span class="hljs-keyword">type</span> Props = {
  posts: Post[];
};

<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">BlogPostsPage</span>(<span class="hljs-params">{ posts }: Props</span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;div&gt;
      &lt;h1&gt;Blog Posts&lt;/h1&gt;
      &lt;ol&gt;
        {posts.map(<span class="hljs-function"><span class="hljs-params">item</span> =&gt;</span> (
          &lt;li key={item.id}&gt;{item.title}&lt;/li&gt;
        ))}
      &lt;/ol&gt;
    &lt;/div&gt;
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getStaticProps</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'https://example.com/api/v1/blog-posts'</span>);
  <span class="hljs-keyword">const</span> posts = <span class="hljs-keyword">await</span> response.json();

  <span class="hljs-keyword">return</span> {
    props: { posts },
    revalidate: <span class="hljs-number">60</span>, <span class="hljs-comment">// Regenerate every 60 seconds</span>
  };
}
</code></pre>
<h2 id="heading-in-summary-when-should-i-use-what">In Summary… When Should I Use What?</h2>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Strategy</td><td>Best For</td><td>SEO</td><td>Freshness</td><td>Performance</td></tr>
</thead>
<tbody>
<tr>
<td><strong>CSR</strong></td><td>Authenticated apps, dashboards</td><td>❌</td><td>✅</td><td>⚠️ first load</td></tr>
<tr>
<td><strong>SSR</strong></td><td>Dynamic pages with frequent updates</td><td>✅</td><td>✅</td><td>Medium</td></tr>
<tr>
<td><strong>SSG</strong></td><td>Blogs, marketing pages</td><td>✅</td><td>❌ (build-time)</td><td>🚀</td></tr>
<tr>
<td><strong>ISR</strong></td><td>Product pages, CMS-driven sites</td><td>✅</td><td>✅ (after delay)</td><td>🚀 + ⏳</td></tr>
</tbody>
</table>
</div><h3 id="heading-references-amp-further-reading">References &amp; Further Reading</h3>
<ul>
<li><p><a target="_blank" href="https://nextjs.org/docs/app/getting-started/partial-prerendering">Next.js Rendering Docs</a></p>
</li>
<li><p><a target="_blank" href="https://web.dev/rendering-on-the-web/">Google: Rendering on the Web</a></p>
</li>
<li><p><a target="_blank" href="https://nextjs.org/learn/pages-router/data-fetching-two-forms#when-to-use-static-generation-vs-server-side-rendering">When to Use Static Generation vs. Server-side Rendering</a></p>
</li>
<li><p><a target="_blank" href="https://vercel.com/docs/concepts/functions/edge-caching">Caching strategies</a></p>
</li>
</ul>
<p><strong>PS:</strong> Like, comment and share if this helps you. Also, comment areas that may not be so clear to you yet (whether implementation wise, or you want examples in other frameworks) and I’ll do my best to drop more notes on that.</p>
<p>Also worthy of note;</p>
<ul>
<li><p>You can use a mix; In frameworks like Next.js, you can mix strategies per route. For instance, <code>/about</code> can be SSG, <code>/dashboard</code> can be CSR, and <code>/product/[id]</code> can use ISR.</p>
</li>
<li><p>You should measure first; Don’t blindly choose SSG for SEO. Sometimes SSR + cache does the job better.</p>
</li>
</ul>
<p>Thank you and see you in the next one! 😉😇</p>
]]></content:encoded></item><item><title><![CDATA[Collocation on the Frontend Web: Why It Matters and How I Do It in Next.js (or any frontend framework at all)]]></title><description><![CDATA["Put things where they’re used." That’s the golden rule of collocation in frontend development, and once I embraced it fully, my Next.js projects became easier to scale, debug, and maintain.


TLDR;
Collocation makes it easier to find everything rela...]]></description><link>https://blog.ebugo.me/collocation-on-the-frontend-web-why-it-matters-and-how-i-do-it-in-nextjs-or-any-frontend-framework-at-all</link><guid isPermaLink="true">https://blog.ebugo.me/collocation-on-the-frontend-web-why-it-matters-and-how-i-do-it-in-nextjs-or-any-frontend-framework-at-all</guid><category><![CDATA[Colocation]]></category><category><![CDATA[Frontend Development]]></category><category><![CDATA[Next.js]]></category><category><![CDATA[vite]]></category><category><![CDATA[React]]></category><category><![CDATA[TypeScript]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[Developer]]></category><category><![CDATA[development]]></category><dc:creator><![CDATA[Gospel Chinyereugo]]></dc:creator><pubDate>Mon, 23 Jun 2025 07:54:25 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/2FPjlAyMQTA/upload/7a7a5dda95c9f8fef3a869d6c4069d40.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p>"Put things where they’re used." That’s the golden rule of collocation in frontend development, and once I embraced it fully, my Next.js projects became easier to scale, debug, and maintain.</p>
</blockquote>
<hr />
<h2 id="heading-tldr">TLDR;</h2>
<p>Collocation makes it easier to find everything related to a feature, component or page in your code, whether you want to make an update or remove an entire feature. Your project’s features are more modular and reusable, and onboarding a new developer to your codebase becomes less stressful. 😉</p>
<h2 id="heading-what-is-collocation">What is Collocation?</h2>
<p>Collocation in frontend web development simply means <strong>placing related files and logic close to each other, or in the same folder or context where they are actually used</strong>.</p>
<p>So instead of scattering styles in one folder, components in another, and tests in another, you keep everything related to a single feature or component tightly grouped.</p>
<p>Think of it like packing for a trip. You don’t keep your toothbrush in your garage and your passport in the kitchen. You group things by purpose. It’s the same idea here, just that we’re now “packing” our code ☺️.</p>
<h2 id="heading-why-collocation-matters-on-the-frontend">Why Collocation Matters on the Frontend</h2>
<p>In a modern frontend stack, especially with frameworks like <strong>Next.js</strong>, collocation is not just a pattern. It’s a best practice. Why?</p>
<ul>
<li><p><strong>Discoverability:</strong> Easier to find everything related to a component or page.</p>
</li>
<li><p><strong>Cognitive simplicity:</strong> No need to mentally map files across the entire tree.</p>
</li>
<li><p><strong>Testing is easier:</strong> Test files sit next to the components they test.</p>
</li>
<li><p><strong>Scoped styles and logic:</strong> CSS Modules, hooks, and utils don’t leak across the app.</p>
</li>
<li><p><strong>Encapsulation:</strong> Your features are modular and reusable.</p>
</li>
</ul>
<h2 id="heading-a-typical-nextjs-project-without-collocation">A Typical Next.js Project Without Collocation</h2>
<p>Here’s a simple (and painful) structure I’ve seen too many times:</p>
<pre><code class="lang-markdown">/components  
  Navbar.tsx  
  Button.tsx

/styles  
  Navbar.module.css  
  Button.module.css

/pages  
  index.tsx  
  about.tsx

/tests  
  Navbar.test.tsx  
  Button.test.tsx
</code></pre>
<p>Now imagine maintaining this at scale. 🥲</p>
<h2 id="heading-with-collocation">With Collocation</h2>
<p>Here’s how I typically structure my Next.js apps now using collocation:</p>
<pre><code class="lang-markdown">my-next-app/
├── src/
│   ├── app/                 # Top-level route components
│   │   └── login/
│   │       ├── layout.tsx
│   │       └── page.tsx
│   │   └── assets/                # Global static assets (images, fonts)
│   │       ├── logo.svg                
│   │       └── favicon.ico
│   │   ├── layout.tsx
│   │   ├── loading.tsx
│   │   └── page.tsx
│   ├── components/            # Shared components
│   │   └── Button/
│   │       ├── Button.tsx
│   │       ├── Button.module.css
│   │       └── Button.test.tsx
│   ├── features/              # Feature-specific modules
│   │   └── auth/
│   │       ├── components/
│   │       │   ├── Login.tsx
│   │       │   ├── Login.module.css
│   │       │   └── Login.test.tsx
│   │       ├── hooks/
│   │       │   └── useAuth.ts
│   │       ├── services/
│   │       │   └── authService.ts
│   │       └── types.ts
│   ├── hooks/                 # Global reusable hooks
│   │   └── useMediaQuery.ts
│   ├── layouts/               # Layout components (e.g., MainLayout)
│   │   └── MainLayout.tsx
│   ├── types/                 # Global type declarations
│   │   └── index.d.ts
│   ├── utils/                 # Utility functions
│   │   └── formatDate.ts
│   └── middleware.ts          # Middleware component
├── .gitignore
├── package.json
├── tsconfig.json
├── next-env.d.ts
└── next.config.mjs
</code></pre>
<p>Let’s break it down:</p>
<ul>
<li><p>Each route (like <code>/login</code>) has its own folder with its page component and supporting components in the features folder. Now, this is because I prefer not to have my component and logic files in the app folder. You can also decide to move you feature-specific folder to the feature/route folder in the app directory if you prefer them that close.</p>
<p>  Like this;</p>
<pre><code class="lang-markdown">  /app/login/
<span class="hljs-code">    page.tsx
    layout.tsx
    Login.tsx
    Login.module.css
    Login.test.tsx
    useAuth.ts</span>
</code></pre>
</li>
<li><p><strong>Styles</strong>, <strong>tests</strong>, and <strong>local hooks</strong> sit right next to the components they belong to.</p>
</li>
<li><p>Shared UI components or layout wrappers go into <code>components</code> folder.</p>
</li>
<li><p>Shared utils go in <code>utils</code>.</p>
</li>
</ul>
<p>It’s clean, it’s local and, it scales!</p>
<h2 id="heading-bonus-a-vite-app-with-collocation">Bonus: A Vite App With Collocation</h2>
<pre><code class="lang-markdown">my-vite-app/
├── public/                    # Static assets
│   └── favicon.svg
├── src/
│   ├── assets/                # Global static assets (images, fonts)
│   │   └── logo.svg
│   ├── components/            # Shared components
│   │   └── Button/
│   │       ├── Button.tsx
│   │       ├── Button.module.css
│   │       └── Button.test.tsx
│   ├── features/              # Feature-specific modules
│   │   └── auth/
│   │       ├── components/
│   │       │   └── LoginForm.tsx
│   │       ├── hooks/
│   │       │   └── useAuth.ts
│   │       ├── services/
│   │       │   └── authService.ts
│   │       └── types.ts
│   ├── hooks/                 # Global reusable hooks
│   │   └── useMediaQuery.ts
│   ├── layouts/               # Layout components (e.g., MainLayout)
│   │   └── MainLayout.tsx
│   ├── pages/                 # Top-level route components
│   │   └── Home/
│   │       ├── Home.tsx
│   │       └── Home.module.css
│   ├── routes/                
│   │   └── index.tsx
│   ├── types/                 # Global type declarations
│   │   └── index.d.ts
│   ├── utils/                 # Utility functions
│   │   └── formatDate.ts
│   ├── App.tsx                # Root component
│   ├── main.tsx               # Vite entry point
│   └── vite-env.d.ts          
├── .gitignore
├── index.html
├── package.json
├── tsconfig.json
├── tsconfig.node.json
└── vite.config.ts
</code></pre>
<h2 id="heading-a-collocation-example-in-code">A Collocation Example in Code</h2>
<p>Say I have a <code>Hero</code> section in my homepage. Here’s what that folder might look like:</p>
<h3 id="heading-herotsx">Hero.tsx</h3>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> styles <span class="hljs-keyword">from</span> <span class="hljs-string">'./hero.module.css'</span>;
<span class="hljs-keyword">import</span> { useHeroData } <span class="hljs-keyword">from</span> <span class="hljs-string">'./useHeroData'</span>;

<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">Hero</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> { title, subtitle } = useHeroData();
  <span class="hljs-keyword">return</span> (
    &lt;section className={styles.hero}&gt;
      &lt;h1&gt;{title}&lt;/h1&gt;
      &lt;p&gt;{subtitle}&lt;/p&gt;
    &lt;/section&gt;
  );
}
</code></pre>
<h3 id="heading-useherodatats">useHeroData.ts</h3>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">useHeroData</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> {
    title: <span class="hljs-string">'Welcome to My Site'</span>,
    subtitle: <span class="hljs-string">'Frontend, Fast, and Beautiful'</span>,
  };
}
</code></pre>
<p>Everything lives in one place. If I ever need to update or remove the <code>Hero</code>, I know <strong>exactly</strong> what to touch.</p>
<p>Also, if I need to remove an entire feature, I know where to go and not leave any unused code behind.</p>
<h2 id="heading-pro-tip-collocation-coupling">Pro Tip: Collocation ≠ Coupling</h2>
<p>A lot of people confuse collocation with tight coupling. Nope.</p>
<p>You can still keep components modular and testable while collocating. You're just being smarter at putting tools next to the task.</p>
<p><strong>PS:</strong> Coupling speaks to how much one component or module depends on another in a project. For your components to be tightly coupled means that you have components that are heavily connected or dependent on one another and changing one often breaks the other.</p>
<p>I’ll be writing more about this later! 🙃</p>
<h2 id="heading-summary">Summary</h2>
<p>Collocation is like flossing; everyone agrees it’s good for you, but only a few people do it consistently. Once I made it a rule in my Next.js workflow, things got really smoother.</p>
<p>🥂 Fewer bugs.<br />👌 Fewer mental jumps.<br />💪 Better developer experience.</p>
<p>If you’re starting a new project, collocate from day one. If you're refactoring an old one, do it incrementally and I promise you won’t regret it!</p>
]]></content:encoded></item><item><title><![CDATA[How to Run pip with Python 3 on Mac OS]]></title><description><![CDATA[TLDR;

Use python3 and pip3 — don’t rely on python or pip

Use Homebrew to install Python if needed: brew install python3

Run pip in scripts using python3 -m pip

Use venv for project-level dependency management


Have you tried installing Python3 o...]]></description><link>https://blog.ebugo.me/how-to-run-pip-with-python-3-on-mac-os</link><guid isPermaLink="true">https://blog.ebugo.me/how-to-run-pip-with-python-3-on-mac-os</guid><category><![CDATA[General Programming]]></category><category><![CDATA[Python 3]]></category><category><![CDATA[pip]]></category><category><![CDATA[macOS]]></category><category><![CDATA[Installation]]></category><category><![CDATA[Script]]></category><dc:creator><![CDATA[Gospel Chinyereugo]]></dc:creator><pubDate>Wed, 18 Jun 2025 06:00:31 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/-1ZgKN9FBMI/upload/5248a9a36f77527e9d86ff5a9359e729.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-tldr">TLDR;</h3>
<ul>
<li><p>Use <code>python3</code> and <code>pip3</code> — don’t rely on <code>python</code> or <code>pip</code></p>
</li>
<li><p>Use Homebrew to install Python if needed: <code>brew install python3</code></p>
</li>
<li><p>Run <code>pip</code> in scripts using <code>python3 -m pip</code></p>
</li>
<li><p>Use <code>venv</code> for project-level dependency management</p>
</li>
</ul>
<p>Have you tried installing Python3 on your Mac, or more so tried to use <code>pip</code>, and then you face the annoying moment where it’s not clear which Python version is in play or even worse, you accidentally install a package into the wrong interpreter or you followed the official docs and installed everything correctly but don’t know how to use the commands?</p>
<p>I faced this same challenge while at a codelab, and just like you I had to use most of my time for building to try to figure out how to get <code>pip</code> working to even start with.</p>
<p>Here’s how to get <code>pip</code> working cleanly with Python3 on macOS, without pulling your hair out 😊;</p>
<h3 id="heading-step-1-check-your-python-3-install">👉 Step 1: Check your Python 3 install</h3>
<p>macOS used to ship with Python2 by default, so running <code>python</code> might still point to that legacy version.</p>
<p>Open your Terminal and run:</p>
<pre><code class="lang-bash">python3 --version
</code></pre>
<p>You should get something like:</p>
<pre><code class="lang-plaintext">Python 3.13.5
</code></pre>
<p>PS.: Python 3.13 is the latest stable release at the time of writing this post.</p>
<p>If that doesn't work, install the latest Python3 using <a target="_blank" href="https://brew.sh/">Homebrew</a>:</p>
<pre><code class="lang-bash">brew install python3
</code></pre>
<p>This gives you:</p>
<ul>
<li><p><code>python3</code></p>
</li>
<li><p><code>pip3</code></p>
</li>
</ul>
<p>Or you could just download the Python3 installer here; <a target="_blank" href="https://www.python.org/downloads/macos/">Python3 installer</a>.</p>
<p>Ready to go.</p>
<h3 id="heading-step-2-always-use-pip3-not-pip">👉 Step 2: Always use <code>pip3</code>, not <code>pip</code></h3>
<p>Don’t trust <code>pip</code> alone unless you’re <em>absolutely</em> sure it’s mapped to Python 3. Instead, just use:</p>
<pre><code class="lang-bash">pip3 install some-package
</code></pre>
<p>This avoids surprises and keeps everything clean.</p>
<h3 id="heading-step-3-installing-packages-inside-scripts">👉 Step 3: Installing packages inside scripts?</h3>
<p>PS.: Do this only where necessary.</p>
<p>When automating with Python, do this to make sure the right pip is used:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> subprocess
<span class="hljs-keyword">import</span> sys

subprocess.check_call([sys.executable, <span class="hljs-string">"-m"</span>, <span class="hljs-string">"pip"</span>, <span class="hljs-string">"install"</span>, <span class="hljs-string">"some-package"</span>])
</code></pre>
<p>This runs <code>pip</code> for the currently running Python interpreter, whether it's the global <code>python3</code> or inside a virtualenv.</p>
<h3 id="heading-step-4-use-virtual-environments-seriously">👉 Step 4: Use virtual environments (seriously)</h3>
<p>They’re lightweight and essential for managing project dependencies:</p>
<pre><code class="lang-bash">python3 -m venv venv
<span class="hljs-built_in">source</span> venv/bin/activate
pip install some-package
</code></pre>
<p>Now you’re isolated from system Python and global packages.</p>
<h3 id="heading-bonus-official-python-3-docs">🥂 Bonus: Official Python 3 Docs</h3>
<p>If you want to dig deeper into pip, venv, or the Python standard library:</p>
<p>👉 <a target="_blank" href="https://docs.python.org/3/">Python 3 Documentation</a></p>
<p>If this helps you, please don’t forget to like, share and comment to help others facing same blocker.<br />Follow for more tips! 😉</p>
]]></content:encoded></item><item><title><![CDATA[Blockchain for noobs: part 2]]></title><description><![CDATA[How does Web3 really work?
To start with, I didn't want to mention the name Web3 as I think the topic has been over-flogged and abused a lot, but let's take a look at it from this angle - which is this; how really does web3 work? what really is this ...]]></description><link>https://blog.ebugo.me/blockchain-for-noobs-part-2</link><guid isPermaLink="true">https://blog.ebugo.me/blockchain-for-noobs-part-2</guid><category><![CDATA[Web3]]></category><category><![CDATA[Blockchain]]></category><category><![CDATA[noobs]]></category><dc:creator><![CDATA[Gospel Chinyereugo]]></dc:creator><pubDate>Wed, 22 Jun 2022 14:11:17 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/T9rKvI3N0NM/upload/076c24999101f6eb351cc39b2b65fa2a.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-how-does-web3-really-work">How does Web3 really work?</h2>
<p>To start with, I didn't want to mention the name Web3 as I think the topic has been over-flogged and abused a lot, but let's take a look at it from this angle - which is this; how really does web3 work? what really is this ownership thingy that has received so much of am emphasis in a short space of time?</p>
<p>Just before we go on ahead though, and just in case this is your first time reading any of my blog posts, you might be wondering where part 1 of this series is (I mean, for there to be a part 2 there must have been a part 1 right?). If this is you, then here it is <a target="_blank" href="https://blog.ebugo.me/blockchain-for-noobs-part-1">Blockchain for noobs: part 1</a>.</p>
<p>Let's take a look at a dapp (decentralised app) that allows users to create posts and reply them.</p>
<ol>
<li><p>Instead of the usual authentication flow (OAuth, Auth2 etc) where you would want to sign up or log in to the app with your email address and password, or with your social accounts, here you would authenticate by connecting your crypto wallet (a user is represented by their wallet).</p>
</li>
<li><p>When you create a post or send in a reply, a new file is created and stored on a decentralised file storage system like the <a target="_blank" href="https://ipfs.io/">IPFS</a> (InterPlanetary File System).</p>
</li>
<li><p>Also, a token that represents the file (post) is 'minted' on the dapp blockchain and allocated to your wallet address. The file stays in your wallet and as such you 'own' it, hence the much mentioned term 'ownership'.</p>
</li>
<li><p>You can transfer ownership of your files (posts) to other wallets. This is done via transaction calls.</p>
</li>
</ol>
<p>I guess we now have a new question to answer - "what really is this ownership and how does it help me as a user?".</p>
<p>Well, I'd explain this too and I'll be as brief as I can so I don't bore you with the long stories 😉</p>
<p>The idea of ownership proposes that whatever you create (be it a post, an art, or a visual content on a dapp) or get transferred to your wallet via any successful transaction lives in your wallet and are 'owned' by you. They're recognised as assets which gain value over time (and can also lose value too, so you know it's not a bed of roses 🥲). </p>
<p>This is in contrast to web2 which we are so familiar with whereby whatever you create lives in the database of the app or centralised data centres of companies such as Amazon, and as such you don't really 'own' them per se.</p>
]]></content:encoded></item><item><title><![CDATA[Blockchain for noobs: part 1]]></title><description><![CDATA[Why Blockchain?
Humans are subjective in their judgement/recording of facts and as such, the society can't trust humans to keep 100% accurate records.
Also, humans are naturally selected to be self-interested, biased and manipulative. 
All these and ...]]></description><link>https://blog.ebugo.me/blockchain-for-noobs-part-1</link><guid isPermaLink="true">https://blog.ebugo.me/blockchain-for-noobs-part-1</guid><category><![CDATA[Blockchain]]></category><category><![CDATA[noobs]]></category><dc:creator><![CDATA[Gospel Chinyereugo]]></dc:creator><pubDate>Mon, 20 Jun 2022 13:30:45 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/gC_aoAjQl2Q/upload/0544cfa5435caa137a5e486d7107a30c.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-why-blockchain">Why Blockchain?</h1>
<p>Humans are subjective in their judgement/recording of facts and as such, the society can't trust humans to keep 100% accurate records.
Also, humans are naturally selected to be self-interested, biased and manipulative. </p>
<p>All these and more make the quest for a way to keep records that are objective and immune to human bias a very highly prioritizes one, and the answer has been seen to be embodied in blockchain technology with the main aim being to remove humans from the equation altogether and replace them with math.</p>
<p>This brings us to various definitions of Blockchain and it's concepts which we will be taking a look at.</p>
<ol>
<li>The blockchain is a decentralised ledger or digital list of who owns what in a network. This can be anything at all, thus making the applications of the blockchain limitless.</li>
<li>Decentralised means every user in the network has an up-to-date copy of the ledger. This makes the records unchangeable. If someone for instance tampers with the ledger, the rest of the network will reject it. It's important to note that this has been the original vision for the internet from the beginning.</li>
<li>New records (blocks, thus the name "blockchain") encrypted with cryptography. Cryptography is impossibly complicated math that takes a lot of computing power.</li>
<li>This computing power is provided by "miners" who get paid in cryptocurrency (like Bitcoin) for securing the ledger. This makes the cryptocurrency scarce thereby giving it economic value.</li>
</ol>
<p>PS: This is the beginning of a series of articles I will be publishing around Blockchain technologies, enjoy! :)</p>
]]></content:encoded></item><item><title><![CDATA[Generating HMAC using crypto sha512 hashing]]></title><description><![CDATA[Secure Hash Algorithm 512 (SHA-512) is a cryptographic hashing algorithm which is used to convert text of any length into a fixed-size string (hash values). It produces a 512-bit (64bytes) hash value which is known as message digest used commonly for...]]></description><link>https://blog.ebugo.me/generating-hmac-using-crypto-sha512-hashing</link><guid isPermaLink="true">https://blog.ebugo.me/generating-hmac-using-crypto-sha512-hashing</guid><category><![CDATA[crypto]]></category><category><![CDATA[Hashing]]></category><category><![CDATA[sha512]]></category><category><![CDATA[hmac]]></category><dc:creator><![CDATA[Gospel Chinyereugo]]></dc:creator><pubDate>Wed, 08 Jun 2022 09:53:54 GMT</pubDate><content:encoded><![CDATA[<p>Secure Hash Algorithm 512 (SHA-512) is a cryptographic hashing algorithm which is used to convert text of any length into a fixed-size string (hash values). It produces a 512-bit (64bytes) hash value which is known as message digest used commonly for hashing passwords, email addresses and digital record verification. 
Interestingly, it is also used in blockchain as can be seen in the Bitshares (BTS) network. <a target="_blank" href="https://komodoplatform.com/en/academy/sha-512/">Read more here...</a></p>
<p>HMAC involves hashing with the help of a secret key as shown below;</p>
<p><strong>Code</strong></p>
<pre><code>
<span class="hljs-comment">//Import the crypto module in node.js</span>
const crypto <span class="hljs-operator">=</span> <span class="hljs-built_in">require</span>(<span class="hljs-string">'crypto'</span>);

<span class="hljs-comment">//create hmac object </span>
const hmac <span class="hljs-operator">=</span> crypto.createHmac(<span class="hljs-string">'sha512'</span>, {{your_secret_key}});

<span class="hljs-comment">//pass the data to be hashed</span>
const data <span class="hljs-operator">=</span> hmac.update({{ data }});

<span class="hljs-comment">//Create the hmac in the required format</span>
const hmacsignature <span class="hljs-operator">=</span> data.digest(<span class="hljs-string">'hex'</span>);

<span class="hljs-comment">//Log the output on the console</span>
console.log(`hmac : ${hmacsignature}`);
</code></pre><p><strong>Run</strong></p>
<p>Command —&gt;</p>
<pre><code><span class="hljs-bullet">-</span> node {{filename}}.js
</code></pre><p>Expected result —&gt;</p>
<pre><code><span class="hljs-bullet">-</span> hmac : a81b6b65c3df83ae15fe185dd16dc9c846f9e3cb567292422785954130047ac10e2547f505515ea4a20de7e335e60d6489ae71bbfcf130114672e95603dc4571
</code></pre>]]></content:encoded></item></channel></rss>