<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: David Jaja</title>
    <description>The latest articles on DEV Community by David Jaja (@daiveed).</description>
    <link>https://dev.to/daiveed</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F646529%2F104a998e-14f3-46cc-9884-8b11968b860c.jpg</url>
      <title>DEV Community: David Jaja</title>
      <link>https://dev.to/daiveed</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/daiveed"/>
    <language>en</language>
    <item>
      <title>Your code has a health problem — Here's how to see it</title>
      <dc:creator>David Jaja</dc:creator>
      <pubDate>Wed, 25 Mar 2026 08:39:51 +0000</pubDate>
      <link>https://dev.to/daiveed/your-code-has-a-health-problem-heres-how-to-see-it-43j3</link>
      <guid>https://dev.to/daiveed/your-code-has-a-health-problem-heres-how-to-see-it-43j3</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;A VS Code extension that scores your code like a doctor scores your health. No AI, no cloud, no guessing.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And that's the problem Iris was built to fix.&lt;/p&gt;

&lt;p&gt;Every developer has that moment. You open a file you wrote three months ago and it's 400 lines long, has six nested if statements, three unused imports, and a &lt;code&gt;console.log&lt;/code&gt; you forgot to clean up before the last deploy. You knew it was messy. You just didn't know &lt;em&gt;how&lt;/em&gt; messy.&lt;/p&gt;

&lt;p&gt;That's the gap Iris fills.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I built it
&lt;/h2&gt;

&lt;p&gt;I kept moving through large codebases with no real sense of which files were actually problematic. Linters catch syntax errors. Formatters handle style. But nothing answered the question I kept asking: &lt;em&gt;is this file fine, or is this file a problem?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Iris answers that question. Every time you open a file, in under a second, you know where you stand.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Iris is
&lt;/h2&gt;

&lt;p&gt;Iris is a VS Code extension that gives your code a health score — the same way a doctor gives you one after a checkup.&lt;/p&gt;

&lt;p&gt;Open any file, and you get a score from 0 to 100, backed by actual measurements: cyclomatic complexity, code smell detection, unused import analysis, and function-level breakdowns. Not vibes. Numbers.&lt;/p&gt;

&lt;p&gt;Run a workspace scan, and you get all of that aggregated across your entire project — a ranked list of your most complex files, a Problems tab with every finding sorted by severity, and TODOs surfaced from every corner of the codebase. Every finding is clickable and takes you directly to the line.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the analysis actually works
&lt;/h2&gt;

&lt;p&gt;No AI. No cloud. Everything runs locally.&lt;/p&gt;

&lt;p&gt;When you open or save a file, Iris runs a full static analysis pass on it — usually under a second. There's a version-based cache, so it's not re-running on every keystroke, only when the file actually changes.&lt;/p&gt;

&lt;p&gt;Each language has its own analyser with language-specific rules:&lt;/p&gt;

&lt;p&gt;For &lt;strong&gt;TypeScript and JavaScript&lt;/strong&gt;, Iris tracks things like &lt;code&gt;any&lt;/code&gt; usage, &lt;code&gt;@ts-ignore&lt;/code&gt; count, missing return types on exported functions, non-null assertions, and type assertion patterns — metrics that actually matter for TypeScript quality beyond what a linter gives you. It also detects unused variables and unused imports by checking whether each binding appears in the rest of the file after stripping out the import lines themselves.&lt;/p&gt;

&lt;p&gt;For &lt;strong&gt;Go&lt;/strong&gt;, the analyser understands the difference between exported and unexported functions — it won't flag a capitalised function as unused just because it isn't called within the file, since it may be the whole point of the package. It parses &lt;code&gt;go.mod&lt;/code&gt; for workspace-level unused dependency detection.&lt;/p&gt;

&lt;p&gt;For &lt;strong&gt;Python&lt;/strong&gt;, function boundaries are tracked by indentation depth rather than braces, deep nesting is flagged at four indent levels rather than two, and unused function detection is scoped to &lt;code&gt;_private&lt;/code&gt; functions only — public functions may be imported anywhere.&lt;/p&gt;

&lt;p&gt;Complexity scoring starts at 1 and caps at 10, factoring in function density, max indentation depth, control flow count, and third-party import volume. The health score starts at 100 and gets deducted based on actual findings — &lt;code&gt;any&lt;/code&gt; usages, console logs, unused variables, deep nesting, and long parameter lists. Floor is 0.&lt;/p&gt;

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

&lt;p&gt;This is all deterministic. Same code, same score, every time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the scores are weighted the way they are
&lt;/h2&gt;

&lt;p&gt;A health score is only useful if the penalties actually reflect real-world impact. Here's the thinking behind the numbers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Health score deductions
&lt;/h3&gt;

&lt;p&gt;Not all code problems are equal, and the deductions reflect that.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;@ts-ignore&lt;/code&gt; gets a heavier penalty than a stray &lt;code&gt;console.log&lt;/code&gt; because it's an active decision to suppress the type system — you're not just leaving debugging code in, you're telling TypeScript to look away. Similarly, unused functions carry a larger penalty than unused variables. A dead variable is noise. A dead function is a maintenance trap: someone will eventually wonder if it's safe to delete, spend time tracing it, and find out it does nothing.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;any&lt;/code&gt; usage sits in the middle — it's not always wrong, but it's a signal that type coverage has a hole. Each usage chips away at the score rather than tanking it, because one &lt;code&gt;any&lt;/code&gt; in a large file is very different from twenty.&lt;/p&gt;

&lt;p&gt;Errors deduct more than warnings, and warnings deduct more than info-level findings. That sounds obvious, but it means a file with one long function isn't necessarily unhealthy — it gets flagged, but it doesn't crater the score the way multiple suppressed type errors would.&lt;/p&gt;

&lt;p&gt;Here's the full breakdown:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Finding&lt;/th&gt;
&lt;th&gt;Deduction&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Error-level warning&lt;/td&gt;
&lt;td&gt;-5 each&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Warning-level warning&lt;/td&gt;
&lt;td&gt;-3 each&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;any&lt;/code&gt; usage&lt;/td&gt;
&lt;td&gt;-2 each&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@ts-ignore&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-3 each&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;console.log&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-1 each&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deep nesting (per function)&lt;/td&gt;
&lt;td&gt;-2 each&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Long parameter list (per function)&lt;/td&gt;
&lt;td&gt;-1 each&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unused variable&lt;/td&gt;
&lt;td&gt;-1 each&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unused function&lt;/td&gt;
&lt;td&gt;-2 each&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Score floor is 0 — it won't go negative.&lt;/p&gt;

&lt;h3&gt;
  
  
  Complexity score
&lt;/h3&gt;

&lt;p&gt;Complexity is a 1–10 scale that answers a different question than health: not "is this code problematic?" but "how hard is this code to hold in your head?"&lt;/p&gt;

&lt;p&gt;Four things contribute to it. Function density — how many functions exist relative to the file's size — reflects how much is being packed into one place. Max indentation depth is a proxy for nesting hell: deeply indented code usually means deeply nested conditionals, which means deeply nested logic you have to mentally unwind to follow. Control flow count tracks the actual branching — every &lt;code&gt;if&lt;/code&gt;, &lt;code&gt;for&lt;/code&gt;, &lt;code&gt;while&lt;/code&gt;, &lt;code&gt;switch&lt;/code&gt;, &lt;code&gt;catch&lt;/code&gt;, and ternary is a decision point that multiplies the paths through the code. Third-party import volume is the loosest signal of the four, but a file pulling in a lot of external dependencies tends to be doing a lot of things, which usually means more to reason about.&lt;/p&gt;

&lt;p&gt;Each factor has a cap on its contribution, so no single thing can max out the score alone. A file can be large and have many functions, but still score low on complexity if the logic itself is straightforward.&lt;/p&gt;

&lt;h3&gt;
  
  
  Workspace rankings
&lt;/h3&gt;

&lt;p&gt;When you scan a full workspace, Iris surfaces two ranked lists: largest files by line count and most complex files by complexity score. These are intentionally separate because they answer different questions.&lt;/p&gt;

&lt;p&gt;A 600-line file with simple, flat logic is a different kind of problem than a 200-line file with a complexity score of 9. The first is probably just overdue for a split. The second is the one that will slow down every developer who has to touch it.&lt;/p&gt;

&lt;p&gt;The Problems tab sorts by severity — errors first, then warnings, then info. The goal is that the first thing you see when you open it is the thing most worth fixing, not just the most recent finding.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it supports
&lt;/h2&gt;

&lt;p&gt;JavaScript, TypeScript (including JSX/TSX), Go, and Python. Each language has its own analysis rules built for how that language actually works — not a one-size-fits-all pass applied to everything.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to get it
&lt;/h2&gt;

&lt;p&gt;Search &lt;strong&gt;Iris — Code Health&lt;/strong&gt; on the VS Code Marketplace, or go to &lt;a href="https://iriscode.co" rel="noopener noreferrer"&gt;iriscode.co&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Free to install. The free plan covers full file-level analysis — health score, complexity, code smells, status bar, and code lens. Pro unlocks workspace and folder-wide scans, the Problems tab, TODOs aggregation, and &lt;code&gt;.irisconfig.json&lt;/code&gt; for team-wide config. Pricing is regionally adjusted — Nigerian developers get an early adopter rate of ₦2,000/month until March 30.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;p&gt;The core is solid — file health, workspace scans, code smell detection, and unused import analysis. There's more coming. I'm not going to put a full roadmap here, but if you've ever wanted Iris in a CI/CD pipeline, or wanted to track whether your codebase is getting healthier or worse over time, that's the kind of direction things are heading.&lt;/p&gt;

&lt;p&gt;If you try it and something feels off or missing, reply to this post or reach me at &lt;a href="mailto:hello@iriscode.co"&gt;hello@iriscode.co&lt;/a&gt;. I read everything.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>OneEntry Headless Content Management System</title>
      <dc:creator>David Jaja</dc:creator>
      <pubDate>Fri, 02 Feb 2024 12:19:45 +0000</pubDate>
      <link>https://dev.to/daiveed/oneentry-headless-content-management-system-57np</link>
      <guid>https://dev.to/daiveed/oneentry-headless-content-management-system-57np</guid>
      <description>&lt;p&gt;In the world of online content, where everyone talks about CMS, OneEntry stands out. Forget the usual CMS stories — OneEntry is more than just a solution; it’s a game-changer. It’s not your typical content manager. It’s super easy to use, flexible, and keeps your content safe. In a time when success is all about digital experiences, OneEntry is here to shake things up. Say goodbye to the usual and hello to something extraordinary! In this article, we’ll cover OneEntry CMS from practical integration steps to its unique features.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Sets Headless CMSs Apart from Conventional Ones?
&lt;/h2&gt;

&lt;p&gt;A headless CMS is a revolutionary type of content management system designed to liberate content creation and storage from the constraints of presentation on specific devices or platforms. In stark contrast to traditional CMS, which tightly intertwines the front end (what users see) with the back end (where content is managed), a headless CMS takes a more liberated approach. It decouples these components, offering unparalleled flexibility in disseminating content across diverse channels, making it a pivotal solution for crafting modern and engaging digital experiences.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Distinctions from Traditional CMS
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Decoupled Front and Back Ends&lt;/strong&gt;: Traditional CMS integrates the content creation and storage process tightly with the presentation layer, often limiting flexibility in content delivery. In contrast, a headless CMS decouples these functions, allowing for independent management and seamless distribution across various platforms.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Channel-Agnostic Content&lt;/strong&gt;: Headless CMSs enable the creation of content that is agnostic to specific devices or channels. This means content can be repurposed and delivered effortlessly across websites, mobile applications, IoT devices, and other digital touchpoints without being tied to a predefined structure.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Enhanced Flexibility&lt;/strong&gt;: The decoupling of the front and back ends grants developers the freedom to choose the technologies best suited for each component. This results in a more adaptable and scalable system that can evolve with technological advancements.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Efficient Content Delivery&lt;/strong&gt;: With traditional CMS, content is often delivered in a predefined format, limiting its adaptability. Headless CMS empowers content creators to tailor their content dynamically, ensuring an optimal user experience across a spectrum of devices and platforms.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Ensuring long-term viability&lt;/strong&gt;: The architecture of a headless CMS is naturally designed to anticipate shifts in technology and trends in content consumption. This adaptability serves as a strategic advantage, enabling businesses to maintain a leading position in the constantly evolving digital environment.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  A Complete Content Management Solution
&lt;/h2&gt;

&lt;p&gt;OneEntry is a headless CMS, which provides an extensive array of tools and functionalities that go beyond the normal boundaries of traditional data storage solutions. It’s not just a place to store your data; it’s a powerful platform that allows you to manage, organize, and present your content in the most effective way possible. With OneEntry, you can foster collaboration across your team, streamline your content delivery processes, and ultimately, enhance your audience’s digital experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Prerequisite for Seamless Integration
&lt;/h2&gt;

&lt;p&gt;Before delving into npm integration, let’s acknowledge the preliminary step — configuring your content with OneEntry’s intuitive GUI. If you’re new to this, fret not. The detailed instructions on &lt;a href="https://oneentry.cloud/en/instructions" rel="noopener noreferrer"&gt;OneEntry’s official instructions page&lt;/a&gt; are your go-to resource, covering account setup to content structuring.&lt;/p&gt;

&lt;h2&gt;
  
  
  OneEntry NPM Package
&lt;/h2&gt;

&lt;p&gt;The OneEntry NPM package is a powerful tool for developers, offering efficient and adaptable features. It seamlessly integrates with all major frameworks, providing a toolkit that goes beyond limits. This compatibility unlocks OneEntry’s full capabilities and is accompanied by an in-code documentation and robust guide ensuring quick and effective integration.&lt;/p&gt;

&lt;h3&gt;
  
  
  Essentials:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Compatibility&lt;/strong&gt;: OneEntry’s NPM package is framework-agnostic, supporting React, Angular, Vue, and more.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;In-Code Documentation&lt;/strong&gt;: Comprehensive documentation within the codebase for quick reference and clarity.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Integration Guide:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Run on your computer’s terminal&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;npm install oneentry&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Then import the package&lt;/p&gt;

&lt;p&gt;&lt;code&gt;import { defineOneEntry } from 'oneentry';&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;To initialize your project, run the command and log to the console to see your OneEntry app instance.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;const api = defineOneEntry('your-url', { apiKey: 'your-api-key' });&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Logging your project instance to the console gives&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F0%2ATO_wdJOQxUJLO9DG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F0%2ATO_wdJOQxUJLO9DG" alt="OneEntry Instance"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Fetching data from your OneEntry Project
&lt;/h2&gt;

&lt;p&gt;To demonstrate retrieving data from OneEntry, follow the following steps.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Log into your OneEntry project and create a couple of pages&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3200%2F0%2Awpf5mQbbRtOZ1-ew" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3200%2F0%2Awpf5mQbbRtOZ1-ew" alt="Creating pages"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Navigate to Settings and copy your API key&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3200%2F1%2AMdVlVlSLy0IhKL_exeumnQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3200%2F1%2AMdVlVlSLy0IhKL_exeumnQ.png" alt="Retrieving API key"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Create a local JS application (eg React).&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm create vite@latest&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Finally, create an API request with your API key and domain URL.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;useEffect(() =&amp;gt; {&lt;br&gt;
    const fetchData = async () =&amp;gt; {&lt;br&gt;
      try {&lt;br&gt;
        const params = new URLSearchParams({&lt;br&gt;
          langCode: "en_US",&lt;br&gt;
        });&lt;br&gt;
        const response = await fetch("${API_URL}/api/content/pages?${params}", {&lt;br&gt;
          method: "GET",&lt;br&gt;
          headers: {&lt;br&gt;
            "Content-Type": "application/json",&lt;br&gt;
            "x-app-token": API_TOKEN,&lt;br&gt;
          },&lt;br&gt;
        });&lt;br&gt;
        const status = response.status;&lt;br&gt;
        const data = await response.json();&lt;br&gt;
        setPages(data);&lt;br&gt;
        console.log(data);&lt;br&gt;
        console.log(status);&lt;br&gt;
      } catch (error) {&lt;br&gt;
        console.error("Error fetching data:", error);&lt;br&gt;
      }&lt;br&gt;
    };&lt;br&gt;
    fetchData();&lt;br&gt;
  }, []);&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And with that, you’ve successfully fetched your pages data from your project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AJoiJ5HwckKEyj_9LamrcEQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AJoiJ5HwckKEyj_9LamrcEQ.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Secure API and SDK Integration
&lt;/h2&gt;

&lt;p&gt;OneEntry ensures the security of your data with a dedicated API and SDK for JavaScript and Swift, guaranteeing seamless content management. Security measures include the utilization of mTLS certificates and an optional token-based authentication system. &lt;a href="https://www.cloudflare.com/learning/access-management/what-is-mutual-tls/" rel="noopener noreferrer"&gt;Mutual TLS (mTLS)&lt;/a&gt; is a protocol ensuring both client and server authenticate each other, a vital layer of security for protecting sensitive data and preventing unauthorized access. For a step-by-step guide, check &lt;a href="https://account.oneentry.cloud/materials/mtls" rel="noopener noreferrer"&gt;OneEntry’s material page&lt;/a&gt;, and if you’re setting up a Swift application, consult &lt;a href="https://oneentry.cloud/en/instructions#SWIFT" rel="noopener noreferrer"&gt;OneEntry’s SDK docs&lt;/a&gt; for a thorough walkthrough.&lt;/p&gt;

&lt;h2&gt;
  
  
  Backup
&lt;/h2&gt;

&lt;p&gt;Recognizing the paramount significance of data security and integrity, OneEntry incorporates a robust content backup feature. Automatic data backups are regularly executed to mitigate the risk of data loss, ensuring the safety and retrievability of your content in unforeseen circumstances. This feature not only instills peace of mind but also offers the assurance that your data is secure and can be restored as needed. While the system handles backups automatically, users also have the flexibility to trigger manual backups through the admin panel.&lt;/p&gt;

&lt;h2&gt;
  
  
  Attribute-based System
&lt;/h2&gt;

&lt;p&gt;OneEntry operates on an attribute-based system. This system allows you to create attribute sets for various elements such as pages, goods, news, blocks, etc. The built-in logic for linking attributes makes it easy to use through the admin panel. Users can edit, add, and delete attributes in a working project, providing flexibility and customization to suit your specific needs. This attribute-based structure is a powerful tool for data validation and content customization, including its usage for form building.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3200%2F0%2A-sbVo2sZMVY0IJPa" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3200%2F0%2A-sbVo2sZMVY0IJPa" alt="Attributes to pages"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Attribute Sets for Pages and Blocks
&lt;/h2&gt;

&lt;p&gt;Creating attribute sets for pages and blocks in OneEntry is straightforward. For pages, you can create attributes like Image and Text with Header. For blocks, you can create attributes like String and Image. These attributes allow you to customize your pages and blocks to suit your specific content needs. To do this, head over to content management, select your page and edit the attributes of your use case.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3200%2F0%2Axk4S2WcymQhhM7H1" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3200%2F0%2Axk4S2WcymQhhM7H1" alt="Attributes to pages"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Validation
&lt;/h2&gt;

&lt;p&gt;OneEntry uses attribute validators for data validation. This feature ensures that the data entered matches the specified attribute type, enhancing the integrity and reliability of your data. It simplifies the process of server-side validations, making it easier for developers to ensure data accuracy.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3200%2F0%2A582MwcmVTMII2jj2" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3200%2F0%2A582MwcmVTMII2jj2" alt="Data Attribute validation"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Module Overview
&lt;/h2&gt;

&lt;p&gt;OneEntry offers key modules such as Catalog, Menu, Forms, and Blocks. The Catalog module allows you to create text, catalogue, news and other pages, add forms, blocks and other elements to pages, and set up hierarchies. The Forms module lets you add/delete/edit fields, configure validation and placeholders, and set up interaction with the form. The Blocks module provides page elements showing the content, such as text or news.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3200%2F0%2AUvKruCpXasGOLNPM" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3200%2F0%2AUvKruCpXasGOLNPM" alt="Related data with catalo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating and Managing Menus
&lt;/h2&gt;

&lt;p&gt;OneEntry allows you to create menus and rearrange pages within the menu. You can also nest pages within each other, providing a hierarchical structure to your content. This feature offers flexibility in organizing your content and enhances the user experience.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F0%2Amt-oeuB5VLYByi0R" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F0%2Amt-oeuB5VLYByi0R" alt="managing menus-gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Customization using Blocks
&lt;/h2&gt;

&lt;p&gt;Blocks in OneEntry extend page content and provide flexibility in adding them to pages. They are page elements that display content such as text, or news. This feature allows for a high level of customization, enabling you to tailor your pages to your specific needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Multilingual Content Storage
&lt;/h2&gt;

&lt;p&gt;OneEntry supports storing content in multiple languages. This feature is particularly useful for businesses operating in multiple regions or countries, as it allows for content localization and enhances the user experience.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3200%2F0%2AmTCHCPmobvAOUti7" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3200%2F0%2AmTCHCPmobvAOUti7" alt="Multiple languages"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Product Catalog Relation
&lt;/h2&gt;

&lt;p&gt;OneEntry allows for linking products as “Related Products” in the catalogue. This feature facilitates better organization and presentation of product information, making it easier for users to find related products.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3200%2F0%2A7nYAY_1mnwqIJ5cu" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3200%2F0%2A7nYAY_1mnwqIJ5cu" alt="Related data with catalog"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Managing Product Statuses
&lt;/h2&gt;

&lt;p&gt;OneEntry allows you to manage product statuses. This feature is important in organizing and presenting products. It enables you to categorize products based on their status, making it easier for users to find what they are looking for.&lt;/p&gt;

&lt;h2&gt;
  
  
  Administrator Action Log
&lt;/h2&gt;

&lt;p&gt;OneEntry provides an administrator action log. This feature tracks and monitors administrative activities, providing transparency and accountability. It is a useful tool for auditing and tracking changes made by administrators.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3200%2F0%2A_Ohs6FjFYw6sKgVZ" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3200%2F0%2A_Ohs6FjFYw6sKgVZ" alt="admins"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional Features
&lt;/h2&gt;

&lt;p&gt;OneEntry offers several unique and notable features that make it a comprehensive Content Management System. It is a flexible, user-friendly, and scalable backend that allows you to manage all your websites and applications from a centralized dashboard. With OneEntry, you can deliver content at scale to multiple platforms like websites, mobile applications, electronic devices, IoTs, etc.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;OneEntry is a comprehensive, flexible, and user-friendly Content Management System that goes beyond traditional data storage. It is a complete content management solution that offers a wide range of tools and functionalities, designed to streamline content delivery processes and enhance digital experiences. Whether you’re a beginner or an experienced developer, OneEntry provides a platform that meets your needs, empowering you to create, manage, and deliver content effectively and efficiently. With OneEntry, you are not just managing your content; you are transforming how your content is presented and delivered to your audience.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://daiveedjay.hashnode.dev/oneentry-headless-content-management-system" rel="noopener noreferrer"&gt;https://daiveedjay.hashnode.dev&lt;/a&gt; on February 2, 2024.&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Building a Utility Weather Widget with JavaScript</title>
      <dc:creator>David Jaja</dc:creator>
      <pubDate>Mon, 19 Dec 2022 09:31:50 +0000</pubDate>
      <link>https://dev.to/daiveed/building-a-utility-weather-widget-with-javascript-5h6n</link>
      <guid>https://dev.to/daiveed/building-a-utility-weather-widget-with-javascript-5h6n</guid>
      <description>&lt;p&gt;We've all seen widgets on web pages before, haven't we? Those little icons of varying shapes and sizes usually displayed in a corner of a devices viewport. These widgets are simply small, pre-designed components that can be easily added to a website to provide additional functionality or information. They can be made using &lt;strong&gt;HTML&lt;/strong&gt; , &lt;strong&gt;CSS&lt;/strong&gt; , and &lt;strong&gt;JavaScript&lt;/strong&gt;. By hovering over or clicking on a widget, you can interact with it and see what it does. Examples of widgets include chatbots in the sidebar, pop-ups, and CTA buttons.&lt;/p&gt;

&lt;p&gt;In this article, we will learn how to build a widget that displays a user's current weather, date and time using their current location.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Why use Widgets?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;For one, you can use widgets to improve the visual organization and presentation of information on a website. Widgets can be added to a website to provide additional features or hide data that may create cluttered visual elements. They can also be used to display pop-ups and other types of information without making changes to the website's underlying code. By using widgets, you can effectively reduce clutter and improve the overall appearance of your website.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Fundamental knowledge of HTML, CSS and JavaScript.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fundamental knowledge of JavaScripts Native Internalization and Geolocation API.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fundamental knowledge of Asynchronous JavaScript (Using Promises and the &lt;strong&gt;&lt;em&gt;try catch&lt;/em&gt;&lt;/strong&gt; block).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A code editor and a browser (Preferably Google Chrome).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fundamental knowledge of the working of a Browsers Dev Tools.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Project Breakdown&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Before we dive into building our project, it is important to know that this project consists of 2 parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The Interface section&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The Functionality section&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;The Interface Section&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This section consists of all the mockup and styling required to render our widget on the page. Instead of diving head-first into the strange-looking HTML and CSS, I will give you a sneak preview of what the widget will look like in the end. This will help you understand why our codebase is structured the way it is.&lt;/p&gt;

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

&lt;p&gt;Excited right? Lets dive in!&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;&lt;em&gt;markup&lt;/em&gt;&lt;/strong&gt; for this project is shown below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;body&amp;gt;
    &amp;lt;div class="widget"&amp;gt;
      &amp;lt;div class="widget__blob"&amp;gt;
         &amp;lt;i class="fa-duotone fa-gear"&amp;gt;&amp;lt;/i&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;div class="widget__sidebar"&amp;gt;
        &amp;lt;div class="arrow__pointer"&amp;gt;&amp;lt;/div&amp;gt;
        &amp;lt;div class="weather"&amp;gt;
          &amp;lt;span class="greet"&amp;gt;Hi there, &amp;lt;/span&amp;gt;
          &amp;lt;i class="fa-solid fa-hand-wave"&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;br /&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;div class="date"&amp;gt;Placeholder Date&amp;lt;/div&amp;gt;
        &amp;lt;div class="color__palette--container"&amp;gt;
          &amp;lt;div class="color__palette" data-bgcolor="#5DADE2"&amp;gt;&amp;lt;/div&amp;gt;
          &amp;lt;div class="color__palette" data-bgcolor="#cf9fed"&amp;gt;&amp;lt;/div&amp;gt;
          &amp;lt;div class="color__palette" data-bgcolor="#73C6B6"&amp;gt;&amp;lt;/div&amp;gt;
          &amp;lt;div class="color__palette" data-bgcolor="#EDBB99"&amp;gt;&amp;lt;/div&amp;gt;
          &amp;lt;div class="color__palette" data-bgcolor="#808B96"&amp;gt;&amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;

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

&lt;/div&gt;



&lt;p&gt;I know the HTML markup looks weird with all the nesting and &lt;strong&gt;&lt;em&gt;data&lt;/em&gt;&lt;/strong&gt;  &lt;strong&gt;&lt;em&gt;attributes&lt;/em&gt;&lt;/strong&gt; 😂, so lets go over it. First, the main parent element is a &lt;strong&gt;&lt;em&gt;div&lt;/em&gt;&lt;/strong&gt; with the class &lt;strong&gt;&lt;em&gt;widget&lt;/em&gt;&lt;/strong&gt; containing 2 child elements, ( &lt;strong&gt;&lt;em&gt;widget__blob&lt;/em&gt;&lt;/strong&gt; ) and ( &lt;strong&gt;&lt;em&gt;widget__sidebar&lt;/em&gt;&lt;/strong&gt; ). The &lt;strong&gt;&lt;em&gt;widget__blob&lt;/em&gt;&lt;/strong&gt; contains only one element, which is an icon from &lt;a href="https://fontawesome.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;font awesome&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;&lt;em&gt;.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Next, the &lt;strong&gt;&lt;em&gt;widget__sidebar&lt;/em&gt;&lt;/strong&gt; contains 4 elements ( &lt;strong&gt;&lt;em&gt;arrow__pointer, weather, date&lt;/em&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;em&gt;color__palettecontainer&lt;/em&gt;&lt;/strong&gt; ), which are all self-explanatory. The only thing left to highlight is the &lt;strong&gt;&lt;em&gt;data-bgcolor&lt;/em&gt;&lt;/strong&gt; attribute attached to each of the &lt;strong&gt;&lt;em&gt;color-pallette&lt;/em&gt;&lt;/strong&gt; elements. This attribute will help us dynamically set each of the elements background to the value set in its &lt;strong&gt;&lt;em&gt;data-bgcolor&lt;/em&gt;&lt;/strong&gt; attribute. With the HTML set, we can now proceed to the CSS part of this section.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;&lt;em&gt;Styling&lt;/em&gt;&lt;/strong&gt; for this project is shown below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: "Ubuntu", sans-serif;
}

body {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh;
  background: #e0e0e0;
}

.widget {
  position: relative;
  width: 220px;
  height: 220px;
  display: flex;
  justify-content: center;
  align-items: center;
}

.widget__blob {
  width: 75%;
  height: 75%;
  cursor: pointer;
  background: #5dade2;
  border-radius: 68% 55% 46% 69% / 58% 74% 44% 59%;
  z-index: 2;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 4rem;
  color: #f0f4fd;
  transition: all ease-in 0.2s;
}

.widget__blob:hover &amp;gt; i {
  animation: blobby 10s infinite linear;
}

@keyframes blobby {
  0% {
    transform: rotate(0);
  }
  100% {
    transform: rotate(360deg);
  }
}

.widget__sidebar {
  color: #3d3d3d;
  position: absolute;
  top: 0;
  width: 170%;
  left: -200%;
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 1rem;
  gap: 1rem;
  line-height: 1.5;
  transition: all ease-in 0.2s;
  background: #5dade2;
  border-radius: 1rem;
}

.arrow__pointer {
  position: absolute;
  content: "";
  top: 50%;
  transform: rotate(45deg) translate(0, -50%);
  right: 0;
  background: #5dade2;
  width: 50px;
  height: 50px;
  transition: all ease-in 0.2s;
  z-index: -1;
}

.weather span {
  color: #fff;
  font-size: 1.6rem;
}

.weather i {
  font-size: 1.6rem;
  color: #fff;
}

.color__palette--container {
  display: flex;
  gap: 0.5rem;
}

.color__palette {
  width: 25px;
  height: 25px;
  border-radius: 50%;
  cursor: pointer;
}

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

&lt;/div&gt;



&lt;p&gt;There's quite a lot of CSS code there, so feel free to take a moment to analyze it before moving on. The styling above simply arranges the two child elements of the &lt;strong&gt;&lt;em&gt;widget&lt;/em&gt;&lt;/strong&gt; element next to each other and adds some interactivity to the &lt;strong&gt;&lt;em&gt;widget__blob&lt;/em&gt;&lt;/strong&gt; element.&lt;/p&gt;

&lt;p&gt;What weve achieved so far can be seen below&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1c56de8z79sahylnrmvl.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1c56de8z79sahylnrmvl.gif" width="600" height="283"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We neatly presented both elements and their contents, with only the elements in &lt;strong&gt;&lt;em&gt;color__palette--container&lt;/em&gt;&lt;/strong&gt; still yet to be displayed, but dont worry, we would fix that in the &lt;strong&gt;Functionality section.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;The Functionality Section&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This section consists of all our programs logic and how the widget would work. To help you grasp the totality of everything were going to do, heres a flowchart of our application.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Flowchart of the Application&lt;/strong&gt;&lt;/p&gt;

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

&lt;p&gt;Before we begin implementing, we should keep in mind that we will start on the right side with the &lt;strong&gt;&lt;em&gt;Load Page&lt;/em&gt;&lt;/strong&gt; symbol.&lt;/p&gt;

&lt;p&gt;Weve already added the widget to the webpage. Now, we will handle the behaviour when the widget is clicked. We want to hide the &lt;strong&gt;&lt;em&gt;widget__sidebar&lt;/em&gt;&lt;/strong&gt; element and only show it again when the &lt;strong&gt;&lt;em&gt;widget__blob&lt;/em&gt;&lt;/strong&gt; is clicked. To achieve this, we will create a CSS class that hides the &lt;strong&gt;&lt;em&gt;widget__sidebar&lt;/em&gt;&lt;/strong&gt; element and add that class to the &lt;strong&gt;&lt;em&gt;widget__sidebar&lt;/em&gt;&lt;/strong&gt; element in our HTML markup.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.hidden {
  opacity: 0;
  transform: translateX(-100%);
}

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

&lt;/div&gt;



&lt;p&gt;Then target the &lt;strong&gt;&lt;em&gt;widget__sidebar&lt;/em&gt;&lt;/strong&gt; element to render the &lt;strong&gt;&lt;em&gt;widget__sidebar&lt;/em&gt;&lt;/strong&gt; visible with JavaScript whenever we click on the &lt;strong&gt;&lt;em&gt;widget__blob&lt;/em&gt;&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const widgetBlob = document.querySelector(".widget__blob");
const widgetSideBar = document.querySelector(".widget__sidebar");

const revealSideBar = function () { widgetSideBar.classList.toggle("hidden"); 
};
widgetBlob.addEventListener("click", revealSideBar);

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

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl05f0u2fjbqbdvc8x7rl.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl05f0u2fjbqbdvc8x7rl.gif" width="600" height="325"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is a quick recap of how we just achieved this;&lt;/p&gt;

&lt;p&gt;First, we selected both elements and stored them in variables.&lt;/p&gt;

&lt;p&gt;Next, we created a function called &lt;strong&gt;&lt;em&gt;revealSideBar&lt;/em&gt;&lt;/strong&gt; which toggles the &lt;strong&gt;&lt;em&gt;hidden&lt;/em&gt;&lt;/strong&gt; class on the &lt;strong&gt;&lt;em&gt;widget__sidebar&lt;/em&gt;&lt;/strong&gt; element every time the &lt;strong&gt;&lt;em&gt;widget__blob&lt;/em&gt;&lt;/strong&gt; is clicked. Finally, we attached an event handler function to the &lt;strong&gt;&lt;em&gt;widget__blob&lt;/em&gt;&lt;/strong&gt; and passed the &lt;strong&gt;&lt;em&gt;revealSideBar&lt;/em&gt;&lt;/strong&gt; function as a callback. This means that the &lt;strong&gt;&lt;em&gt;revealSideBar&lt;/em&gt;&lt;/strong&gt; function will be called every time the &lt;strong&gt;&lt;em&gt;widget__blob&lt;/em&gt;&lt;/strong&gt; is clicked.&lt;/p&gt;

&lt;p&gt;The next step in our flowchart is to display the color palettes and the current date and time. To do this, we use the following lines of code to dynamically set the color of each palette element to its corresponding HTML data attribute value (recall we stored color codes in their individual &lt;strong&gt;data&lt;/strong&gt; attribute in our HTML markup).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const colorPalete = document.querySelectorAll(".color__palette");
colorPalete.forEach((el) =&amp;gt; (el.style.backgroundColor = el.dataset.bgcolor));

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

&lt;/div&gt;



&lt;p&gt;This simply loops over each element and changes the background color to the value set in its &lt;strong&gt;&lt;em&gt;data-bgcolor&lt;/em&gt;&lt;/strong&gt; attribute.&lt;/p&gt;

&lt;p&gt;Thus producing the interface below.&lt;/p&gt;

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

&lt;p&gt;Next, we work on displaying live date and time information on the &lt;strong&gt;&lt;em&gt;widget__sidebar.&lt;/em&gt;&lt;/strong&gt; To accomplish this, we would make use of &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl" rel="noopener noreferrer"&gt;&lt;strong&gt;&lt;em&gt;JavaScripts Internationalization API&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;&lt;em&gt;.&lt;/em&gt;&lt;/strong&gt; This API is a built-in feature of the JavaScript language that provides a set of functions and objects for formatting and parsing dates, numbers, and strings according to the conventions of a specific locale (ie the language format of the users location).&lt;/p&gt;

&lt;p&gt;To begin, we first select our HTML element where we plan to store our date and time information.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const dateEl = document.querySelector(".date");

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

&lt;/div&gt;



&lt;p&gt;After that, we retrieve the language preference of the user from the browser using &lt;strong&gt;&lt;em&gt;navigator.locale&lt;/em&gt;&lt;/strong&gt; and store it in the &lt;strong&gt;&lt;em&gt;locale&lt;/em&gt;&lt;/strong&gt; variable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const locale = navigator.language;

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

&lt;/div&gt;



&lt;p&gt;Logging my locale to the console, yields&lt;/p&gt;

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

&lt;p&gt;Then we create a date using the date constructor function and store the result in the &lt;strong&gt;&lt;em&gt;now&lt;/em&gt;&lt;/strong&gt; variable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const now = new Date();

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

&lt;/div&gt;



&lt;p&gt;Logging our result to the console gives:&lt;/p&gt;

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

&lt;p&gt;Remember that the date and time information will vary based on when you implement this.&lt;/p&gt;

&lt;p&gt;Next, we create a &lt;strong&gt;&lt;em&gt;date options&lt;/em&gt;&lt;/strong&gt; object which we would use to extract all the information we want from the date object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const dateOptions = {
    hour: "numeric",
    minute: "numeric",
    day: "numeric",
    month: "long",
    year: "numeric",
    weekday: "long",
  };

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

&lt;/div&gt;



&lt;p&gt;Then, we use our &lt;strong&gt;&lt;em&gt;Internationalization API&lt;/em&gt;&lt;/strong&gt; to format our date to the users locale. To do this, we first create our Internationalization function and store it in a variable with the syntax below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const curDate = new Intl.DateTimeFormat();

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

&lt;/div&gt;



&lt;p&gt;After that, we pass in our &lt;strong&gt;&lt;em&gt;locale&lt;/em&gt;&lt;/strong&gt; and our &lt;strong&gt;&lt;em&gt;dateOptions&lt;/em&gt;&lt;/strong&gt; object as arguments to our &lt;strong&gt;&lt;em&gt;Internationalization&lt;/em&gt;&lt;/strong&gt; function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const curDate = new Intl.DateTimeFormat(locale, dateOptions);

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

&lt;/div&gt;



&lt;p&gt;Then, we call the &lt;strong&gt;&lt;em&gt;format&lt;/em&gt;&lt;/strong&gt; method on the date were trying to format.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const curDate = new Intl.DateTimeFormat(locale, dateOptions).format(now);

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

&lt;/div&gt;



&lt;p&gt;Looking at what weve done in the console gives;&lt;/p&gt;

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

&lt;p&gt;Finally, we display our well-formatted data on our webpage.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; dateEl.textContent = `Your current date and time is ${curDate}`;

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

&lt;/div&gt;



&lt;p&gt;With that, lets have a look at our interface so far.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3i5qcl58fokidxwarl5b.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3i5qcl58fokidxwarl5b.gif" width="600" height="311"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And yeah, weve successfully implemented live date and time information which is already pretty cool. Lets refactor our new code into a nice helper function &lt;strong&gt;&lt;em&gt;getDnT&lt;/em&gt;&lt;/strong&gt; which contains all our date and time logic.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const getDnT = function () {
  const now = new Date();
  const dateOptions = {
    hour: "numeric",
    minute: "numeric",
    day: "numeric",
    month: "long",
    year: "numeric",
    weekday: "long",
  };
  const locale = navigator.language;
  const curDate = new Intl.DateTimeFormat(locale, dateOptions).format(now);
  dateEl.textContent = `Your current date and time is ${curDate}`;
};

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

&lt;/div&gt;



&lt;p&gt;Finally, we call the &lt;strong&gt;&lt;em&gt;getDnT&lt;/em&gt;&lt;/strong&gt; function with the same event handler function we called the &lt;strong&gt;&lt;em&gt;revealSideBar&lt;/em&gt;&lt;/strong&gt; function, like so&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;widgetBlob.addEventListener("click", function () {
  revealSideBar();
  getDnT();
});

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; : Instead of calling our function manually, we can attach it to an event handler function. This will prevent the function from constantly running in the background, which can improve performance.&lt;/p&gt;

&lt;p&gt;To clarify the next step, we will change the theme of the &lt;strong&gt;&lt;em&gt;widget_sidebar&lt;/em&gt;&lt;/strong&gt; , &lt;strong&gt;&lt;em&gt;arrow__pointer&lt;/em&gt;&lt;/strong&gt; , and &lt;strong&gt;&lt;em&gt;widget__blob&lt;/em&gt;&lt;/strong&gt; based on the color palette that we click.&lt;/p&gt;

&lt;p&gt;Id like to divide this step into 3 sub-steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Theme Changing&lt;/strong&gt; (Changing the theme based on the palette we click).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Active Class Addition&lt;/strong&gt; (Adding an active class to the current palette we clicked on).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Local Storage Use&lt;/strong&gt; ( Storing the active theme in local storage to prevent the theme from resetting on reload of the webpage).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Theme Changing&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;For this first step, we create a &lt;strong&gt;&lt;em&gt;themeChanger&lt;/em&gt;&lt;/strong&gt; function containing all the swapping logic between our target elements.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const arrowPointer = document.querySelector(".arrow__pointer");
const themeChanger = function (e) {
  widgetSideBar.style.backgroundColor = e.target.dataset.bgcolor;
  widgetBlob.style.backgroundColor = e.target.dataset.bgcolor;
  arrowPointer.style.backgroundColor = e.target.dataset.bgcolor;
};

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

&lt;/div&gt;



&lt;p&gt;The &lt;strong&gt;&lt;em&gt;e&lt;/em&gt;&lt;/strong&gt; argument is simply the event object which points to the current element being clicked. Then, we loop over each &lt;strong&gt;&lt;em&gt;color__palette&lt;/em&gt;&lt;/strong&gt; element, attach an event handler, and pass in the &lt;strong&gt;&lt;em&gt;themeChanger&lt;/em&gt;&lt;/strong&gt; function as an argument. This runs our &lt;strong&gt;&lt;em&gt;themeChanger&lt;/em&gt;&lt;/strong&gt; function everytime we click on a palette.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;colorPalete.forEach((el) =&amp;gt; {
  el.addEventListener("click", themeChanger);
});

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

&lt;/div&gt;



&lt;p&gt;We have successfully implemented the first step of our theme changer function.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzfnsuhbn1cdchjgj04sd.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzfnsuhbn1cdchjgj04sd.gif" width="600" height="296"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Active Class Addition&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;If you paid attention, you may have noticed that whenever we click on a palette, it appears to blend in and disappear with the background. We plan to fix this by adding an active class to any element we click on, which will make it easier to see which element is currently selected. We first create a CSS active class which separates the active palette from the rest.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.color__palette--active {
  border: 1.5px solid #fff;
}

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

&lt;/div&gt;



&lt;p&gt;Then, we add that active class to any palette we click on using the code snippet below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; e.target.classList.add("color__palette--active");

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

&lt;/div&gt;



&lt;p&gt;Finally, to ensure that only the clicked palette has the active class, we need to remove the active class from all other palettes. This way, when a new palette is clicked, it will be the only one palette with an active class. This will help us achieve the desired behaviour where only one palette can be active at a time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;colorPalete.forEach((el) =&amp;gt; el.classList.remove("color__palette--active"));

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; : We're adding the above code snippets to our &lt;strong&gt;&lt;em&gt;themeChanger&lt;/em&gt;&lt;/strong&gt; function so that we can add the active class when we toggle between themes.&lt;/p&gt;

&lt;p&gt;This leaves our final function looking something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const themeChanger = function (e) {
  widgetSideBar.style.backgroundColor = e.target.dataset.bgcolor;
  widgetBlob.style.backgroundColor = e.target.dataset.bgcolor;
  arrowPointer.style.backgroundColor = e.target.dataset.bgcolor;
  colorPalete.forEach((el) =&amp;gt; el.classList.remove("color__palette--active"));
  e.target.classList.add("color__palette--active");
};

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

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3gv1ck861v8b8n7tr82w.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3gv1ck861v8b8n7tr82w.gif" width="600" height="288"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Local Storage Use&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;In the third step, we will use &lt;strong&gt;&lt;em&gt;Local Storage&lt;/em&gt;&lt;/strong&gt; to save the theme that the user has selected. This way, their theme selection will be retained even if the user refreshes the page or closes it. To do this, we have to store the current theme in &lt;strong&gt;&lt;em&gt;Local Storage&lt;/em&gt;&lt;/strong&gt; and load that theme whenever the user refreshes the page. Seems fairly easy? Lets begin then.&lt;/p&gt;

&lt;p&gt;First, we call the &lt;strong&gt;&lt;em&gt;setItem&lt;/em&gt;&lt;/strong&gt; method on the &lt;strong&gt;&lt;em&gt;LocalStorage&lt;/em&gt;&lt;/strong&gt; object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;localStorage.setItem();

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

&lt;/div&gt;



&lt;p&gt;This method enables us to store data in the browser and create a &lt;strong&gt;key: value&lt;/strong&gt; pair, with the &lt;strong&gt;&lt;em&gt;key&lt;/em&gt;&lt;/strong&gt; being a name used to reference the stored value in &lt;strong&gt;&lt;em&gt;Local Storage.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Next, we pass in &lt;strong&gt;key: value&lt;/strong&gt; pair into our &lt;strong&gt;&lt;em&gt;setItem&lt;/em&gt;&lt;/strong&gt; method&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;localStorage.setItem("palette", color);

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

&lt;/div&gt;



&lt;p&gt;Keep in mind that the &lt;strong&gt;&lt;em&gt;color&lt;/em&gt;&lt;/strong&gt; argument would be the value stored in the palette we click.&lt;/p&gt;

&lt;p&gt;Next we wrap our above snippet in a function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const setLocalStorage = function (color) {
  localStorage.setItem("palette", color);
};

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

&lt;/div&gt;



&lt;p&gt;This way, whatever value is being called with the &lt;strong&gt;&lt;em&gt;setLocalStorage&lt;/em&gt;&lt;/strong&gt; function becomes &lt;strong&gt;&lt;em&gt;color&lt;/em&gt;&lt;/strong&gt; value.&lt;/p&gt;

&lt;p&gt;Next, we call the &lt;strong&gt;&lt;em&gt;setLocalStorage&lt;/em&gt;&lt;/strong&gt; function with the element that was clicked.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;setLocalStorage(e.target.dataset.bgcolor);

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

&lt;/div&gt;



&lt;p&gt;Note: To ensure that Local Storage is updated with the current theme, we call this function inside the &lt;strong&gt;&lt;em&gt;themeChanger&lt;/em&gt;&lt;/strong&gt; function.&lt;/p&gt;

&lt;p&gt;To prove &lt;strong&gt;Local Storage&lt;/strong&gt; is operational, head over to your developer tools, open the application tab, and then click on a palette.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fis1t6d59cyxpj3r1rguy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fis1t6d59cyxpj3r1rguy.gif" width="600" height="319"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you observe closely, each time we click on a palette, the local storage theme value is updated, proving weve successfully saved the current theme value.&lt;/p&gt;

&lt;p&gt;To ensure that we dont lose our theme when we reload or exit the webpage, we retrieve our theme from local storage and update our interface. To implement this, we start by listening for the &lt;strong&gt;&lt;em&gt;load event.&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;window.addEventListener("load", function () {});

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

&lt;/div&gt;



&lt;p&gt;Next, we retrieve the value stored in our &lt;strong&gt;&lt;em&gt;Local Storage&lt;/em&gt;&lt;/strong&gt; using its &lt;strong&gt;&lt;em&gt;key&lt;/em&gt;&lt;/strong&gt; and store it in a variable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const paletteColor = localStorage.getItem("palette");

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

&lt;/div&gt;



&lt;p&gt;After that, we change the theme of all our targetted elements to the value stored in &lt;strong&gt;Local Storage.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;widgetSideBar.style.backgroundColor = paletteColor;
widgetBlob.style.backgroundColor = paletteColor;
arrowPointer.style.backgroundColor = paletteColor;

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

&lt;/div&gt;



&lt;p&gt;Next, we clear all the active classes on the palette elements&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;colorPalete.forEach((el) =&amp;gt; el.classList.remove("color__palette--active"));

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

&lt;/div&gt;



&lt;p&gt;Finaly, we select the palette whose data attribute value matches that value stored in the Local Storage, and add the active class to it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const btn = document.querySelector(
    `.color__palette[data-bgcolor="${paletteColor}"]`
  );
btn.classList.add("color__palette--active");

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

&lt;/div&gt;



&lt;p&gt;We have successfully completed all the steps on the right side of our flowchart. Congratulations on making it this far 🎈, but we still have more work to do.&lt;/p&gt;

&lt;p&gt;Next up, wed be working on adding live weather information using asynchronous JavaScript ( promises and the &lt;strong&gt;&lt;em&gt;try catch&lt;/em&gt;&lt;/strong&gt; block. ).&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding Weather functionality to the Widget using Asynchronous JavaScript
&lt;/h2&gt;

&lt;p&gt;A code is asynchronous if it can execute multiple lines of code at the same time, rather than executing them one at a time in the order in which they appear.&lt;/p&gt;

&lt;p&gt;In JavaScript, asynchronous code is typically written using &lt;strong&gt;&lt;em&gt;callback functions&lt;/em&gt;&lt;/strong&gt; , &lt;strong&gt;&lt;em&gt;promises&lt;/em&gt;&lt;/strong&gt; , or &lt;strong&gt;&lt;em&gt;async/await&lt;/em&gt;&lt;/strong&gt;. These techniques allow the JavaScript engine to execute multiple lines of code concurrently, rather than executing them sequentially. In this step, were going to use &lt;strong&gt;&lt;em&gt;promises&lt;/em&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;em&gt;async/await&lt;/em&gt;&lt;/strong&gt;. techniques to fetch the users current position and supply the user with weather data corresponding with their location.&lt;/p&gt;

&lt;p&gt;The steps to achieving this include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Promisifying the Geolocation API.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Catching the error produced when the &lt;strong&gt;&lt;em&gt;Geolocation API&lt;/em&gt;&lt;/strong&gt; promise fails.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Creating an async function to contain all our logic.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Extracting the users coordinates.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fetching the users city data with the users coordinates.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Throwing an error if the users city data cannot be obtained.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fetching the users weather data with the users coordinates.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Throwing an error if the users city weather data cannot be obtained.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Destructuring the weather data object to get the weather value.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Storing the final weather data string in a variable.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Inserting the weather data in our webpage.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const getPosition = function () {
  return new Promise(function (resolve, reject) {
    navigator.geolocation.getCurrentPosition(resolve, reject);
  });
};

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

&lt;/div&gt;



&lt;p&gt;Keep in mind that calling this function right now returns a promise and not the data gotten from the &lt;strong&gt;Geolocation&lt;/strong&gt; function.&lt;/p&gt;

&lt;p&gt;Next, we catch any errors formed when the Geolocation promise fails (i.e, the user refuses to share their location data).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;getPosition().catch((err) =&amp;gt;
  alert(`${err.message}. Please grant location access to see weather data`)
);

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

&lt;/div&gt;



&lt;p&gt;After that, we create our async function which includes a &lt;strong&gt;&lt;em&gt;trycatch&lt;/em&gt;&lt;/strong&gt; block to contain all our logic.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const whereAmI = async function () {
  try {
  } catch {}
};

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

&lt;/div&gt;



&lt;p&gt;To extract the users coordinates (latitude and longitude), we simply &lt;strong&gt;&lt;em&gt;await&lt;/em&gt;&lt;/strong&gt; the values from the &lt;strong&gt;&lt;em&gt;getPosition&lt;/em&gt;&lt;/strong&gt; function, then deconstruct the result into 2 variables.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const position = await getPosition();
const { latitude, longitude } = position.coords;

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

&lt;/div&gt;



&lt;p&gt;Next, we use a &lt;strong&gt;&lt;em&gt;Reverse Geolocation API&lt;/em&gt;&lt;/strong&gt; to convert our coordinates into a defined city. Ill be using &lt;a href="https://geocode.xyz/" rel="noopener noreferrer"&gt;Geocode XYZs Reverse Geolocation API&lt;/a&gt; to perform this operation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const responseGeo = await fetch( `https://geocode.xyz/${latitude},${longitude}?geoit=json&amp;amp;auth=YOUR_API_KEY`
    );

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

&lt;/div&gt;



&lt;p&gt;Our result in the console becomes&lt;/p&gt;

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

&lt;p&gt;If an error occurs during the &lt;strong&gt;&lt;em&gt;fetch&lt;/em&gt;&lt;/strong&gt; operation, we handle that by using an error constructor function to throw an error message.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (!responseGeo.ok) throw new Error("Problem getting location data");

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

&lt;/div&gt;



&lt;p&gt;If no error occurs, we convert the result of our fetch function to an object using the &lt;strong&gt;&lt;em&gt;.json()&lt;/em&gt;&lt;/strong&gt; method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const dataGeo = await responseGeo.json();

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

&lt;/div&gt;



&lt;p&gt;Next, we use a &lt;strong&gt;&lt;em&gt;Weather API&lt;/em&gt;&lt;/strong&gt; to fetch the users weather information based on their current position. Well be using &lt;a href="https://open-meteo.com/" rel="noopener noreferrer"&gt;Open Metros API&lt;/a&gt; to get our weather data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const weatherResponse = await fetch(
      `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&amp;amp;longitude=${longitude}&amp;amp;hourly=temperature_2m`
    );

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

&lt;/div&gt;



&lt;p&gt;Our result in the console becomes&lt;/p&gt;

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

&lt;p&gt;We also account for errors during the fetch operation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (!weatherResponse.ok) throw new Error("Problem getting Weather data");

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

&lt;/div&gt;



&lt;p&gt;Then convert the value of the fetch function to an object if we do not encounter any errors.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const weatherData = await weatherResponse.json();

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

&lt;/div&gt;



&lt;p&gt;We then deconstruct our &lt;strong&gt;&lt;em&gt;weatherData&lt;/em&gt;&lt;/strong&gt; object to obtain the exact current weather value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const [curWeather] = weatherData.hourly.temperature_2m;

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

&lt;/div&gt;



&lt;p&gt;After that, we create a string which contains the format for displaying our weather on our webpage.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const finalWeather = `The weather in ${dataGeo.region} right now is ${curWeather} ${weatherData.hourly_units.temperature_2m}`;

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

&lt;/div&gt;



&lt;p&gt;Logging our progress to the console so far gives:&lt;/p&gt;

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

&lt;p&gt;The resulting data will vary based on your location, but the format would likely be similar.&lt;/p&gt;

&lt;p&gt;Then, we insert the above string into our webpage&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const weatherEl = document.querySelector(".weather");
 weatherEl.insertAdjacentText("beforeend", finalWeather);

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

&lt;/div&gt;



&lt;p&gt;And with this, weve successfully completed our widget, congratulations!🎉🎉&lt;/p&gt;

&lt;p&gt;Only thing left to do is catch any errors that we may not have caught earlier using the catch block and log that to the console.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;catch (err) {
    console.log(`${err} 💥💥💥`);
  }

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

&lt;/div&gt;



&lt;p&gt;Then calling our function in the global scope.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;whereAmI();

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

&lt;/div&gt;



&lt;p&gt;Our final codebase looks something like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const setLocalStorage = function (color) {
  localStorage.setItem("palette", color);
};

const widget = document.querySelector(".widget");
const widgetBlob = document.querySelector(".widget__blob");
const widgetSideBar = document.querySelector(".widget__sidebar");
const arrowPointer = document.querySelector(".arrow__pointer");
const weatherEl = document.querySelector(".weather");
const paletteContainer = document.querySelector(".color__palette--container");
const colorPalete = document.querySelectorAll(".color__palette");
const dateEl = document.querySelector(".date");

window.addEventListener("load", function () {
  const paletteColor = localStorage.getItem("palette");
  widgetSideBar.style.backgroundColor = paletteColor;
  widgetBlob.style.backgroundColor = paletteColor;
  arrowPointer.style.backgroundColor = paletteColor;

  const btn = document.querySelector(
    `.color__palette[data-bgcolor="${paletteColor}"]`
  );
  colorPalete.forEach((el) =&amp;gt; el.classList.remove("color__palette--active"));
  btn.classList.add("color__palette--active");
});

const revealSideBar = function () {
  widgetSideBar.classList.toggle("hidden");
};

widgetBlob.addEventListener("click", function () {
  revealSideBar();
  getDnT();
});

colorPalete.forEach((el) =&amp;gt; (el.style.backgroundColor = el.dataset.bgcolor));

const themeChanger = function (e) {
  widgetSideBar.style.backgroundColor = e.target.dataset.bgcolor;
  widgetBlob.style.backgroundColor = e.target.dataset.bgcolor;
  arrowPointer.style.backgroundColor = e.target.dataset.bgcolor;
  colorPalete.forEach((el) =&amp;gt; el.classList.remove("color__palette--active"));
  e.target.classList.add("color__palette--active");
  setLocalStorage(e.target.dataset.bgcolor);
};

colorPalete.forEach((el) =&amp;gt; {
  el.addEventListener("click", themeChanger);
});

document.addEventListener("keydown", function (e) {
  if (e.key === "Escape" &amp;amp;&amp;amp; !widgetSideBar.classList.contains("hidden")) {
    widgetSideBar.classList.toggle("hidden");
  }
});

const getDnT = function () {
  const now = new Date();
  const dateOptions = {
    hour: "numeric",
    minute: "numeric",
    day: "numeric",
    month: "long",
    year: "numeric",
    weekday: "long",
  };

  const locale = navigator.language;

  const curDate = new Intl.DateTimeFormat(locale, dateOptions).format(now);

  dateEl.textContent = `Your current date and time is ${curDate}`;
};

const getPosition = function () {
  return new Promise(function (resolve, reject) {
    navigator.geolocation.getCurrentPosition(resolve, reject);
  });
};

getPosition().catch((err) =&amp;gt;
  alert(`${err.message}. Please grant location access`)
);

const whereAmI = async function () {
  try {
    const position = await getPosition();
    const { latitude, longitude } = position.coords;
    const responseGeo = await fetch(
      `https://geocode.xyz/${latitude},${longitude}?geoit=json&amp;amp;auth=YOUR_API_KEY`
    );

    if (!responseGeo.ok) throw new Error("Problem getting location data");
    const dataGeo = await responseGeo.json();

    const weatherResponse = await fetch(
      `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&amp;amp;longitude=${longitude}&amp;amp;hourly=temperature_2m`
    );
    if (!weatherResponse.ok) throw new Error("Problem getting Weather data");

    const weatherData = await weatherResponse.json();
    const [curWeather] = weatherData.hourly.temperature_2m;

    const finalWeather = `The weather in ${dataGeo.region} right now is ${curWeather} ${weatherData.hourly_units.temperature_2m}`;

    weatherEl.insertAdjacentText("beforeend", finalWeather);
  } catch (err) {
    console.log(`${err} 💥💥💥`);
  }
};
whereAmI();

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

&lt;/div&gt;



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

&lt;p&gt;As you can see, our utility widget is fully operational, good going! It displays accurate time, date and weather information all at the click of a button, pretty cool, dont you think?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Limitation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Despite our best efforts to build a cool application, it does have a limitation. Both APIs used during implementation were free APIs, meaning that they can only handle a limited number of API calls per second. This hinders our widget from being a full-scale application that can be used by a large number of people simultaneously.&lt;/p&gt;

&lt;h3&gt;
  
  
  Project Link
&lt;/h3&gt;

&lt;p&gt;Source Code: &lt;a href="https://github.com/Daiveedjay/Utility-Widget-Article" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;We successfully built a utility widget using JavaScript that can provide us with the current weather, date, and time. This widget utilizes the &lt;strong&gt;&lt;em&gt;fetch()&lt;/em&gt;&lt;/strong&gt; function to retrieve data from a &lt;strong&gt;&lt;em&gt;Weather API&lt;/em&gt;&lt;/strong&gt; and the &lt;strong&gt;&lt;em&gt;Date object&lt;/em&gt;&lt;/strong&gt; to access the current date and time. By implementing this widget, we have demonstrated the power of JavaScript in creating dynamic and useful web applications. With a few lines of code, we are able to access real-time data and display it in a user-friendly manner, making it easy for users to stay informed and up-to-date. Overall, this widget serves as a useful tool for anyone looking to quickly check the current weather, date and time.&lt;/p&gt;

</description>
      <category>watercooler</category>
    </item>
    <item>
      <title>Implementing image lazy loading to improve website performance using JavaScript</title>
      <dc:creator>David Jaja</dc:creator>
      <pubDate>Wed, 16 Nov 2022 09:09:38 +0000</pubDate>
      <link>https://dev.to/daiveed/implementing-image-lazy-loading-to-improve-website-performance-using-javascript-be8</link>
      <guid>https://dev.to/daiveed/implementing-image-lazy-loading-to-improve-website-performance-using-javascript-be8</guid>
      <description>&lt;p&gt;You know that feeling of logging into a website but having to wait an extra few seconds before you can efficiently navigate the page because the images haven't loaded completely? Annoying, right? 😅 Well, this situation typically occurs based on one of the following reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A slow internet connection.&lt;/li&gt;
&lt;li&gt;An older (slower) device.&lt;/li&gt;
&lt;li&gt;The size of the image being fetched by the browser.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With the use of graphic assets(images) on websites for aesthetics, illustration, data representation, and several other reasons, there is a need to find more efficient ways of quickly delivering them to the users. Hence, the need for the implementation of lazy loading in images.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Fundamental knowledge of HTML, CSS and JavaScript.&lt;/li&gt;
&lt;li&gt;Fundamental knowledge of JavaScripts Intersection API.&lt;/li&gt;
&lt;li&gt;A code editor and a browser (Preferably one that supports JavaScripts Intersection API eg Google Chrome).&lt;/li&gt;
&lt;li&gt;Fundamental knowledge of the working of a Browsers Dev Tools.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is lazy loading?
&lt;/h2&gt;

&lt;p&gt;Put plainly, lazy loading is a technique in web development where the loading of resources is postponed on a page until they are needed rather than loading them immediately after the page loads. This technique helps to improve user experience, makes better use of the device's resources, and helps optimize page performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Lazy Load at All?
&lt;/h2&gt;

&lt;p&gt;If the user never scrolls to the point on the page where the image resides, then there is never a need to load it in the first place, leading to increased website performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Methods of Lazy Loading
&lt;/h2&gt;

&lt;p&gt;Some methods of performing lazy loading include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use of JavaScript libraries eg &lt;strong&gt;&lt;em&gt;Layzr.js&lt;/em&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Triggering the image loading using native JavaScript.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is an Intersection Observer API?
&lt;/h2&gt;

&lt;p&gt;The Intersection Observer API is a native JavaScript API that allows the browser to observe changes according to the way a specific target element intersects another element in the DOM. It is also a great way to keep track of how much of an element is visible on the screen.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does the Intersection Observer API work?
&lt;/h2&gt;

&lt;p&gt;The Intersection Observer API watches an element or elements to see if it intersects (meets or passes through) another element in the DOM. It can also be set up to watch for intersections between an element and the browser's viewport. The intersection observer function watches for a specified intersection event and fires a callback function when that event occurs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; : A callback function is a normal function passed to another function as that functions argument.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a simple Intersection Observer
&lt;/h2&gt;

&lt;p&gt;To create an Intersection Observer, we would need to adhere to a couple of steps.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Define the Intersection Observer function itself.&lt;/li&gt;
&lt;li&gt;Call the &lt;strong&gt;&lt;em&gt;observe&lt;/em&gt;&lt;/strong&gt; method on the element we wish to observe.&lt;/li&gt;
&lt;li&gt;Define our observer callback function.&lt;/li&gt;
&lt;li&gt;Define our observer options object.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I know all this seems pretty complex, so Ill break it down into smaller, more manageable steps.&lt;/p&gt;

&lt;p&gt;Firstly, we initialize and store our Intersection Observer function in a variable using the syntax below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const observer = new IntersectionObserver();

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

&lt;/div&gt;



&lt;p&gt;The IntersectionObserver function takes in two arguments as parameters, i.e., an observer options object and a callback function, but more about that later.&lt;/p&gt;

&lt;p&gt;After initializing the IntersectionObserver API, we have to specify which element we wish to observe using the &lt;em&gt;observe&lt;/em&gt; method. To do this, we call the &lt;strong&gt;&lt;em&gt;observe&lt;/em&gt;&lt;/strong&gt; method on our observer API and pass the element were trying to observe to the &lt;strong&gt;&lt;em&gt;observe&lt;/em&gt;&lt;/strong&gt; method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;observer.observe(h1);

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

&lt;/div&gt;



&lt;p&gt;In this case, weve chosen to observe the h1 element.&lt;/p&gt;

&lt;p&gt;Next, we specify or define our Observer callback function. This callback function holds what we want the observed element to do or how we want it to behave.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const observerCallback = function () {};

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

&lt;/div&gt;



&lt;p&gt;Finally, we define the observer options object i.e., the second argument passed to our observer function. This is used to customize the intersection event; and before creating this, we must first understand the contents of this object. This object contains the following properties:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;root&lt;/strong&gt; : This is the root element that our target element is intersecting. For reference, our target element is the h1 element we just recently observed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;threshold&lt;/strong&gt; : This is the percentage of the root element at which the event is triggered. To better explain it, let's use an example of a swimming pool as the root element. How deep should a person (target element) dive into the pool (root element) before it is considered an intersection. Similarly, the threshold is the intersection required before the Intersection observer event is fired and its callback function (observerCallback) is executed. To set the threshold value, we use numbers between 0 to 1 to indicate the value from 0% to 100%.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Creating the observer options object becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const observerCallback = {
    root: null,
    threshold: 0.1,
};

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; : If the &lt;strong&gt;&lt;em&gt;root&lt;/em&gt;&lt;/strong&gt; element is unspecified, or set to &lt;strong&gt;&lt;em&gt;null&lt;/em&gt;&lt;/strong&gt; , the &lt;strong&gt;&lt;em&gt;root&lt;/em&gt;&lt;/strong&gt; element becomes the entire browsers viewport, just as weve done in our code sample above.&lt;/p&gt;

&lt;p&gt;Considering this article isnt intended on explaining the workings of the JavaScript Intersection Observer extensively, Ill recommend the following articles for a better understanding.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://daveyhert.hashnode.dev/revealing-contents-on-scroll-using-javascripts-intersection-observer-api" rel="noopener noreferrer"&gt;Revealing Contents on Scroll Using JavaScripts Intersection Observer API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://daveyhert.hashnode.dev/revealing-multiple-content-on-scroll-using-javascripts-intersection-observer" rel="noopener noreferrer"&gt;Revealing Multiple contents on Scroll Using JavaScripts Intersection Observer API&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, that were familiar with JavaScripts intersection Observer API, lets dive into the actual implementation of the lazy loading feature.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating Lazy Loading Images with JavaScripts Intersection Observer
&lt;/h2&gt;

&lt;p&gt;The main idea behind image lazy loading is to showcase a low-resolution/size version of the image (that is faster to download) when the page loads, and then replace that image with the final higher-quality image when the user scrolls to where the image is located on the webpage. Lazy loading logic can be made possible through JavaScripts native Intersection Observer API with the following steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check for the users current viewport when the page loads.&lt;/li&gt;
&lt;li&gt;Check for intersections between the viewport and the target element.&lt;/li&gt;
&lt;li&gt;Swap the low-resolution image for its high-resolution alternative when the target element intersects with the viewport.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Considering the size of our project to be built, we would divide the implementation into three phases;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The mockup phase ( Webpage Creation)&lt;/li&gt;
&lt;li&gt;The CSS phase ( Webpage Designing )&lt;/li&gt;
&lt;li&gt;The JavaScript phase ( Functionality development )&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Keep in mind that we would only explain the essential parts of the first two stages of implementation.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Mockup phase
&lt;/h3&gt;

&lt;p&gt;This phase consists of all the HTML markup we are going to need for the project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;body&amp;gt;
    &amp;lt;header&amp;gt;
      &amp;lt;h1&amp;gt;Just a header&amp;lt;/h1&amp;gt;
    &amp;lt;/header&amp;gt;
    &amp;lt;main&amp;gt;
      &amp;lt;div class="image__container"&amp;gt;
        &amp;lt;img
          src="./img/digital-lazy.jpg"
          data-src="./img/digital.jpg"
          alt="Computer"
          class="section__img"
        /&amp;gt;
        &amp;lt;div class="image__description"&amp;gt; Lorem ipsum dolor sit amet consectetur adipisicing elit.Quas iusto eius sapiente distinctio aut quaerat ab. Necessitatibus provident esse repudiandae culpa officiis libero minus, consequatur incidunt voluptates repellat sunt cum?
        &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;div class="image__container"&amp;gt;
        &amp;lt;div class="image__description"&amp;gt;
         Lorem ipsum dolor sit amet consectetur adipisicing elit.Quas iusto eius sapiente distinctio aut quaerat ab. Necessitatibus provident esse repudiandae culpa officiis libero minus, consequatur incidunt voluptates repellat sunt cum?
        &amp;lt;/div&amp;gt;
        &amp;lt;img
          src="./img/card-lazy.jpg"
          data-src="./img/card.jpg"
          alt="Card"
          class="section__img"
        /&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;div class="image__container"&amp;gt;
        &amp;lt;img
          src="./img/grow-lazy.jpg"
          data-src="./img/grow.jpg"
          alt="Plant"
          class="section__img"
        /&amp;gt;
        &amp;lt;div class="image__description"&amp;gt;
         Lorem ipsum dolor sit amet consectetur adipisicing elit.Quas iusto eius sapiente distinctio aut quaerat ab. Necessitatibus provident esse repudiandae culpa officiis libero minus, consequatur incidunt voluptates repellat sunt cum?
        &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/main&amp;gt;
    &amp;lt;footer&amp;gt;&amp;lt;h1&amp;gt;Just a footer&amp;lt;/h1&amp;gt;&amp;lt;/footer&amp;gt;
  &amp;lt;/body&amp;gt;

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

&lt;/div&gt;



&lt;p&gt;Its a little overwhelming, I know. Lets go over it then. We created three sections; a &lt;strong&gt;header&lt;/strong&gt; section, the &lt;strong&gt;main&lt;/strong&gt; section, and a &lt;strong&gt;footer&lt;/strong&gt; section.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;header&lt;/strong&gt; section only contains a heading text, which would be helpful when scrolling into our observed elements.&lt;/p&gt;

&lt;p&gt;We created three sections; a &lt;strong&gt;&lt;em&gt;header&lt;/em&gt;&lt;/strong&gt; section, the &lt;em&gt;main&lt;/em&gt; section, and a &lt;strong&gt;&lt;em&gt;footer&lt;/em&gt;&lt;/strong&gt; section. The &lt;strong&gt;&lt;em&gt;header&lt;/em&gt;&lt;/strong&gt; section only contains a heading text, which would be helpful when scrolling into our observed elements. The &lt;strong&gt;&lt;em&gt;main&lt;/em&gt;&lt;/strong&gt; section consists of three child elements named ( &lt;strong&gt;&lt;em&gt;image__container&lt;/em&gt;&lt;/strong&gt; ). Each of these three children elements contain two child elements (an &lt;strong&gt;&lt;em&gt;img&lt;/em&gt;&lt;/strong&gt; element and a &lt;strong&gt;&lt;em&gt;div&lt;/em&gt;&lt;/strong&gt; ). Finally, the &lt;strong&gt;&lt;em&gt;footer&lt;/em&gt;&lt;/strong&gt; section contains a heading text.&lt;/p&gt;

&lt;p&gt;After taking a closer look at the HTML markup, you may notice that each &lt;em&gt;img&lt;/em&gt; element contains two similar attributes: the &lt;strong&gt;&lt;em&gt;src&lt;/em&gt;&lt;/strong&gt; and the &lt;strong&gt;&lt;em&gt;data-src&lt;/em&gt;&lt;/strong&gt; attribute. These attributes would be useful in implementing the lazy loading feature because they are the attributes that contain the images we are swapping. The &lt;strong&gt;&lt;em&gt;src&lt;/em&gt;&lt;/strong&gt; attributes contain the initial low-resolution images and the &lt;strong&gt;&lt;em&gt;data-src&lt;/em&gt;&lt;/strong&gt; attributes, are custom attributes containing the high-resolution images.&lt;/p&gt;

&lt;p&gt;The HTML markup looks like this;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvmmc6u6euda56xv5vzr1.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvmmc6u6euda56xv5vzr1.gif" alt="Raw-Html-2.gif" width="800" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The CSS phase
&lt;/h3&gt;

&lt;p&gt;Then, for the CSS, we have the following codes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;header {
  border-bottom: 1px dashed #888;
}

header,
footer {
  height: 100vh;
  width: 100%;
  display: grid;
  place-items: center;
  font-size: 2rem;
}
footer {
 border-top: 1px dashed #888;
}

.image__container {
  display: grid;
  grid-template-columns: 1fr 1fr;
  padding: 3rem;
  gap: 2rem;
  place-items: center;
}

.image__container img {
  width: 100%;
}

.image__description {
  font-size: 1.2rem;
  line-height: 1.5;
}

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

&lt;/div&gt;



&lt;p&gt;We use the above code block to style our webpage to display the images neatly before we add our lazy loading effect. A visual representation of what we have achieved so far:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz3i29b486pcrq3g9b97b.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz3i29b486pcrq3g9b97b.gif" alt="Initial-design-without-functionality-2.gif" width="800" height="429"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At a first glance, we can see the well-laid-out structure of our webpage, the separation between sections, and, more importantly, how only the low-resolution images load into the webpage. Now, it is time to focus on the functional aspect of our webpage.&lt;/p&gt;

&lt;h3&gt;
  
  
  The JavaScript Phase
&lt;/h3&gt;

&lt;p&gt;Below is a step-by-step procedure for this phase to help us better understand what we plan to do. These steps include;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Outlining and selecting all the elements to be lazy-loaded.&lt;/li&gt;
&lt;li&gt;Creating our intersection observer function. This process breeds two subprocesses which are:

&lt;ul&gt;
&lt;li&gt;Creating our observer callback function.&lt;/li&gt;
&lt;li&gt;Creating our observer options object.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Passing the callback function and options object as arguments of the Intersection observer function.&lt;/li&gt;
&lt;li&gt;Looping through all the observed images to observe each of the images.&lt;/li&gt;
&lt;li&gt;Creating a guard clause to ignore non-intersecting events.&lt;/li&gt;
&lt;li&gt;Creating a lazy loading event which fires when the observed images intersect with the viewport. This logic is responsible for swapping out the low-quality image for the high-quality image.&lt;/li&gt;
&lt;li&gt;Adding a blurry effect to the images, so they appear blurry when swapping hasnt occurred and clear when it has.&lt;/li&gt;
&lt;li&gt;Capturing the load event to remove the blurry filter when the load event is done.&lt;/li&gt;
&lt;li&gt;Unobserving all the images after theyve been loaded.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;As you can see, weve got our work cut out, so lets dive right in.&lt;/p&gt;

&lt;p&gt;Firstly, we identify what elements we plan to lazy load on our webpage. On quick inspection of our HTML document, we can quickly determine that all our images have a common attribute called data-src, so we use that attribute to select them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const imgTargets = document.querySelectorAll("img[data-src]");

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

&lt;/div&gt;



&lt;p&gt;Next, we initialize our intersection observer API.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const imgObserver = new IntersectionObserver();

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

&lt;/div&gt;



&lt;p&gt;Define our observer callback function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const imgLoad = function (entries, observer) {};

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

&lt;/div&gt;



&lt;p&gt;It is important to note that our observer callback function is invoked with two arguments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The entries argument, which is an array that holds the &lt;strong&gt;&lt;em&gt;IntersectionObserverEntry&lt;/em&gt;&lt;/strong&gt; Object. This object contains several properties describing the intersection event between the target element and its root element.&lt;/li&gt;
&lt;li&gt;Its second argument is the &lt;strong&gt;&lt;em&gt;observer object&lt;/em&gt;&lt;/strong&gt; (i.e., the intersection Observer we created earlier).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And our observer options object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const obsOptions = {
  root: null,
  threshold: 0.2,
};

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; We set the root to null to trigger our lazy loading effect relative to the devices viewport and set a threshold of 0.2, i.e., to trigger our functionality when a 20% intersection is obtained.&lt;/p&gt;

&lt;p&gt;Next, we pass the callback function and options object as arguments to the Intersection observer function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const imgObserver = new IntersectionObserver(imgLoad, obsOptions);

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

&lt;/div&gt;



&lt;p&gt;After that, we use a forEach loop to iterate through each image and observe them individually. We are capable of doing this because the &lt;strong&gt;&lt;em&gt;document.querySelectorAll&lt;/em&gt;&lt;/strong&gt; created a nodelist of all the selected images, and despite a nodelist not being an array, we can loop through it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;imgTargets.forEach((img) =&amp;gt; imgObserver.observe(img));

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

&lt;/div&gt;



&lt;p&gt;This statement interpreted in English is For each img in the nodelist (imgTargets), observe each img.&lt;/p&gt;

&lt;p&gt;To have a more visual understanding of our progress so far, I wrote a small code block inside of our callback function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const imgLoad = function (entries, observer) {
  entries.forEach((entry) =&amp;gt; {
    console.log(entry);
  });
};

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

&lt;/div&gt;



&lt;p&gt;As stated earlier, the &lt;strong&gt;&lt;em&gt;entries&lt;/em&gt;&lt;/strong&gt; argument, an array indicating when an intersection occurs, can easily be looped over to display the entry and exit of an intersecting element. The result of the &lt;strong&gt;imgLoad&lt;/strong&gt; callback function can be shown in the image below.&lt;/p&gt;

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

&lt;p&gt;By default, JavaScript fires the Intersection Observer function once the page loads, which yields a false value on the &lt;strong&gt;&lt;em&gt;IntersectionObserverEntry&lt;/em&gt;&lt;/strong&gt; Objects &lt;strong&gt;&lt;em&gt;isIntersecting&lt;/em&gt;&lt;/strong&gt; attribute. But as we scroll down the page, the threshold is reached, and the &lt;strong&gt;&lt;em&gt;isIntersecting&lt;/em&gt;&lt;/strong&gt; value changes to true.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm9krz8bcp7t0eegyynw9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm9krz8bcp7t0eegyynw9.png" alt="Intersection Observer - Scroll - 1.png" width="800" height="354"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It is also noteworthy to talk about some of the essential attributes in the IntersectionObserverEntry Object, such as;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;target&lt;/strong&gt; : This is the element the observer is looking at for an intersection with the root element.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;isIntersecting&lt;/strong&gt; : This attribute returns a Boolean value of true if the target element being observed is intersecting with the root element(if the threshold value has been achieved).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;intersectionRatio&lt;/strong&gt; : This attribute consists of float values between 0 and 1 and is constantly compared with the threshold value to indicate when the threshold has been reached. When the value of &lt;strong&gt;&lt;em&gt;intersectionRatio&lt;/em&gt;&lt;/strong&gt; is greater than or equal to the threshold value, the callback function is fired.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One more thing we must do before creating the program's logic is to get the returned object of each entry from the entries array using array destructuring. Performing this action makes our function look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const imgLoad = function (entries, observer) {
  entries.forEach((entry) =&amp;gt; {
    console.log(entry);
  });
  const [entry] = entries;
};

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

&lt;/div&gt;



&lt;p&gt;After that, we create a guard clause that ignores non-intersecting events or triggers fired after an element has stopped intersecting with the root element. This can easily be implemented with this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (!entry.isIntersecting) return;

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

&lt;/div&gt;



&lt;p&gt;This code states that if the observed elements are not intersecting with the root element, no action should be taken, hence the return statement. &lt;strong&gt;&lt;em&gt;isIntersecting&lt;/em&gt;&lt;/strong&gt; attribute, which we just discussed.&lt;/p&gt;

&lt;p&gt;So far, our callback function looks something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const imgLoad = function (entries, observer) {
  entries.forEach((entry) =&amp;gt; {
    console.log(entry);
  });
  const [entry] = entries;
  if (!entry.isIntersecting) return;
};

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

&lt;/div&gt;



&lt;p&gt;Next, we create our program logic which swaps the low-quality image for the high-quality image using one simple line of code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;entry.target.src = entry.target.dataset.src;

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

&lt;/div&gt;



&lt;p&gt;Explaining the code above; entry.target is simply the current element that has intersected the viewport. Adding the .src property specifies that we are targeting the source attribute contained in our target element. Next, we assign entry.target.src the value stored in the dataset.src of that same element. Keep in mind that the dataset.src value is the link to the high-quality we specified in our HTML using the data-src attribute. With this single line of code, weve successfully swapped the low-quality image for that of the high-quality image, and implemented the image lazy-loading feature!&lt;/p&gt;

&lt;p&gt;Dont believe me? See for yourself.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F81gows71nzgx9zjyrkq3.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F81gows71nzgx9zjyrkq3.gif" alt="cataezgif.com-gif-maker (1).gif" width="600" height="338"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, as we scroll down the page, our callback function is fired, and the browser automatically swaps the image in our &lt;strong&gt;&lt;em&gt;src&lt;/em&gt;&lt;/strong&gt; attribute to the image in our &lt;strong&gt;&lt;em&gt;data-src&lt;/em&gt;&lt;/strong&gt; attribute, effectively swapping the images as we scroll to them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; : Whenever JavaScript swaps each image, it emits a &lt;strong&gt;&lt;em&gt;load&lt;/em&gt;&lt;/strong&gt; event to indicate that our &lt;strong&gt;&lt;em&gt;data-src&lt;/em&gt;&lt;/strong&gt; image has been loaded to display. This event can be useful when writing logic to check if each image has been swapped.&lt;/p&gt;

&lt;p&gt;Next, Id like to add a blurry effect to our observed images so that they appear blurry at first and become clear when loaded. It is safe to assume that a certain aesthetic effect is added when the user sees a blurry image become clear rather than a low-quality pixelated image at first. To do this, we simply use the CSS class created below containing the styles to add our blurry effect, add them to our specific HTML elements, then take it off with JavaScript based on the users scroll.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.lazy-img {
  filter: blur(20px);
  transition: filter 0.5s;
}

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

&lt;/div&gt;



&lt;p&gt;And now, to remove them when we scroll into our observed elements. We use another inbuilt JavaScript event the &lt;strong&gt;load&lt;/strong&gt; event to check if each target element(image) has been loaded, then remove the blurry effect from it. Seems pretty easy enough? 😉 Lets dive in immediately.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;entry.target.addEventListener("load", function () {
    entry.target.classList.remove("lazy-img");
});

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

&lt;/div&gt;



&lt;p&gt;We attached an event listener with the &lt;strong&gt;&lt;em&gt;load&lt;/em&gt;&lt;/strong&gt; event for each element were observing, then removed the class &lt;strong&gt;&lt;em&gt;lazy-img&lt;/em&gt;&lt;/strong&gt; , which contained our blur.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxh2bkptpo1v5p7dq5wra.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxh2bkptpo1v5p7dq5wra.gif" alt="Final-blurry-2.gif" width="500" height="260"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And yeah, It worked! Of course, it did; we wrote sleek code to achieve this. As you can see, each image loses its blur after we've scrolled into it and revealed a nice high-resolution image for display. Keep in mind that for this article, I intentionally slowed down the webpage's load time to showcase the blur effect fading out on the scroll. Normally, It possesses a faster load time since we're developing with our local machine.&lt;/p&gt;

&lt;p&gt;Finally, we easily unobserve each element so that the browser no longer pays attention to (observes) them after they have been loaded.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;observer.unobserve(entry.target);

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

&lt;/div&gt;



&lt;p&gt;And with that, we have successfully implemented our lazy loading feature on our images; congratulations! All thats left is to demonstrate the performance difference between a lazy-loaded website and a regular one, as illustrated by the images below.&lt;/p&gt;

&lt;p&gt;Image -1 represents our lazy-loaded webpage&lt;/p&gt;

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

&lt;p&gt;Image -2 represents the same webpage but without any lazy-loading feature&lt;/p&gt;

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

&lt;p&gt;As you can see, our lazy-loaded website is near &lt;strong&gt;&lt;em&gt;4700ms&lt;/em&gt;&lt;/strong&gt; (4.7 seconds) faster than our regular webpage. Thats quite a sizeable gap, wouldnt you say? And in a field where speed and performance matter, our lazy-loaded website ousts its alternative.&lt;/p&gt;

&lt;h2&gt;
  
  
  Project Link
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/Daiveedjay/Lazy-loading-article" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This article has been quite a lengthy one. Still, it has also been an adventure where we explored a perfect use of JavaScripts Intersection Observer and created a lazy-loading feature. Its now up to you to explore and push the limits of the Intersection Observer and create more fascinating features on your own, and to that, I wish you the best .&lt;/p&gt;

</description>
      <category>watercooler</category>
    </item>
    <item>
      <title>Creating aesthetic cards with CSS ::before and ::after pseudo-elements</title>
      <dc:creator>David Jaja</dc:creator>
      <pubDate>Thu, 22 Sep 2022 17:36:32 +0000</pubDate>
      <link>https://dev.to/daiveed/creating-aesthetic-cards-with-css-before-and-after-pseudo-elements-2jl2</link>
      <guid>https://dev.to/daiveed/creating-aesthetic-cards-with-css-before-and-after-pseudo-elements-2jl2</guid>
      <description>&lt;p&gt;Have you ever wondered how some beautiful animations on the web are made, then assumed it was done by a far more experienced and skilled person, and then abandoned your plans to recreate it?&lt;/p&gt;

&lt;p&gt;Usually, vanilla CSS is used to create these mesmerizing designs, not some animation library. This article will look at how to make some mesmerizing designs, starting with small practical examples and working our way to creating a highly aesthetic profile card to further elaborate on the actual ability of pseudo-selectors.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Prerequisites&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Before we elucidate our topic of interest, we need to get familiar with some essential web development tools and knowledge required to follow along.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fundamental knowledge of HTML&lt;/li&gt;
&lt;li&gt;Fundamental knowledge of CSS&lt;/li&gt;
&lt;li&gt;A Code editor and a browser&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;What are Pseudo-elements?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Pseudo-elements are CSS selectors that add a whole new HTML element into the markup. They tend to add content or decorate our webpage without creating additional HTML tags. We declare these elements with the double colon as a prefix (i.e., ::before). This article will dwell on the ::before and ::after pseudo-elements to understand how we can use them to create fantastic animations and transitions.&lt;/p&gt;

&lt;p&gt;However, there is a common misconception associated with pseudo-elements. Pseudo-elements are sometimes mistaken as pseudo-classes, however, there is a slight variation. A pseudo-class selects elements that exist in a specific state and often applies some styling to it, and sometimes to prevent excessive use of CSS classes when targeting specific elements to promote cleaner HTML code. They are declared with the single colon as a prefix (i.e., :hover). Some examples of pseudo-classes include: :hover, :first-child, :first-letter.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Pseudo-elements overview&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;The ::before pseudo-element&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;As the name implies, the function of the ::before pseudo-element is to add content before the element's content.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;p&amp;gt; This is a paragraph &amp;lt;/p&amp;gt;


p::before { content: "👑"; }

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

&lt;/div&gt;



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

&lt;h3&gt;
  
  
  &lt;strong&gt;The ::after pseudo-element&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Also, as the name implies, the function of the ::after pseudo-element is to add content after the elements content.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;p&amp;gt; This is a paragraph &amp;lt;/p&amp;gt;


p::after { content: "👑"; }

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

&lt;/div&gt;



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

&lt;h2&gt;
  
  
  &lt;strong&gt;CSS Properties applied with the Pseudo-elements&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Preliminary to diving into building our main attraction (profile card) of this article, lets take a little detour and first explain some CSS properties well be using for design and customization.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Positioning 

&lt;ul&gt;
&lt;li&gt;Relative&lt;/li&gt;
&lt;li&gt;Absolute &lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Z-index&lt;/li&gt;

&lt;li&gt;Transform&lt;/li&gt;

&lt;li&gt;Transition&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;A brief intro to CSS Positioning and Z-index&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Before using these properties to build our final project, it is important to highlight their behaviours.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Positioning in CSS&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The position property of an element specifies the type of positioning the element should have in the document or page. In CSS, there are several positioning properties such as fixed, sticky, absolute, relative, and sticky, but well only go through relative and absolute in this article.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Relative Positioning&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Setting an elements position property relative sets the element according to the normal document flow. An offset can then be selected based on top, right, bottom, and left.&lt;/p&gt;

&lt;p&gt;An example would be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;body&amp;gt;
    &amp;lt;div class="box-1"&amp;gt;Normal Flow&amp;lt;/div&amp;gt;
    &amp;lt;div class="box-2"&amp;gt;Offset Flow&amp;lt;/div&amp;gt;
&amp;lt;/body&amp;gt;


.box-1 {
  background: #333;
}
.box-2 {
  position: relative;
  left: 120px;
  background: #999;
  top: 0;
}

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

&lt;/div&gt;



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

&lt;p&gt;As shown above, .box-2 moves 120px away from its natural alignment, yet other surrounding elements observe its vacated space.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Absolute Positioning&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;On the contrary, setting an elements position property to absolute pulls the element out of its natural document flow. It tethers that element to its immediate parent, whose position property is set to relative. If no relative parent of the absolutely positioned element is available, it is tethered to the body element (i,e., root relative parent element). It is important to note that absolutely positioned elements have a higher stacking order than relative elements and are placed above every relative element they intersect.&lt;/p&gt;

&lt;p&gt;An example would be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;body&amp;gt;
  &amp;lt;div class="container"&amp;gt;
    &amp;lt;div class="box-1"&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;div class="box-2"&amp;gt;&amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/body&amp;gt;


.container {
        position: relative;
        width: 300px;
        height: 200px;
        border: 2px solid #888;
  }

  .box-1 {
        position: absolute;
        left: 20px;
        top: 20px;
        width: 50px;
        height: 50px;
        background: lavender;
   }

   .box-2 {
        position: absolute;
        left: 200px;
        top: 70px;
        width: 50px;
        height: 50px;
        background: aqua;
    }

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

&lt;/div&gt;



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

&lt;p&gt;As expected, both boxes are tethered and use their parent element (.container) as a reference point of alignment when the position coordinates are provided.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Z-index and CSS elements stacking order&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;First off, the stacking order describes the arrangement of HTML elements in the z-axis, i.e., how elements are arranged when stacked on top of each other (which comes before the other). Naturally, HTML elements are positioned in the following order:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Root element.&lt;/li&gt;
&lt;li&gt;Non-positioned elements in the order theyre defined (i.e., elements without a position property defined).&lt;/li&gt;
&lt;li&gt;Positioned elements in the order theyre defined.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;The Z-index property&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This property lets us stack elements on each other depending on their increasing number of z-index. An element with a higher z-index property value will appear on top of all other elements with a lower z-index value.&lt;/p&gt;

&lt;p&gt;A visual example would be:&lt;/p&gt;

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

&lt;p&gt;It is worth remembering that the z-index property only works on elements whose position properties have been set. Also, if two elements have the same z-index, the element created further down the HTML document stays over the previous element.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;The Transform and Transition property&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The CSS transform property comprises a series of preset functions such as;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Translate()&lt;/strong&gt;: This property repositions an element in a horizontal and/or vertical direction(s).
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;div {
    background: #c3c3ff;
    width: 30px;
    height: 30px;
}
.box-1 { transform: translateX(30px); }
.box-2 { transform: translate(30px); }

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

&lt;/div&gt;



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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Rotate()&lt;/strong&gt;: This property rotates an element without deforming it around a fixed point in the 2D plane.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.box-1 { transform: rotate(30deg); }

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

&lt;/div&gt;



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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Scale()&lt;/strong&gt;: This property resizes a 2D plane element.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.box-1 { transform: scale(2); }

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

&lt;/div&gt;



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

&lt;p&gt;Skew(): This property skews a 2D plane element. Skew means a slight tilt in a particular direction or to a certain angle.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.box-1 { transform: skewX(30deg); }

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

&lt;/div&gt;



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

&lt;p&gt;Lastly, the CSS transition function allows you to define the transition of an element between different states. After acclimatizing with some of the basics, lets dive into our starter project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building an animated button with CSS pseudo-elements
&lt;/h2&gt;

&lt;p&gt;We start by creating a button element using the HTML link syntax&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;a href="#" class="btn"&amp;gt; Hover Me &amp;lt;/a&amp;gt;

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

&lt;/div&gt;



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

&lt;p&gt;Then adding some basic CSS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;a {
  padding: 15px 25px;
  border: 2px solid #926ec6;
  border-radius: 10px;
  text-decoration: none;
  position: relative;
}

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

&lt;/div&gt;



&lt;p&gt;This is easy code; we applied padding to create spacing around our buttons text. Then added borders to it and rounded off those borders using the border-radius property. Next, we removed the default underlining displayed as we created the element (i.e., the underlining that comes with all a tags). Finally, we added a position property of relative since were making a child pseudo-element and need to tether it to its parent (the a element).&lt;/p&gt;

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

&lt;p&gt;Now, we create our pseudo-element from the parent element and style that.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;a::before {
  position: absolute;
  content: "";
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: #926ec6;
  transition-property: all;
  transition-timing-function: ease-in;
  transition-duration: 0.3;
}

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

&lt;/div&gt;



&lt;p&gt;We first set the position property to absolute. This lifts the pseudo-element from its natural stacking order and attaches it to its relative parent element (the a tag). We also set the content to an empty set of quotation marks ( ), since we arent adding any content to the parent element. Then using offset values, we set the absolutely positioned elements bearings to the top left part of its parent element (i.e., top:0, left: 0). Finally, we spanned the absolutely positioned element its parent height and width (i.e., width: 100%, height: 100%), added a background colour and some transition properties for smooth animation.&lt;/p&gt;

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

&lt;p&gt;It looks like weve messed up our button, doesnt it 😅? Well, dont fright, we meant to do this, and well modify it in a second. For clarity, the pseudo-element we created is currently laying over our button. We then translate the pseudo-element weve created by its full height upwards along the Y-axis to reveal our initial button.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;a::before {
  transform: translateY(-100%);
}

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

&lt;/div&gt;



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

&lt;p&gt;Then we apply the pseudo-class :hover to the parent element and animate the tethered pseudo-element based on the :hover behaviour.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;a:hover::before {
  transform: translateY(0);
}

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

&lt;/div&gt;



&lt;p&gt;And viola!, we have this really cool animation done with pure CSS.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fffpow445grczz4cam65q.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fffpow445grczz4cam65q.gif" alt="btn-vid.gif" width="396" height="202"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We're left with changing the colour of the text to make it visible on hover and this can easily be achieved with the code below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;a::before { z-index: -1; }

a:hover {
  transition-property: all;
  transition-timing-function: ease-in;
  transition-delay: 0.5s;
  transition-duration: 0.1s;
  color: #fff;
}

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

&lt;/div&gt;



&lt;p&gt;To explain the code above. First, we reduced the z-index of the pseudo-element, which moves the pseudo-element behind its parent element, and hence makes the parent element always stay on top. We then added similar transition function properties to the parent element, with the variation being the transition delay, which in my opinion, adds a smoother effect. This delays the parent elements animation after the pseudo-element has finished animating. Finally, we changed the colour of the text in the parent element to make the text visible and finish our animation.&lt;/p&gt;

&lt;p&gt;Now, we only need to remove the overflowing bits produced by the pseudo-element to leave this beautifully rounded button. We can quickly achieve this using the overflow function, which hides any overflowing content.&lt;/p&gt;

&lt;p&gt;Implementing this function looks something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;a:{ overflow: hidden; }

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

&lt;/div&gt;



&lt;p&gt;And finally, we have:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F950rt5245k7h3xqkzu47.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F950rt5245k7h3xqkzu47.gif" alt="btn-vid-2.gif" width="332" height="186"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Creating an advanced aesthetic card with multiple pseudo-elements.&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Now comes the big show. We're building a more complex animated card using multiple pseudo-elementstwo to be exactto create a stunning origami-looking effect. Without further ado, let's dive into the HTML mockup.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;body&amp;gt;
    &amp;lt;div class="card"&amp;gt;
      &amp;lt;div class="img-box"&amp;gt;&amp;lt;/div&amp;gt;
      &amp;lt;div class="details"&amp;gt;
        &amp;lt;h2&amp;gt;Jenny Lawrence &amp;lt;br /&amp;gt;&amp;lt;span&amp;gt;Founder&amp;lt;/span&amp;gt;&amp;lt;/h2&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
&amp;lt;/body&amp;gt;

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

&lt;/div&gt;



&lt;p&gt;We created a parent class named card and nested two child elements (img-box and details). We then filled the details element with some content separated by a line break, which we would style later.&lt;/p&gt;

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

&lt;p&gt;Indulging in the CSS, we add the following styles:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* { 
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
body {
  display: grid;
  place-items: center;
  height: 100vh;
  background-color: #222;
}

.card {
  width: 320px;
  height: 350px;
  background-color: #fff;
  border-radius: 5px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
  position: relative;
}

.img-box {
  background: #222;
  transition: all, ease-in, 0.5s;
}

.details {
  height: 60px;
  text-align: center;
}

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

&lt;/div&gt;



&lt;p&gt;Firstly, the * styling is used to remove default styling applied by browsers. For the body, we specified a height, used CSS Grid to place the card right in the middle of the browsers page, and added a background colour. We then specified the dimensions for the card, set a background, rounded its corners, added some box shadow, and positioned it relatively. Additionally, a background and a transition property were set on the img-box container. Finally, a fixed height was set on the details container, and its text was aligned to the center.&lt;/p&gt;

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

&lt;p&gt;Adding the last piece of HTML: an image&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div class="img-box"&amp;gt;
    &amp;lt;img src="./sample.jpg" alt="Sample image" /&amp;gt;
&amp;lt;/div&amp;gt;

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

&lt;/div&gt;



&lt;p&gt;Then adding a little more CSS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.img-box {
  position: absolute;
  top: 10px;
  left: 10px;
  right: 10px;
  bottom: 10px;
  z-index: 2;
}

.details {
  position: absolute;
  left: 10px;
  right: 10px;
  bottom: 10px;
}

img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

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

&lt;/div&gt;



&lt;p&gt;Lets first go over what we just did.&lt;/p&gt;

&lt;p&gt;We first positioned the img-box element absolutely, which tethered it to its relative parent element (card). We then used position offset values to move it 10px from every direction, which produces the white border-like effect.&lt;/p&gt;

&lt;p&gt;We also absolutely positioned the details element, but we can't see it only due to the higher z-index of the img-box element sitting over the details element. Then we spanned the image to its parent container's full width/height. Finally, we used the object-fit property to control how the image is resized to fit its container (trust me, this would be useful later).&lt;/p&gt;

&lt;p&gt;And now, we have a cool looking card:&lt;/p&gt;

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

&lt;p&gt;To finally get our desired effect, we add the following styles:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;h2 {
  color: #777;
  text-transform: uppercase;
  font-weight: 400px;
}
span {
  font-size: 16px;
  font-weight: 500;
  color: #f38695;
}
.card:before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  border-radius: 5px;
  background: #fff;
  transition: all, ease-in, 0.5s;
  z-index: -1;
}
.card::after {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  border-radius: 5px;
  background: #fff;
  Transition: all, ease-in, 0.5s;
  z-index: -2;
}

.card:hover::before {
  transform: rotate(20deg);
  box-shadow: 0 20px 10px rgba(0, 0, 0, 0.2);
}

.card:hover::after {
  transform: rotate(10deg);
  box-shadow: 0 20px 10px rgba(0, 0, 0, 0.2);
}

.card:hover .img-box {
  bottom: 80px;
}

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

&lt;/div&gt;



&lt;p&gt;I know what youre thinking 😅; thats a handful of code, which is why Ill go through every critical line with you. We created two pseudo-elements ::before and ::after and positioned them absolutely to their relative parent element. We styled their width and height, and gave them varying z-indexes to create the effect of stacking them on each other. Then we added a transition animation which made them rotate at slightly different angles and activated the animation on hover of their parent. Finally, on hover, we increased the bottom offset of the image container, which allows the text in the details container to be smoothly revealed.&lt;/p&gt;

&lt;p&gt;Thus, producing this masterpiece!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F20lyzrn0k2k9edn83i36.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F20lyzrn0k2k9edn83i36.gif" alt="Vid-final.gif" width="600" height="338"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Source Code (Code Pen)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://codepen.io/david-jaja/pen/OJZWGXd" rel="noopener noreferrer"&gt;Animated button&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://codepen.io/david-jaja/pen/JjvEVrO" rel="noopener noreferrer"&gt;Aesthetic Card&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Congratulations on making it to the end of the article. As youve seen, the ::before and ::after pseudo-elements can be applied in several ways to create some mesmerizing effects.&lt;/p&gt;

&lt;p&gt;Feel free to play around with these elements and create your own custom designs and test your level of imagination.&lt;/p&gt;

</description>
      <category>tooling</category>
      <category>nginx</category>
    </item>
  </channel>
</rss>
