<?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: Jenning Ho</title>
    <description>The latest articles on DEV Community by Jenning Ho (@j3nnning).</description>
    <link>https://dev.to/j3nnning</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F195051%2F4bdf04db-362c-433f-b350-6d880aa05a41.jpg</url>
      <title>DEV Community: Jenning Ho</title>
      <link>https://dev.to/j3nnning</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/j3nnning"/>
    <language>en</language>
    <item>
      <title>How I Use AI Councils to Solve Ambiguous Engineering Problems</title>
      <dc:creator>Jenning Ho</dc:creator>
      <pubDate>Wed, 24 Jun 2026 16:41:10 +0000</pubDate>
      <link>https://dev.to/j3nnning/how-i-use-ai-councils-to-solve-ambiguous-engineering-problems-4dii</link>
      <guid>https://dev.to/j3nnning/how-i-use-ai-councils-to-solve-ambiguous-engineering-problems-4dii</guid>
      <description>&lt;h2&gt;
  
  
  A Practical AI Council Workflow for Software Architecture and Delivery
&lt;/h2&gt;




&lt;h3&gt;
  
  
  One AI Assistant Is Useful, But Not Always Enough
&lt;/h3&gt;

&lt;p&gt;If you've used an AI coding assistant for anything beyond autocomplete, you've probably noticed a pattern: single-model workflows converge fast. Sometimes too fast.&lt;/p&gt;

&lt;p&gt;You describe a problem. The model proposes a solution. The solution looks reasonable. You implement it. Then three days later, during review or integration, you discover the architecture didn't account for a boundary condition, a simpler alternative existed, or the design coupled two things that should have stayed separate.&lt;/p&gt;

&lt;p&gt;This isn't a failure of the model. It's a failure of the process. A single model — no matter how capable — can commit early and refine within its own frame. It may not challenge its own assumptions the way a second engineer would.&lt;/p&gt;

&lt;p&gt;Source-grounded coding agents — tools like Qoder, Codex, Claude Code, Cursor, Devin, Copilot Agent, or similar agentic coding environments — are powerful precisely because they work within your actual codebase. They can work within your repository, inspect relevant files, follow visible conventions, and run verification commands when the environment supports it. But source grounding doesn't eliminate architectural blind spots. It means the model knows &lt;em&gt;what exists&lt;/em&gt;. It doesn't guarantee the model will challenge &lt;em&gt;whether what exists is the right foundation&lt;/em&gt; for what you're building next.&lt;/p&gt;

&lt;p&gt;For ambiguous engineering problems — cross-cutting refactors, unclear ownership boundaries, specification work for complex features — one assistant isn't always enough. Not because the model is bad, but because critique is a separate function from proposal.&lt;/p&gt;




&lt;p&gt;Before going further, this is not a claim that AI councils are a new idea.&lt;/p&gt;

&lt;p&gt;The broader pattern already exists in different forms: LLM councils, multi-agent debate, role-based review, self-critique workflows, and multi-agent software development systems. What I’m describing here is narrower and more practical: how I’ve been operationalizing that idea for software architecture and delivery work.&lt;/p&gt;

&lt;p&gt;The useful question is not “can multiple models review the same problem?” We already know they can.&lt;/p&gt;

&lt;p&gt;The useful question is: how do you turn that into a repeatable engineering workflow with clear roles, stop criteria, source grounding, implementation separation, audit, and human governance?&lt;/p&gt;

&lt;p&gt;In this post, “AI council” does not mean a special platform. It simply means multiple AI contexts reviewing the same proposal from intentionally different roles.&lt;/p&gt;




&lt;h3&gt;
  
  
  How I Stumbled Into the Workflow
&lt;/h3&gt;

&lt;p&gt;I first started consulting multiple AI models out of necessity, not grand strategy.&lt;/p&gt;

&lt;p&gt;The immediate triggers were token and context limits. I was working on a complex specification in my agentic coding environment, and the context window was filling up. I couldn't fit the entire problem description, the existing codebase context, &lt;em&gt;and&lt;/em&gt; a meaningful back-and-forth critique into a single session. So I started asking other models to review pieces of the proposal independently.&lt;/p&gt;

&lt;p&gt;The early process was messy. I'd copy my coding agent's architectural proposal into another model, ask "what's wrong with this?", then paste the response back. Sometimes I'd ask a different model about an unfamiliar distributed systems concept to check whether my agent's approach aligned with established patterns. Sometimes I'd ask yet another to play devil's advocate on a trade-off decision.&lt;/p&gt;

&lt;p&gt;There was no consistent order. No defined roles. No stopping criteria. Feedback came in random order. Objections weren't consistently tracked. Conversations could go too long. I'd keep going until I felt like I'd heard enough, or until I ran out of patience for copy-pasting between windows.&lt;/p&gt;

&lt;p&gt;But even in this messy state, I noticed something: the final specs were better. Not marginally better — noticeably better. My coding agent's proposals would shift in meaningful ways after I fed back external critique. Assumptions got surfaced. Simpler alternatives appeared. Edge cases got caught before implementation rather than during audit.&lt;/p&gt;

&lt;p&gt;Different models exposed different blind spots. The process worked. It just needed structure.&lt;/p&gt;




&lt;h3&gt;
  
  
  The Real Insight: It Was Not About More Models
&lt;/h3&gt;

&lt;p&gt;After several runs, I realized the improvement wasn't coming from &lt;em&gt;more models&lt;/em&gt;. Four models saying "looks good" adds nothing. More models alone can create noise.&lt;/p&gt;

&lt;p&gt;The improvement came from specific structural properties:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Role separation&lt;/strong&gt;: Each external model was implicitly playing a different role — critic, simplifier, systems thinker. When I made these roles explicit, the feedback got sharper.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Structured critique&lt;/strong&gt;: Asking "review this" produces vague responses. Asking "identify the three biggest architectural risks in this proposal" produces actionable feedback.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Objection tracking&lt;/strong&gt;: Without a ledger, feedback gets lost. Objections get raised and then quietly dropped. Tracking forces resolution.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Synthesis as a first-class step&lt;/strong&gt;: Manually reconciling five responses is exhausting and error-prone. Making synthesis an explicit operation — performed by a source-grounded agent that can validate claims against the actual codebase — turned it into a reliable process.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Source grounding&lt;/strong&gt;: The synthesis agent validates against reality. External models speculate; the source-grounded agent checks what's actually true in the code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Implementation audit as a separate phase&lt;/strong&gt;: Writing code and reviewing code are different cognitive modes. Separating them into different contexts preserves independence.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Human governance gates&lt;/strong&gt;: The human doesn't synthesize everything manually. But the human decides when to stop, when to proceed, and what risk to accept.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;"The value was not asking more models. The value was turning AI usage into a governed engineering workflow."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This distinction matters. "AI brainstorming" is easy to dismiss. An engineering process with defined roles, tracked objections, synthesis operations, and governance gates is something you can reason about, improve, and trust.&lt;/p&gt;




&lt;h3&gt;
  
  
  The Workflow in One Diagram
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Problem Statement
  → Source-Grounded Architect Agent
    → AI Council Role-Based Critique
      → Feedback Synthesis
        → Objection Ledger + Open Questions
          → Human Governance Gate
            → [If blocking issues remain: repeat council round]
            → [If resolved: proceed]
              → Spec + Implementation Plan
                → Executor Agent (separate context)
                  → Auditor Agent (separate context)
                    → Audit-Driven Remediation (if needed)
                      → Human Final Approval
                        → Commit / Ship
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Stage-by-stage breakdown:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Problem Statement&lt;/strong&gt; — The human frames the problem clearly. This is the input to everything else.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Source-Grounded Architect Agent&lt;/strong&gt; — A coding agent with full repository access produces an initial proposal including architectural options, trade-offs, and open questions explicitly flagged for review.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;AI Council Role-Based Critique&lt;/strong&gt; — Each council role (in a separate context or window) receives the same proposal and reviews it through their assigned lens. Responses are collected with role labels preserved.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Feedback Synthesis&lt;/strong&gt; — All council responses are fed back to the source-grounded agent, which critically evaluates the feedback, identifies agreements, conflicts, and actionable items.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Objection Ledger + Open Questions&lt;/strong&gt; — Objections are tracked with status, severity, and resolution. New objections are added. Resolved ones are marked.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Human Governance Gate&lt;/strong&gt; — The human reviews the ledger and decides: are there blocking objections remaining? Are there meaningful open questions? If yes, another council round. If no, proceed to spec.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Spec + Implementation Plan&lt;/strong&gt; — The architect agent writes the specification and plan incorporating all accepted feedback and resolved objections.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Executor Agent&lt;/strong&gt; — A separate context implements the plan. This context focuses purely on implementation, not design debate.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Auditor Agent&lt;/strong&gt; — Another separate context audits the implementation against the approved spec and plan. Independent review.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Audit-Driven Remediation&lt;/strong&gt; — If audit findings require changes, they go back to the executor. The human approves this loop.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Human Final Approval&lt;/strong&gt; — The human reviews the final state and decides whether to commit, open a PR, or ship.”.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  The Role Model
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;th&gt;Typical Tool&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;th&gt;Output&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Source-Grounded Architect&lt;/td&gt;
&lt;td&gt;Agentic coding environment with repo access&lt;/td&gt;
&lt;td&gt;Produce source-grounded proposal, synthesize feedback, write spec&lt;/td&gt;
&lt;td&gt;Initial proposal, synthesis reports, spec + plan&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;System Thinker&lt;/td&gt;
&lt;td&gt;Any AI model (separate context)&lt;/td&gt;
&lt;td&gt;Evaluate systemic implications, coupling, boundaries&lt;/td&gt;
&lt;td&gt;Architectural risk assessment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Critical Reviewer&lt;/td&gt;
&lt;td&gt;Any AI model (separate context)&lt;/td&gt;
&lt;td&gt;Challenge assumptions, find logical gaps, stress-test claims&lt;/td&gt;
&lt;td&gt;Objections with severity and evidence&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Simplifier&lt;/td&gt;
&lt;td&gt;Any AI model (separate context)&lt;/td&gt;
&lt;td&gt;Identify unnecessary complexity, propose simpler alternatives&lt;/td&gt;
&lt;td&gt;Simplification proposals with trade-offs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Alternatives Reviewer&lt;/td&gt;
&lt;td&gt;Any AI model (separate context)&lt;/td&gt;
&lt;td&gt;Explore approaches the architect didn't consider&lt;/td&gt;
&lt;td&gt;Alternative designs with comparison&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Executor Agent&lt;/td&gt;
&lt;td&gt;Agentic coding environment (separate context)&lt;/td&gt;
&lt;td&gt;Implement the approved plan faithfully&lt;/td&gt;
&lt;td&gt;Working code + implementation report&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auditor Agent&lt;/td&gt;
&lt;td&gt;Agentic coding environment (separate context)&lt;/td&gt;
&lt;td&gt;Independently audit implementation against spec&lt;/td&gt;
&lt;td&gt;Audit findings classified by severity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Human Governor&lt;/td&gt;
&lt;td&gt;Human&lt;/td&gt;
&lt;td&gt;Govern stage transitions, accept risk, approve delivery&lt;/td&gt;
&lt;td&gt;Go/no-go decisions at each gate&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;A note on tooling:&lt;/strong&gt; Tools like Qoder, Codex, Claude Code, Cursor, Devin, Copilot Agent, or similar agentic environments can fill the source-grounded roles — provided they can inspect a repository, reason over code, edit files, run verification commands, and support separate working contexts. The council reviewer roles can be filled by any capable AI model.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A note on role assignment:&lt;/strong&gt; The same underlying model can hold multiple roles. What matters is that each role operates in its own context. A model playing "Critical Reviewer" should not simultaneously hold "Architect" context. Role separation is about preserving independence of perspective, not requiring N different model providers.&lt;/p&gt;




&lt;h3&gt;
  
  
  The Objection Ledger
&lt;/h3&gt;

&lt;p&gt;This is what turns AI discussion into engineering governance. Without tracking, feedback rounds become circular. Objections get raised, discussed, and then quietly dropped without resolution. The objection ledger prevents feedback from becoming vague opinion exchange. It makes objections explicit, trackable, and resolvable.&lt;/p&gt;

&lt;p&gt;Every objection raised during council rounds gets logged:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ID&lt;/th&gt;
&lt;th&gt;Objection&lt;/th&gt;
&lt;th&gt;Raised By&lt;/th&gt;
&lt;th&gt;Severity&lt;/th&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;th&gt;Resolution&lt;/th&gt;
&lt;th&gt;Rationale&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;OBJ-001&lt;/td&gt;
&lt;td&gt;Coupling between X and Y creates deployment dependency&lt;/td&gt;
&lt;td&gt;Critical Reviewer&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;Resolved&lt;/td&gt;
&lt;td&gt;Introduced adapter boundary&lt;/td&gt;
&lt;td&gt;Decouples deployment without adding runtime overhead&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OBJ-002&lt;/td&gt;
&lt;td&gt;Simpler approach using existing queue available&lt;/td&gt;
&lt;td&gt;Simplifier&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;Accepted&lt;/td&gt;
&lt;td&gt;Revised to use existing queue&lt;/td&gt;
&lt;td&gt;Reduces new infrastructure; trade-off: slightly less flexibility&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OBJ-003&lt;/td&gt;
&lt;td&gt;Edge case under concurrent writes not addressed&lt;/td&gt;
&lt;td&gt;System Thinker&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;Deferred&lt;/td&gt;
&lt;td&gt;Documented as future hardening&lt;/td&gt;
&lt;td&gt;Low probability in current traffic; will address in v2&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Statuses:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Open&lt;/strong&gt; — Raised but not yet addressed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accepted&lt;/strong&gt; — Objection is valid; changes will be made&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rejected&lt;/strong&gt; — Objection considered but not adopted (rationale required)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deferred&lt;/strong&gt; — Valid but explicitly out of scope for this iteration&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resolved&lt;/strong&gt; — Accepted and corresponding changes are complete&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Council rounds stop only when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No blocking open questions remain&lt;/li&gt;
&lt;li&gt;No unresolved severe objections remain&lt;/li&gt;
&lt;li&gt;Accepted objections have corresponding changes reflected in the proposal&lt;/li&gt;
&lt;li&gt;Rejected objections have documented rationale&lt;/li&gt;
&lt;li&gt;Deferred items are explicitly marked as out of scope or future work&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Six months later, you can look at the ledger and understand &lt;em&gt;why&lt;/em&gt; the architecture looks the way it does. That's not just process overhead — it's an auditable decision record.&lt;/p&gt;




&lt;h3&gt;
  
  
  Human in the Loop, But as Governor
&lt;/h3&gt;

&lt;p&gt;A common misconception about multi-model workflows is that the human becomes a copy-paste bottleneck — manually reading five responses, mentally reconciling conflicts, and rewriting the proposal by hand.&lt;/p&gt;

&lt;p&gt;That's not how this works.&lt;/p&gt;

&lt;p&gt;The source-grounded agent performs synthesis. It reads all council responses, identifies agreements and conflicts, evaluates each objection against the actual codebase, and produces a structured synthesis report. The human doesn't need to manually reconcile anything.&lt;/p&gt;

&lt;p&gt;What the human &lt;em&gt;does&lt;/em&gt; own:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Deciding when council feedback is sufficient&lt;/strong&gt; — when to stop iterating&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Approving transition to spec writing&lt;/strong&gt; — the green light to commit direction&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Approving remediation after audit&lt;/strong&gt; — deciding what gets fixed vs. deferred&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deciding how many audit rounds are enough&lt;/strong&gt; — diminishing returns exist&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accepting final delivery risk&lt;/strong&gt; — the buck stops here&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;"AI does most of the work. The human owns the gates."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is closer to "human as engineering manager" than "human as manual worker." You're not doing the synthesis. You're governing the process and accepting accountability for the output.&lt;/p&gt;




&lt;h3&gt;
  
  
  Why I Separate Architect, Executor, and Auditor
&lt;/h3&gt;

&lt;p&gt;This is a practical decision, not a theoretical one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Architect context&lt;/strong&gt; accumulates reasoning: the original problem, council feedback, synthesis reports, objection ledger, and design rationale. This context is essential for writing a good spec but would pollute an implementation session.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Executor context&lt;/strong&gt; starts fresh with the approved spec and plan. It focuses purely on implementation — file changes, test writing, integration. No design debate. No "should we reconsider the approach?" The spec is the spec.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Auditor context&lt;/strong&gt; starts fresh with the spec, plan, and changed files. It reviews independently. Because it wasn't involved in implementation, it doesn't share the implementer's assumptions or blind spots.&lt;/p&gt;

&lt;p&gt;This mirrors real engineering practice: the architect who designed a system shouldn't be the only reviewer of its implementation. Separation of concerns applies to AI workflows just as it applies to code.&lt;/p&gt;

&lt;p&gt;Practically, context separation also prevents role confusion. A context that has been arguing about architecture for an hour will approach implementation differently than one that received a clean spec. The executor doesn't need to relitigate design decisions. The auditor doesn't need to be sympathetic to implementation difficulty.&lt;/p&gt;




&lt;h3&gt;
  
  
  A Lightweight Version You Can Try
&lt;/h3&gt;

&lt;p&gt;You don't need the full workflow to get value. Here's a practical starter version:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Write a clear problem statement.&lt;/li&gt;
&lt;li&gt;Ask your coding agent for an initial proposal.&lt;/li&gt;
&lt;li&gt;Send the proposal to two reviewers:

&lt;ul&gt;
&lt;li&gt;Critical Reviewer ("find the three biggest risks")&lt;/li&gt;
&lt;li&gt;Simplifier ("what's unnecessarily complex?")&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Collect feedback with role labels.&lt;/li&gt;
&lt;li&gt;Ask your coding agent to synthesize feedback critically.&lt;/li&gt;
&lt;li&gt;Track objections in a small ledger (a markdown table works fine).&lt;/li&gt;
&lt;li&gt;Proceed only when objections are resolved or deferred with rationale.&lt;/li&gt;
&lt;li&gt;Ask for a spec and implementation plan.&lt;/li&gt;
&lt;li&gt;Implement in a separate context.&lt;/li&gt;
&lt;li&gt;Audit in a separate context.&lt;/li&gt;
&lt;li&gt;Remediate if needed.&lt;/li&gt;
&lt;li&gt;Ship only after human approval.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Checklist:&lt;/strong&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Before Council
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Problem statement written&lt;/li&gt;
&lt;li&gt;[ ] Source-grounded proposal created&lt;/li&gt;
&lt;li&gt;[ ] Roles selected (minimum: Critical Reviewer + Simplifier)&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  During Council
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Same proposal sent to each role&lt;/li&gt;
&lt;li&gt;[ ] Feedback collected with role labels&lt;/li&gt;
&lt;li&gt;[ ] Synthesis performed&lt;/li&gt;
&lt;li&gt;[ ] Objection ledger updated&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Before Implementation
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;[ ] No blocking objections&lt;/li&gt;
&lt;li&gt;[ ] Plan/spec written&lt;/li&gt;
&lt;li&gt;[ ] Acceptance criteria defined&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Before Shipping
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Implementation reviewed by independent auditor&lt;/li&gt;
&lt;li&gt;[ ] Audit findings resolved or deferred&lt;/li&gt;
&lt;li&gt;[ ] Human approval given&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Start with this. Run it three times. You'll find your own refinements quickly.&lt;/p&gt;




&lt;h3&gt;
  
  
  A Small Hypothetical Example
&lt;/h3&gt;

&lt;p&gt;To make this concrete, here's how the workflow might play out on a common engineering problem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The problem:&lt;/strong&gt; A team needs to refactor a shared validation layer used by multiple modules. The current validation logic is duplicated across three services, with subtle inconsistencies. The team wants to unify it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Source-Grounded Architect proposes:&lt;/strong&gt; Extract a shared validation library, define a canonical schema, migrate each service one at a time with feature flags for rollback.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Critical Reviewer identifies:&lt;/strong&gt; Migration risk — if the shared library has a bug, all three services fail simultaneously. The proposal doesn't address versioning or backward compatibility for services that can't migrate immediately.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Simplifier challenges:&lt;/strong&gt; The feature flag approach adds complexity. If the new validation is strictly a superset of the old, why not just swap in-place with good test coverage? The abstraction layer proposed (strategy pattern with injectable validators) may be over-engineering for what's essentially string and schema validation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Alternatives Reviewer suggests:&lt;/strong&gt; Incremental rollout using the strangler fig pattern — new requests go through the new validator, old requests continue on legacy until traffic proves the new path is stable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Synthesis updates the plan:&lt;/strong&gt; Adopts incremental rollout (strangler fig) instead of big-bang migration. Drops the strategy pattern in favor of a simpler shared module with versioned schemas. Adds a compatibility test suite that runs both old and new validation on the same inputs to catch divergence.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Objection ledger resolves the concerns:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ID&lt;/th&gt;
&lt;th&gt;Objection&lt;/th&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;th&gt;Resolution&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;OBJ-001&lt;/td&gt;
&lt;td&gt;Simultaneous failure risk&lt;/td&gt;
&lt;td&gt;Resolved&lt;/td&gt;
&lt;td&gt;Strangler fig eliminates big-bang risk&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OBJ-002&lt;/td&gt;
&lt;td&gt;Over-engineered abstraction&lt;/td&gt;
&lt;td&gt;Accepted&lt;/td&gt;
&lt;td&gt;Simplified to shared module&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OBJ-003&lt;/td&gt;
&lt;td&gt;No versioning strategy&lt;/td&gt;
&lt;td&gt;Resolved&lt;/td&gt;
&lt;td&gt;Versioned schemas with compatibility suite&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Executor implements&lt;/strong&gt; the shared module with versioned schemas and the dual-run compatibility test suite.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Auditor catches&lt;/strong&gt; one spec drift: the executor added an optional "strict mode" parameter not in the spec, which would create an implicit API contract. Flagged as a deviation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Remediation fixes it:&lt;/strong&gt; Strict mode removed. If needed later, it goes through its own spec cycle.&lt;/p&gt;

&lt;p&gt;The point of the example is not the exact implementation detail. The point is that the council changed the shape of the solution before code was written: from a risky big-bang migration to a safer incremental rollout, with unnecessary abstraction removed before it became implementation debt.&lt;/p&gt;




&lt;h3&gt;
  
  
  What This Workflow Is Not
&lt;/h3&gt;

&lt;p&gt;Let me be explicit:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Not a claim that AI councils are new.&lt;/strong&gt; The concepts of LLM councils, multi-agent debate, multi-agent workflows, and role-based AI review exist publicly. I didn't invent the broad idea.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not a fully autonomous engineering system.&lt;/strong&gt; Human governance is intentionally preserved at every gate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not a replacement for human accountability.&lt;/strong&gt; The human accepts delivery risk. AI provides proposals, critique, and implementation — but the human owns the outcome.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not a workflow for every task.&lt;/strong&gt; This is for ambiguous, high-risk, architecturally significant work. Using it for a trivial bug fix would be absurd overhead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not "just ask multiple models."&lt;/strong&gt; The value is in the structure: roles, synthesis, objection tracking, source grounding, audit separation, and governance gates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not a requirement to use any specific tool.&lt;/strong&gt; The methodology is tool-neutral. Any agentic coding environment that can inspect a repository, reason over code, and support separate working contexts can play the source-grounded roles.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not a platform automation proposal.&lt;/strong&gt; The process is the valuable part.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Automation can reduce clerical overhead later — routing prompts, collecting feedback, maintaining the ledger, generating artifacts. But that's optimization, not the core value.&lt;/p&gt;




&lt;h3&gt;
  
  
  When to Use It, and When Not To
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Use this workflow for:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ambiguous architecture where multiple valid approaches exist&lt;/li&gt;
&lt;li&gt;Cross-cutting refactors that affect many modules or boundaries&lt;/li&gt;
&lt;li&gt;High-risk implementation plans where getting it wrong is expensive&lt;/li&gt;
&lt;li&gt;Unclear ownership boundaries between systems or teams&lt;/li&gt;
&lt;li&gt;Incomplete documentation where the "right answer" isn't written down&lt;/li&gt;
&lt;li&gt;Spec generation for AI-assisted implementation&lt;/li&gt;
&lt;li&gt;Changes where implementation drift from intent would be costly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Do not use it for:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Trivial bugs with obvious fixes&lt;/li&gt;
&lt;li&gt;Small, localized changes with clear paths&lt;/li&gt;
&lt;li&gt;Low-risk UI changes where the worst case is a quick revert&lt;/li&gt;
&lt;li&gt;Already-approved implementation paths&lt;/li&gt;
&lt;li&gt;Work where speed matters more than design confidence&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The overhead is real. It pays off when the cost of getting the design wrong exceeds the cost of the process.&lt;/p&gt;




&lt;h3&gt;
  
  
  Closing
&lt;/h3&gt;

&lt;p&gt;AI councils are not valuable because they sound sophisticated or because multi-agent systems are trending in research papers.&lt;/p&gt;

&lt;p&gt;They're valuable when treated as an engineering process — with defined roles, tracked objections, structured synthesis, independent audit, and human governance gates. Without that structure, consulting multiple models is just expensive brainstorming with extra steps.&lt;/p&gt;

&lt;p&gt;What this workflow gives a single engineer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;An architecture review board&lt;/strong&gt; — without needing to schedule five senior engineers in a room&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An implementation team&lt;/strong&gt; — that executes from a clear spec, not a vague description&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An independent audit function&lt;/strong&gt; — that reviews against intent, not just "does it compile"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A decision record&lt;/strong&gt; — that explains why the design looks the way it does, months later&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal is better judgment at higher speed. Not blind automation. Not replacing human accountability. Not claiming that AI can do everything unsupervised.&lt;/p&gt;

&lt;p&gt;The method is portable across tools. The quality depends on the agent's source-grounding capability, its ability to run verification commands, and — most critically — the operator's governance discipline.&lt;/p&gt;

&lt;p&gt;If you try it, start small. One critic. One simplifier. One synthesis round. One audit. See what it catches that you would have missed alone.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>webdev</category>
      <category>productivity</category>
    </item>
    <item>
      <title>RxJS subscription management with Angular</title>
      <dc:creator>Jenning Ho</dc:creator>
      <pubDate>Thu, 09 Sep 2021 11:27:52 +0000</pubDate>
      <link>https://dev.to/j3nnning/rxjs-subscription-management-with-angular-54ek</link>
      <guid>https://dev.to/j3nnning/rxjs-subscription-management-with-angular-54ek</guid>
      <description>&lt;p&gt;Subscription of observables is the bread and butter of using RxJS. With each subscription, we create a &lt;code&gt;Subscription&lt;/code&gt; and it is being held in memory. If not handled, the subscription will be kept in memory and potentially &lt;strong&gt;cause memory leak&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;With this article, I'm going to cover the various methods to manage subscriptions and how to decide on which method to use. RxJS subscription management is one of the common mistakes among developers, partly due to the learning curve of RxJS, partly the opaqueness of subscription, yet it is essential to using RxJS effectively. &lt;/p&gt;

&lt;p&gt;Put simply, managing RxJS subscription is to know when to unsubscribe. Anytime there is a subscription (a &lt;code&gt;.subscribe()&lt;/code&gt; call), developer should know or be aware of when it will be unsubscribed, be it after nth emission, or when the component has been destroyed.&lt;/p&gt;

&lt;p&gt;I'm going to cover 6 ways we can use to manage our subscription, and when to use them, not including any external libraries / plugins besides RxJS itself. Namely &lt;code&gt;async&lt;/code&gt; pipe, &lt;code&gt;first&lt;/code&gt; operator, &lt;code&gt;take&lt;/code&gt; operator, &lt;code&gt;takeWhile&lt;/code&gt; operator, &lt;code&gt;takeUntil&lt;/code&gt; operator, and finally the &lt;code&gt;.unsubscribe()&lt;/code&gt; call. Which to use is dependent on the context, ie. is the piped function (ie. side effects) complex? How often or how long should the subscription be kept alive?&lt;/p&gt;




&lt;h3&gt;
  
  
  async pipe
&lt;/h3&gt;

&lt;p&gt;The first method that we should always try to reach for is the &lt;code&gt;async&lt;/code&gt; pipe method. With &lt;code&gt;async&lt;/code&gt; pipe, we won't need to handle the unsubscribe manually, both subscribe and unsubscribe will be handled for you in the &lt;code&gt;Pipe&lt;/code&gt;. It unsubscribes from the observable as soon as the component is destroyed. Internally, it also handles the change detection for you. With &lt;code&gt;async&lt;/code&gt; pipe, there'll be a lot less code in your .ts file. Less code, less bug. &lt;/p&gt;

&lt;h6&gt;
  
  
  &lt;code&gt;async pipe used in app.component.html&lt;/code&gt;
&lt;/h6&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;{{ data$ | async }}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, there's one caveat with &lt;code&gt;async&lt;/code&gt; pipe method, it is that every time the UI re-renders in Angular, any &lt;code&gt;async&lt;/code&gt; piped observable will trigger, causing any functions, operations or side effects in between to be triggered, as many times as the UI re-renders. If you have an expensive operation in between the pipe, it'll be heavy on the resources. Keep this in mind and move the heavy operations to a different stream of observable and handle them in the component's class (.ts) file. &lt;/p&gt;

&lt;p&gt;Also, &lt;code&gt;async&lt;/code&gt; pipe is really only applicable when the data needs to be printed in template. Still, it should be the first method we reach for to manage observable subscription when the situation allows.&lt;/p&gt;

&lt;p&gt;Reference: &lt;a href="https://angular.io/api/common/AsyncPipe" rel="noopener noreferrer"&gt;AsyncPipe&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  first operator
&lt;/h3&gt;

&lt;p&gt;Despite the name, the &lt;code&gt;first&lt;/code&gt; operator is the second method we consider. With &lt;code&gt;first&lt;/code&gt; operator, your observable subscription will be unsubscribed as soon as there's one emission that passes through. We can pass in a function as our predicate / validator to ensure that the one emission through this operator is the value that we want. This is the operator to go for when we know very surely that we'll only need one emission from the subscription.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="c1"&gt;// without requirement&lt;/span&gt;
&lt;span class="c1"&gt;// unsubscribed with one emission&lt;/span&gt;
&lt;span class="nx"&gt;data$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// output: 0&lt;/span&gt;

&lt;span class="c1"&gt;// with guard / validator function&lt;/span&gt;
&lt;span class="c1"&gt;// ensures only truthy value can pass through&lt;/span&gt;
&lt;span class="c1"&gt;// will only unsubscribe after one truthy value&lt;/span&gt;
&lt;span class="nx"&gt;data$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// output: 1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reference: &lt;a href="https://www.learnrxjs.io/learn-rxjs/operators/filtering/first" rel="noopener noreferrer"&gt;first&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  take operator
&lt;/h3&gt;

&lt;p&gt;Similar to &lt;code&gt;first&lt;/code&gt; operator, &lt;code&gt;take&lt;/code&gt; operator accepts a finite number of emission, difference being that it can take more than one emission. One other difference being &lt;code&gt;first&lt;/code&gt; will emit an error if the stream completes before a value is emitted, while &lt;code&gt;take&lt;/code&gt; won't. Use this operator when you know only a finite number of emission is needed. You may also consider adding a &lt;code&gt;filter&lt;/code&gt; operator to guard against the emissions to ensure that the nth number of emission that you get are of value to you.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// takes 3 truthy value&lt;/span&gt;
&lt;span class="nx"&gt;data$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;take&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// output: 1, 2, 3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reference: &lt;a href="https://www.learnrxjs.io/learn-rxjs/operators/filtering/take" rel="noopener noreferrer"&gt;take&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  takeWhile operator
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;takeWhile&lt;/code&gt; operator will keep the subscription alive while a condition is true. This operator will take in a predicate / validator function to determine the condition to be true or false.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// take while value is less than 4&lt;/span&gt;
&lt;span class="nx"&gt;data$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;takeWhile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// output: 1, 1, 1, 2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is not common to reach for this operator, however there are certain situation that calls for it, ie. we want the subscription to stop as soon as a condition is fulfilled. Another instance, we want to remain subscribed as soon as we hover on an element, and unsubscribe as soon as we leave.&lt;/p&gt;

&lt;p&gt;Reference: &lt;a href="https://www.learnrxjs.io/learn-rxjs/operators/filtering/takewhile" rel="noopener noreferrer"&gt;takeWhile&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  takeUntil operator
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;takeUntil&lt;/code&gt; operator accepts an observable as its notifier that will tell it when to end the subscription. When the notifier is passed in to &lt;code&gt;takeUntil&lt;/code&gt; operator, it will subscribe to that observable internally, and as soon as there's one emit from the notifier, it will unsubscribe from both the source and the notifier observable. Do note that the notifier observable is unsubscribed by &lt;code&gt;takeUntil&lt;/code&gt; internally, hence it is unecessary to unsubscribe or complete the notifier observable if nothing else is subscribed to the notifier.&lt;/p&gt;

&lt;p&gt;This operator is likely the most common operator that we'll use. If none of the above mentioned operators worked for your situation, then &lt;code&gt;takeWhile&lt;/code&gt; will most likely be the one for the job. It is most often used to keep a subscription alive until an event happened, i.e. when a component is destroyed.&lt;/p&gt;

&lt;h6&gt;
  
  
  &lt;code&gt;takeUntil to end subscription when component is destroyed&lt;/code&gt;
&lt;/h6&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppComponent&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;OnInit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OnDestroy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;destroyed$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Subject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nf"&gt;ngOnInit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;interval$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;interval$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nf"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
      &lt;span class="nf"&gt;takeUntil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;destroyed$&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;ngOnDestroy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;destroyed$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When using &lt;code&gt;takeUntil&lt;/code&gt; to end a subscription, make sure that you place it last in the chain of operators to ensure that it covers all the streams in between. This will prevent the subscription leak to streams that are after the &lt;code&gt;takeUntil&lt;/code&gt; operator.&lt;/p&gt;

&lt;h6&gt;
  
  
  &lt;code&gt;takeUntil subscription leak&lt;/code&gt;
&lt;/h6&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;streamA$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;streamB$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;notifier$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Subject&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;streamA$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;takeUntil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;notifier$&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nf"&gt;switchMap&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;streamB$&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;notifier$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the snippet above, &lt;code&gt;streamA$&lt;/code&gt; would end after the &lt;code&gt;notifier$&lt;/code&gt; emitted, but &lt;code&gt;streamB$&lt;/code&gt; would not end, it's subscription would be kept alive and that is the &lt;code&gt;takeUntil&lt;/code&gt; leak.&lt;/p&gt;

&lt;p&gt;Reference: &lt;a href="https://www.learnrxjs.io/learn-rxjs/operators/filtering/takeuntil" rel="noopener noreferrer"&gt;takeUntil&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  .unsubscribe()
&lt;/h3&gt;

&lt;p&gt;Finally, we can simply call &lt;code&gt;.unsubscribe()&lt;/code&gt; of a &lt;code&gt;Subscription&lt;/code&gt; to end the subscription. You'll have to first assign your subscription to a variable, or a class property, then call &lt;code&gt;.unsubscribe()&lt;/code&gt; when it is time to end the subscription.&lt;/p&gt;

&lt;h6&gt;
  
  
  &lt;code&gt;single subscription .unsubscribe()&lt;/code&gt;
&lt;/h6&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;interval$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;subscription&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;interval$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;subscription&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unsubscribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, because we'll have to assign each subscription to a variable, it is a lot more work / code to do, and it is done very manually and imperatively compared to the few above mentioned methods. It is especially so when there are more than one subscription.&lt;/p&gt;

&lt;h6&gt;
  
  
  &lt;code&gt;batch subscriptions .unsubscribe()&lt;/code&gt;
&lt;/h6&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;subsciptions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;interval$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;subscriptionA&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;interval$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;subscriptionB&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;interval$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;subscriptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;subscriptionA&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;subscriptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;subscriptionB&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;subscriptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;subscription&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;subscription&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unsubscribe&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reference: &lt;a href="https://rxjs.dev/guide/subscription" rel="noopener noreferrer"&gt;Subscription&lt;/a&gt;&lt;/p&gt;




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

&lt;p&gt;So I've covered 6 ways we can manage our RxJS subscriptions, ordered according to a heirarchy of decisions. Learn them, and decide for yourself which one is best suited to solve your problem in the context. &lt;/p&gt;

&lt;p&gt;Worth mentioning, there's a library named &lt;a href="https://github.com/ngneat/until-destroy" rel="noopener noreferrer"&gt;UntilDestroy&lt;/a&gt; that can help you unsubscribe from observables when the component is destroyed. It's like &lt;code&gt;takeUntil&lt;/code&gt; except you write less code.&lt;/p&gt;

&lt;p&gt;That's all I have to share. Happy coding!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>angular</category>
      <category>rxjs</category>
      <category>codequality</category>
    </item>
    <item>
      <title>Improve your Javascript conditionals</title>
      <dc:creator>Jenning Ho</dc:creator>
      <pubDate>Sun, 25 Jul 2021 16:37:33 +0000</pubDate>
      <link>https://dev.to/j3nnning/improve-your-javascript-conditionals-3jmk</link>
      <guid>https://dev.to/j3nnning/improve-your-javascript-conditionals-3jmk</guid>
      <description>&lt;p&gt;Writing conditionals are unavoidable when building software. It is one of the key topics when learning Javascript. However, conditionals are also the biggest contributor to push our software into entropy. It is important to be clear and explicit with our conditionals to ensure the quality of our code is maintained.&lt;/p&gt;

&lt;p&gt;Modern Javascript provide us a vast arsenal of tools and methods to help structure our code. Here are some tips to improve your Javascript conditionals:&lt;/p&gt;




&lt;h3&gt;
  
  
  1. Name your condition
&lt;/h3&gt;

&lt;p&gt;The first and maybe the most impactful thing you can do to improve your code is naming things correctly, that includes when dealing with conditionals. After all, &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;There are only two hard things in Computer Science: cache invalidation and naming things.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Phil Karlton&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;Be explicit with what you're checking for when writing an if statement, especially so if its a multi-condition check. You may get a pass if its a short one liner with single condition.&lt;/p&gt;

&lt;h6&gt;
  
  
  BAD
&lt;/h6&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;group&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fruits&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;apple&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ripe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// slice my apple&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h6&gt;
  
  
  GOOD
&lt;/h6&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isAppleRipe&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;group&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fruits&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;apple&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ripe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isAppleRipe&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// slice my apple&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another quick tip here: naming boolean type variable, start it with "is", or "should" or "has", that are intuitively of boolean nature.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Type coercion
&lt;/h3&gt;

&lt;p&gt;Javascript is a dynamically typed language, that means variable in Javascript can switch data type on the fly if you're not careful. Understand what are &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Truthy" rel="noopener noreferrer"&gt;truthy&lt;/a&gt; and &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Falsy" rel="noopener noreferrer"&gt;falsy&lt;/a&gt; values, and type cast your conditional check into boolean using &lt;code&gt;!&lt;/code&gt; and &lt;code&gt;!!&lt;/code&gt; (single and double exclamation). This is especially useful when writing Typescript that are type sensitive when return values.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isEmpty&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isNotEmpty&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In most cases, you want to avoid explicitly checking for type. Ultimately it depends on the requirement, maybe in certain cases you want to be really explicit that you're checking for undefined, or null, but usually you can get away with simply casting them into boolean.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isAvailable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// do your thing&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// instead of&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isAvailable&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;isAvailable&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;isAvailable&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// do your thing&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're using Typescript, you should instead leverage on it's capability by declaring variable type along side with the variable. Otherwise, default parameters in javascript can also help your case here. Design your software in a way where falsy or truthy value is expected.&lt;/p&gt;

&lt;h6&gt;
  
  
  BAD
&lt;/h6&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;doYourThing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isActive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isActive&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;isActive&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;isActive&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h6&gt;
  
  
  GOOD
&lt;/h6&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;doYourThing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isActive&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isActive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In cases where we'd check for object property value, we're used to a long list of condition chaining, ie. &lt;code&gt;item &amp;amp;&amp;amp; item.name&lt;/code&gt; to avoid nullish reference error. We can now use &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining" rel="noopener noreferrer"&gt;optional chaining&lt;/a&gt; when checking for object property, which would return &lt;code&gt;undefined&lt;/code&gt; if it is not available.&lt;/p&gt;

&lt;h6&gt;
  
  
  BAD
&lt;/h6&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h6&gt;
  
  
  GOOD
&lt;/h6&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  3. Guard clause
&lt;/h3&gt;

&lt;p&gt;Guard clause is a fancy way to tell you to always return early. Write your conditions to exit a function, rather than conditions to enter a function, to put it succinctly:&lt;/p&gt;

&lt;h6&gt;
  
  
  BAD
&lt;/h6&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getUserSession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// proceed to get user session&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h6&gt;
  
  
  GOOD
&lt;/h6&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getUserSession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// proceed to get user session&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By exiting a function early with guard clause, you get the invalid cases out of the way first (the bouncer pattern), before proceeding with the "real" body of your function. This will effectively reduce your code indentation caused by multi-level nested &lt;code&gt;if else&lt;/code&gt; statements that are hard to read and hard to edit.&lt;/p&gt;

&lt;p&gt;Mentally it also helps your fellow developers to jump to the next function earlier without needing to read through the whole body of function.&lt;/p&gt;




&lt;h3&gt;
  
  
  4. Conditional operators
&lt;/h3&gt;

&lt;p&gt;A lot of the times we need to assign values or call a function based on condition. We can use conditional operators to make our code a little cleaner and easier to follow. Which conditional operator to use will depend on the requirement.&lt;/p&gt;

&lt;p&gt;When declaring a variable, we should minimize the need for re-assignment to help with predictability of your code. In the same spirit, it is good to prefer const when declaring a variable. &lt;/p&gt;

&lt;p&gt;In cases where the value of the variable can be different if condition is true or false, we can use &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator" rel="noopener noreferrer"&gt;ternary operator&lt;/a&gt; to help shorten our code:&lt;/p&gt;

&lt;h6&gt;
  
  
  BAD
&lt;/h6&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;itemGroup&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;itemType&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;apple&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;itemGroup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fruit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;itemGroup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vegetable&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h6&gt;
  
  
  GOOD
&lt;/h6&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;itemGroup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;itemType&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;apple&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fruit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vegetable&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, be mindful to not overdo it with multiple nested ternary operator. In cases where that is required, consider restructuring your logic or use one of the methods mentioned later in the article to handle conditionals with multiple outs.&lt;/p&gt;

&lt;p&gt;In cases where we need to assign value if value is falsy, we can use OR &lt;code&gt;||&lt;/code&gt; operator. If we want to be more explicit with our checking, to target only &lt;code&gt;null&lt;/code&gt; or &lt;code&gt;undefined&lt;/code&gt; we can use &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator" rel="noopener noreferrer"&gt;nullish coalescing&lt;/a&gt; operator.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;itemNameFalsyCheck&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Name is falsy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;itemNameNullOrUndefinedCheck&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Name is null or undefined&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  5. List check
&lt;/h3&gt;

&lt;p&gt;There are many scenarios where we are dealing with a list of values, and we'll want to check for something in the list, either if value exist, or value is of certain type, etc.&lt;/p&gt;

&lt;p&gt;If we're checking for multiple values we can use Array method &lt;code&gt;.includes&lt;/code&gt; or Set method &lt;code&gt;.has&lt;/code&gt; instead of chaining multiple OR operators.&lt;/p&gt;

&lt;h6&gt;
  
  
  BAD
&lt;/h6&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isFruit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;apple&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;orange&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;durian&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isFruit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h6&gt;
  
  
  GOOD
&lt;/h6&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isFruit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;apple&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;orange&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;durian&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// or&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isFruit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;apple&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;orange&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;durian&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is worth nothing that &lt;code&gt;Set.has&lt;/code&gt; has a significant performance edge over &lt;code&gt;Array.includes&lt;/code&gt;, especially when dealing with a &lt;a href="https://www.tech-hour.com/javascript-performance-and-optimization" rel="noopener noreferrer"&gt;large data set&lt;/a&gt;, it is worth fitting Set checking in your code when possible.&lt;/p&gt;

&lt;p&gt;However in cases where Set has to be repeatedly re-initialized (ie. in a loop), the cost of initializing Set will be too big, the offset will result in worse performance, and in such cases it is better to stick with &lt;code&gt;Array.includes&lt;/code&gt;.&lt;/p&gt;

&lt;h6&gt;
  
  
  BAD
&lt;/h6&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;listOfFruits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fruits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;apple&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;orange&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;durian&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;fruits&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h6&gt;
  
  
  GOOD
&lt;/h6&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;listOfFruits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;apple&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;orange&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;durian&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we're checking for any of the items in a list is of certain value, we can use &lt;code&gt;Array.some&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hasFruits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fruit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we're checking whether all of the items in a list if of certain value, we can use &lt;code&gt;Array.every&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;itsAllFruits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;every&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fruit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  6. Multiple outs
&lt;/h3&gt;

&lt;p&gt;In cases where we are checking for more than 2 outs, there are multiple ways to handle them without the need for multiple &lt;code&gt;if else&lt;/code&gt; statement. It is in fact best to avoid multiple &lt;code&gt;if else&lt;/code&gt; as it is notoriously hard to read, hard to edit, and also slower in performance in comparison to the few options that we have. They are namely, &lt;code&gt;switch&lt;/code&gt; statements, &lt;code&gt;object&lt;/code&gt; literals, and &lt;code&gt;Map&lt;/code&gt;.&lt;/p&gt;

&lt;h6&gt;
  
  
  BAD
&lt;/h6&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;itemGroup&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;apple&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;itemGroup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fruit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;carrot&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;itemGroup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vegetable&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mazda&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;itemGroup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;car&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;itemGroup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fruit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;h6&gt;
  
  
  GOOD
&lt;/h6&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;itemGroup&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// with switch&lt;/span&gt;
&lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;carrot&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nx"&gt;itemGroup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vegetable&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mazda&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nx"&gt;itemGroup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;car&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;apple&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nx"&gt;itemGroup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fruit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// with object&lt;/span&gt;
&lt;span class="nx"&gt;itemGroup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;apple&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fruit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;carrot&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vegetable&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;mazda&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;car&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;}[&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fruit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// with Map&lt;/span&gt;
&lt;span class="nx"&gt;itemGroup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;apple&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fruit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;carrot&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vegetable&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mazda&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;car&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fruit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can also use &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/IIFE" rel="noopener noreferrer"&gt;IIFE&lt;/a&gt; with switch to make our switch statement much more readable. Using IIFE to handle switch cases also open up your conditional check for data massaging before returning. Just be mindful and not overdo it, keep it small and simple.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;itemGroup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;carrot&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vegetable&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mazda&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;car&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;apple&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fruit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;})(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






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

&lt;p&gt;Be mindful when writing conditionals in your code. It is one of the foundation to becoming a solid Javascript developer. One last tip I have is to extract your commonly used check / validations into small utility functions. They are easily readable, testable, which will result in a less error prone system. That is all that I have to share when it comes to improving your Javascript conditionals. Happy coding!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>functional</category>
      <category>programming</category>
      <category>codequality</category>
    </item>
    <item>
      <title>Animated CSS loaders</title>
      <dc:creator>Jenning Ho</dc:creator>
      <pubDate>Sat, 12 Jun 2021 11:46:27 +0000</pubDate>
      <link>https://dev.to/j3nnning/animated-css-loaders-2km4</link>
      <guid>https://dev.to/j3nnning/animated-css-loaders-2km4</guid>
      <description>&lt;p&gt;Let's talk about a set of CSS loaders / spinners that I've made recently. A little brief on the idea and the technical details behind them. &lt;/p&gt;

&lt;p&gt;Here is the set of loaders and their source code, written in plain HTML &amp;amp; CSS. The idea is to make them readable to anyone with some CSS understanding and hopefully inspire you to make one yourself.&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/jenning/embed/LYWJdWz?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h6&gt;
  
  
  They are rearranged for better display, not sequentially ordered.
&lt;/h6&gt;




&lt;h3&gt;
  
  
  The brief
&lt;/h3&gt;

&lt;p&gt;With this set, I wanted to do some motion animation with 2 dots mixed with more advanced and tricky animation using 3d perspective, that relies a bit on sleight of hand principle for the visual to work.&lt;/p&gt;

&lt;p&gt;The first and the main constraint I have is to make these with single HTML element. This is so that they can be easily applied to projects without complicating the code too much, which makes them practical.&lt;/p&gt;

&lt;p&gt;Secondly without applying SCSS or SASS, I can't be doing a lot of hardcoded values, or multiple nth elements with loop. I mostly mitigate this constraint by using CSS custom properties. CSS custom properties is different from SASS variables, in the sense that they are not static. They are dynamic based on context, which you'll see from their application in this set. A good example is &lt;code&gt;--loader-size-half&lt;/code&gt; applied in &lt;code&gt;loader--7&lt;/code&gt;. By only setting &lt;code&gt;--loader-size&lt;/code&gt;, &lt;code&gt;--loader-size-half&lt;/code&gt; being an abstract &lt;code&gt;calc&lt;/code&gt; function based on &lt;code&gt;--loader-size&lt;/code&gt;, will also update its value accordingly.&lt;/p&gt;

&lt;p&gt;This set contains mostly square and circles, as such they are always same height and width. Instead of setting both width and height manually, I choose to use the relatively new CSS property &lt;code&gt;aspect-ratio&lt;/code&gt;. By only setting the &lt;code&gt;width&lt;/code&gt; value, and setting &lt;code&gt;aspect-ratio&lt;/code&gt; value to &lt;code&gt;1 / 1&lt;/code&gt;, it turns the element into square. Finally, &lt;code&gt;border-radius&lt;/code&gt; 50% will make any element that has equal width and height into circles.&lt;/p&gt;




&lt;h3&gt;
  
  
  The .loader class
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.loader&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--loader-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--block-size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="py"&gt;--loader-size-half&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--loader-size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="py"&gt;--loader-size-half-neg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--loader-size-half&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;*&lt;/span&gt; &lt;span class="m"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="py"&gt;--light-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="py"&gt;--dot-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--dot-size-half&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--dot-size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="py"&gt;--dot-size-half-neg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--dot-size-half&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;*&lt;/span&gt; &lt;span class="m"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;block&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;relative&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--loader-size&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;place-items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the base class for all loaders. Within this class I've declared a few CSS custom properties that can be applied and reused in every loader.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.loader&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--loader-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--block-size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="py"&gt;--loader-size-half&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--loader-size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="py"&gt;--loader-size-half-neg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--loader-size-half&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;*&lt;/span&gt; &lt;span class="m"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="py"&gt;--light-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="py"&gt;--dot-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--dot-size-half&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--dot-size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="py"&gt;--dot-size-half-neg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--dot-size-half&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;*&lt;/span&gt; &lt;span class="m"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;base loader size is half of block size, the container&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--loader-size-half&lt;/code&gt; is a &lt;code&gt;calc&lt;/code&gt; function that calculates half of loader size, which can be updated in real time by setting loader size value.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--loader-size-half-neg&lt;/code&gt; is simply half of loader size turned negative by multiplying it with -1.&lt;/li&gt;
&lt;li&gt;light color is meant to be a constant to be used in many places.&lt;/li&gt;
&lt;li&gt;dot size is the size of each tiny white circle, is set to 5px. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The elements inside each loader are centered by default with this 2 lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.loader&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;place-items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The color of all elements is also set in this base class with &lt;code&gt;color: white&lt;/code&gt;, which sets the value of &lt;code&gt;currentColor&lt;/code&gt; and be used in every other classes.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;position: relative&lt;/code&gt; is set so that child elements' (::before and ::after pseudo elements) &lt;code&gt;position: absolute&lt;/code&gt; are anchored to it.&lt;/p&gt;




&lt;h3&gt;
  
  
  The dots
&lt;/h3&gt;

&lt;p&gt;They are made with each loader element's pseudo elements, &lt;code&gt;::before&lt;/code&gt; and &lt;code&gt;::after&lt;/code&gt;. With each HTML element, we actually have 2 child elements and 1 parent element to work with. A lot of the time we can create these presentational elements with pseudo elements. You can read more about them &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/::before" rel="noopener noreferrer"&gt;in MDN&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You will notice that most other elements are set to &lt;code&gt;vmin&lt;/code&gt; value rather than &lt;code&gt;px&lt;/code&gt; value, but dot is different. &lt;code&gt;vmin&lt;/code&gt; values are directly tied to the viewport size, while &lt;code&gt;px&lt;/code&gt; is not. Ideally the dot size should be &lt;code&gt;vmin&lt;/code&gt; too, but why is it not? &lt;/p&gt;

&lt;p&gt;This is mainly to make its position precise in relative the the line that each dots is "on". Ultimately when rendered on screen, the visuals are rendered in &lt;code&gt;px&lt;/code&gt; and the smallest &lt;code&gt;px&lt;/code&gt; on screen is &lt;code&gt;1px&lt;/code&gt;. The line is a static &lt;code&gt;1px&lt;/code&gt; size, and as such dot has to be too to make it "sit" on the line centered precisely. You can change dot's &lt;code&gt;5px&lt;/code&gt; value to any &lt;code&gt;vmin&lt;/code&gt; value to see what I mean.&lt;/p&gt;

&lt;p&gt;The loaders with dots can work with 4px ~ 6px sizes visually. So why 5px? So that it can be placed centered to the line. ie. 2px on top, 1px on the line centered, 2px at the bottom. This is the kind of calculation we should make to create pixel perfect layout.&lt;/p&gt;




&lt;h3&gt;
  
  
  The animation
&lt;/h3&gt;

&lt;p&gt;A set of keyframes is declared for each loader despite some of them are the same set of keyframes to keep them separated and contained. Within each loader, the keyframes are reused by applying CSS custom properties. You can see them in action in loader 5, 6, 8, 9.&lt;/p&gt;

&lt;p&gt;Most animation used in this set of loaders are simple translating (moving along the x, y, z axis) and rotating, but made interesting / unique via different easing and delay settings.&lt;/p&gt;

&lt;p&gt;The subjects of each animation (ie. the dots) are actually doing the same motion, just one earlier than the other. This is achieved by simply setting a &lt;code&gt;animation-delay&lt;/code&gt; to one of the dot. Instead of setting a positive delay, which will cause one of the element to pause for awhile before animating, I applied a negative delay. This allow the element to act earlier instead of later, and so skipping the initial pause while also creating the difference in delay.&lt;/p&gt;

&lt;p&gt;When it comes to easing, I am not actually a wizard with bezier-curve calculation. I first have an idea of the outcome, ie. "snappy", "bouncy", "smooth, etc, then play with them in the &lt;a href="https://developers.google.com/web/updates/2015/05/the-easing-editor" rel="noopener noreferrer"&gt;devtool easing editor&lt;/a&gt; to come up with a suitable easing for the animation. ie. for loader 7, the effect is achieved by having an overly "bouncy" easing that allows the dot to go out of it's linear curve and comes back. While most other loaders simply have a "snappy" motion.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

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

&lt;p&gt;With this, I have shared my thoughts and some technical details behind creating this set of loaders. I hope you can pick up some css trickery from this and inspire you to make your own. Feel free to use any of this in your project too. Would make me happy to see actual application of this set. Happy crafting!&lt;/p&gt;

</description>
      <category>css</category>
      <category>animation</category>
      <category>webdev</category>
      <category>design</category>
    </item>
    <item>
      <title>Responsive typography</title>
      <dc:creator>Jenning Ho</dc:creator>
      <pubDate>Mon, 03 May 2021 15:20:13 +0000</pubDate>
      <link>https://dev.to/j3nnning/responsive-typography-4c31</link>
      <guid>https://dev.to/j3nnning/responsive-typography-4c31</guid>
      <description>&lt;p&gt;This article is going to cover 3 common methods to create responsive typography for your website. Responsive typography is one of the core elements to a responsive website, it is about sizing your fonts as the website resizes itself. This is necessary to keep your content inline with the UI design, and that it doesn't break the layout of your website.&lt;/p&gt;

&lt;p&gt;The 3 methods covered are namely &lt;strong&gt;media-queries&lt;/strong&gt;, &lt;strong&gt;CSS clamp&lt;/strong&gt;, and &lt;strong&gt;CSS calc&lt;/strong&gt;. Here's a codepen that demo the 3 methods:&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/jenning/embed/mdRNjZq?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;You may want to open the codepen in another window to play around with the viewport size (resizing the browser) to see how the content scale along the viewport, and observe the differences between the 3 methods.&lt;/p&gt;

&lt;h3&gt;
  
  
  media queries
&lt;/h3&gt;

&lt;p&gt;Using media queries to scope the styling of an element is one of the most common method, as it is one of the earliest available CSS feature. It has the best browser support. You would define a breakpoint, and the styling for an element once the viewport is past the breakpoint.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.block&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="n"&gt;all&lt;/span&gt; &lt;span class="n"&gt;and&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;800px&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;.block&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above code would set &lt;code&gt;.block&lt;/code&gt; element's width to 50% once the screen is above 800px, and 100% while it is below 800px.&lt;/p&gt;

&lt;p&gt;similarly we can use this technique to set the font sizes of our content.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="nc"&gt;.title&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="n"&gt;all&lt;/span&gt; &lt;span class="n"&gt;and&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;800px&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="nc"&gt;.title&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2.5rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This would set &lt;code&gt;.title&lt;/code&gt; to 5rem when screen is above 800px, and 2.5rem while below 800px.&lt;/p&gt;

&lt;h3&gt;
  
  
  clamp()
&lt;/h3&gt;

&lt;p&gt;CSS clamp function allow you to define a range of values, ie. the minimum value, current value, and maximum value of a property. With this in mind, we can apply a responsive view unit as the current value that allows the font to size according to viewport, then set a minimum and maximum font size to keep it within an acceptable range that works with your UI design.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="nc"&gt;.title&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;clamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2.5rem&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;8vw&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;5rem&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This would set &lt;code&gt;.title&lt;/code&gt; to be 8% of the width of your viewport, until 8vw is smaller than 2.5rem, then it would anchor to 2.5rem, or when 8vw is bigger than 5rem, it would stop growing at 5rem. This essentially means that &lt;code&gt;.title&lt;/code&gt; will be within the range of 2.5rem and 5rem, while fluidly scaling according to the size of the viewport.&lt;/p&gt;

&lt;h3&gt;
  
  
  calc()
&lt;/h3&gt;

&lt;p&gt;With CSS calc function you can write a math formula for your element's font size sizing behavior. The suggested formula for responsive font-size is a minimum absolute value plus a percentage value to create a responsive font size. ie. &lt;code&gt;min + viewport size&lt;/code&gt;. The calculated outcome should work with your UI design. &lt;/p&gt;

&lt;p&gt;Caution when using this method, as there isn't a maximum size for the font-size, but we can switch the percentage value to use &lt;code&gt;vmin&lt;/code&gt; instead of &lt;code&gt;vw&lt;/code&gt; to help limit it's growth.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="nc"&gt;.title&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1rem&lt;/span&gt; &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="m"&gt;4vw&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This would set &lt;code&gt;.title&lt;/code&gt; to 1rem + 4% of your viewport width. In other words, &lt;code&gt;.title&lt;/code&gt; will never be smaller than 1rem while it fluidly resize itself accordingly.&lt;/p&gt;

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

&lt;p&gt;Master these 3 methods and you'll create the next perfect responsive website. They're not methods that can only apply to font-sizes of your content, but also every part of your website. You may also mix media queries with either clamp and calc for more advance and intricate sizing behavior. Happy coding! 🥳&lt;/p&gt;

</description>
      <category>css</category>
      <category>beginners</category>
      <category>webdev</category>
      <category>design</category>
    </item>
    <item>
      <title>Resolve promises in sequence with RXJS (ConcatMap)</title>
      <dc:creator>Jenning Ho</dc:creator>
      <pubDate>Tue, 19 Jan 2021 05:26:45 +0000</pubDate>
      <link>https://dev.to/j3nnning/resolve-promises-in-sequence-with-rxjs-concatmap-58a</link>
      <guid>https://dev.to/j3nnning/resolve-promises-in-sequence-with-rxjs-concatmap-58a</guid>
      <description>&lt;p&gt;This article will be a short one mainly on resolving / handling promises in sequence using RXJS. One such example would be fetching a series of data, one after another, but only after the current one resolves.&lt;/p&gt;

&lt;p&gt;The go to RXJS operator to achieve this is &lt;strong&gt;ConcatMap&lt;/strong&gt;. When our use case requires sequentiality, ie. queueing a set of events to be resolved in order, we can consider ConcatMap as a possible solution.&lt;/p&gt;

&lt;p&gt;ConcatMap when paired with RXJS's &lt;strong&gt;Subject&lt;/strong&gt; will present you an easily modifiable, readable, function that can be adapted to most use cases. Here's the code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;concatMap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Subject&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`url-to-api/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;res$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="nx"&gt;res$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;complete&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="p"&gt;});&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res$&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the ConcatMap operator, we return a Subject. &lt;/p&gt;

&lt;p&gt;This way, we can control the flow of the stream, we can decide when is the time to complete the current event and go to the next. The next request will not fire until the current one completes, which we'll do so via &lt;code&gt;.complete()&lt;/code&gt; call.&lt;/p&gt;

&lt;p&gt;In between the fetch response and the completion of the subject, it is the gap for us to perform any modifications, or actions that is required.&lt;/p&gt;

&lt;p&gt;In closing, &lt;a href="https://codepen.io/jenning/pen/GRjzMve" rel="noopener noreferrer"&gt;here's a codepen&lt;/a&gt; to demo the code above.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>angular</category>
      <category>rxjs</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Organize styled-components theme in React with Functional Programming</title>
      <dc:creator>Jenning Ho</dc:creator>
      <pubDate>Mon, 07 Sep 2020 10:46:01 +0000</pubDate>
      <link>https://dev.to/j3nnning/theme-setup-with-styled-components-functional-programming-4i5p</link>
      <guid>https://dev.to/j3nnning/theme-setup-with-styled-components-functional-programming-4i5p</guid>
      <description>&lt;p&gt;Through this article, I'm going to show you one way to setup a theme for your React app using styled-components, and how to implement it in a structured and readable manner by applying functional programming practices.&lt;/p&gt;

&lt;h4&gt;
  
  
  styled-components
&lt;/h4&gt;

&lt;p&gt;styled-components is a CSS-in-JS library. According to the State of CSS 2019 survey, &lt;a href="https://styled-components.com/" rel="noopener noreferrer"&gt;styled-components&lt;/a&gt; is one of if not the most popular option for those opting for CSS-in-JS solution. It's not hard to see why, it gives us the best of ES6 and CSS.&lt;/p&gt;

&lt;p&gt;To style a component we write CSS in template literals. The styling of the component can be adapted by passing a function that accepts component's props into the template literal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;StyledButton&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;styled&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="s2"&gt;`
    height: 40px;
    background-color: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;primary&lt;/span&gt;
        &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;white&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;blue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;;
`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h6&gt;
  
  
  A button component style that will adapt its &lt;code&gt;background-color&lt;/code&gt; based on component's prop &lt;code&gt;primary&lt;/code&gt;.
&lt;/h6&gt;

&lt;p&gt;styled-components appends a theme object to the props for you to access the values that are provided in the setup. The same code previously would be written like so to apply theme values instead.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;StyledButton&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;styled&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="s2"&gt;`
    background-color: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;primary&lt;/span&gt;
        &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;white&lt;/span&gt;
        &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;blue&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;
`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h6&gt;
  
  
  Accessing these theme value can get messy when you have a lot of them.
&lt;/h6&gt;

&lt;h4&gt;
  
  
  Functional programming
&lt;/h4&gt;

&lt;p&gt;How does FP plays a role here? FP is its own subject, but for the purpose of this article, the key concepts we'll need are function composition and function currying. A simple explanation and example to illustrate each:&lt;/p&gt;

&lt;h5&gt;
  
  
  Function currying
&lt;/h5&gt;

&lt;p&gt;A curried function is a function which takes multiple parameters one at a time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;add&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first function takes in the first argument, variable &lt;code&gt;x&lt;/code&gt; and returns another function that is ready to take the second argument, variable &lt;code&gt;y&lt;/code&gt; and finally returns the sum of &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt;.&lt;/p&gt;

&lt;h5&gt;
  
  
  Function composition
&lt;/h5&gt;

&lt;p&gt;Function composition in the simplest term is to combine multiple functions to create a new function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;addDash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;oneDash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;addDash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="nf"&gt;oneDash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// outputs '1-2'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;addDash&lt;/code&gt; function returns a string with a dash appended at the end of the argument. When it is passed into &lt;code&gt;add&lt;/code&gt; it returns a function that will return a string with a dash in between first and second argument.&lt;/p&gt;

&lt;h4&gt;
  
  
  Ramda
&lt;/h4&gt;

&lt;p&gt;In this article I will use my favorite FP utility library, &lt;a href="https://ramdajs.com/" rel="noopener noreferrer"&gt;Ramda&lt;/a&gt; to demonstrate. It provides us an arsenal of small functions that are ready to be curried to compose from. It is what I'm using in most of my React projects, if you like applying FP in your javascript projects do give it a go. &lt;/p&gt;

&lt;h3&gt;
  
  
  Setup
&lt;/h3&gt;

&lt;p&gt;Your theme values will be provided in a &lt;code&gt;ThemeProvider&lt;/code&gt; that comes with styled-components. To set it up:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;white&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#ffffff&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;primary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#3b49df&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Layout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ThemeProvider&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ThemeProvider&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Accessors
&lt;/h4&gt;

&lt;p&gt;Accessors are functions to access your values. A simple &lt;code&gt;props.theme&lt;/code&gt; accessor written in plain javascript can be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;theme&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We'll compose increasingly complex accessor functions by currying them. I'll use the color accessor as an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ramda&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;keys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;path&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;theme&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;color&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;path&lt;/code&gt; function from Ramda will return you the value based on the &lt;em&gt;path&lt;/em&gt; that you've passed in (in the form of array).&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;theme&lt;/code&gt; accessor will return a function that expects props as argument and returns you the theme object.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;color&lt;/code&gt; accessor takes the &lt;code&gt;theme&lt;/code&gt; accessor and compose into a function that, again expects props as argument and returns you the color object.&lt;/p&gt;

&lt;p&gt;Given that our props object shape to be...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;white&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#ffffff&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To get the value of white &lt;code&gt;#ffffff&lt;/code&gt;, we'll call the color accessor with 'white', and that'll return us a function that expects props as argument. Which we can then do this...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;color&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;white&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// outputs '#ffffff'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To review this in plain javascript, it is equivalent to...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;whiteColor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;whiteColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// outputs '#ffffff'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because styled-components's template literal openings expect a function that takes props as argument, you can pass in these accessors to keep the code short and concise like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;StyledButton&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;styled&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="s2"&gt;`
    color: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;color&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;white&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;;
`&lt;/span&gt;

&lt;span class="c1"&gt;// is equivalent to&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;StyledButton&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;styled&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="s2"&gt;`
    color: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;white&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;;
`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see from the snippet above how big of a difference it can make to your code. More complex accessors can be made by composing them with helper functions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;pipe&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ramda&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;space&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;space&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;multiplier&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;space&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
    &lt;span class="nx"&gt;space&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;space&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;multiplier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;space&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;space&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;px`&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nf"&gt;space&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// outputs '20px'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;pipe&lt;/code&gt; will allow you to chain multiple functions together to create one big function. We chain the &lt;code&gt;space&lt;/code&gt; accessor up with 2 other functions, a function that multiplies the base value of space (10) and another that appends the &lt;code&gt;px&lt;/code&gt; unit, to come to the final output of &lt;code&gt;20px&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Helpers
&lt;/h4&gt;

&lt;p&gt;Helper functions help us better compose our function for reusability, similar to mixins in SASS. Some simple helpers to get you started:&lt;/p&gt;

&lt;h5&gt;
  
  
  Appending unit
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;px&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;px`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All fixed sizes of elements should be provided as number value without its unit for ease of calculation and reference. Function like &lt;code&gt;px&lt;/code&gt; will allow us to append px unit to our size value by composing it with the accessor function.&lt;/p&gt;

&lt;h5&gt;
  
  
  Media query
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mobile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;css&lt;/span&gt;&lt;span class="s2"&gt;`
    @media all and (max-width: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;breakpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt; {
        &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;
    }
`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A simple media query for targeting mobile styles. It'll make your media query look clean and simple.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;StyledSection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;styled&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;section&lt;/span&gt;&lt;span class="s2"&gt;`
    height: 100vh;

    &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;mobile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;css&lt;/span&gt;&lt;span class="s2"&gt;`
        height: auto;
    `&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;
`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;css&lt;/code&gt; is a function provided by styled-components to forward the props.&lt;/p&gt;

&lt;h5&gt;
  
  
  Unit converter
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pxToRem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;rem`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is recommended to set values (ie. padding, margin, font-size) to &lt;code&gt;rem&lt;/code&gt;, as that'll scale to user's browser settings. It does involve some calculation though. I like to set my values as px, and have a little helper function to convert px value to rem, so I can apply rem units without thinking about it too much.&lt;/p&gt;

&lt;h3&gt;
  
  
  Implementation
&lt;/h3&gt;

&lt;p&gt;Here's a snippet that shows how your code can look like...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;styled&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;styled-components&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;space&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;theme&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;StyledButton&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;styled&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="s2"&gt;`
    height: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;height&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;px;
    padding: 0 &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;space&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;;
    border: 0;
    background-color: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;color&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;primary&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;;
    color: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;color&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;white&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;;
`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compiles into...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;40px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;16px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#3b49df&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#ffffff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;So there you have it, that's how you can setup a theme with styled-components and write it in a structured and readable manner.&lt;/p&gt;

&lt;p&gt;I have setup a sample project in github that applies all that is written in this article for your reference. You can find it &lt;a href="https://github.com/jennning/styled-components-ramda" rel="noopener noreferrer"&gt;&lt;strong&gt;here&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can find me on &lt;a href="https://twitter.com/J3nnning" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;, feel free to DM me if you have questions.&lt;/p&gt;

&lt;h6&gt;
  
  
  Follow me on DEV and Twitter to read more frontend development tips and practices.
&lt;/h6&gt;

</description>
      <category>css</category>
      <category>javascript</category>
      <category>tutorial</category>
      <category>react</category>
    </item>
    <item>
      <title>Stagger animations with SCSS</title>
      <dc:creator>Jenning Ho</dc:creator>
      <pubDate>Sat, 11 Apr 2020 11:36:13 +0000</pubDate>
      <link>https://dev.to/j3nnning/stagger-animations-with-scss-2k2o</link>
      <guid>https://dev.to/j3nnning/stagger-animations-with-scss-2k2o</guid>
      <description>&lt;h3&gt;
  
  
  Overview
&lt;/h3&gt;

&lt;p&gt;Staggered animations consists of a series of sequential or overlapping animations, similar to a domino effect. Staggering animations is an effective way to add flare to animating a group of items. In the context of web animation, it can be done with the help of a JS animation plugin like GSAP, or simply with CSS, depending on the requirements.&lt;/p&gt;

&lt;h3&gt;
  
  
  Intro
&lt;/h3&gt;

&lt;p&gt;In this post I will show how we can do it with SCSS. SCSS enable us to create staggered animations with its programming like features, namely variable, for loop, and calculations.&lt;/p&gt;

&lt;p&gt;What staggered animations is, is a series of animations that are played in sequence with a tiny delay between each elements. We will need to calculate the delay needed for each elements and apply this delay to the &lt;code&gt;transition-delay&lt;/code&gt; or the &lt;code&gt;animation-delay&lt;/code&gt; property. The delay needs to be less than of the duration of the animation, so that the next animation will start before the current animation ended. Ideally the delay should be between 30% to 70% of the duration for the best effect.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scenario
&lt;/h3&gt;

&lt;p&gt;Given the scenario where there are 4 elements next to each other, and we want to fade in each elements with a duration of 300ms and a delay of 100ms between each other. Here are the HTML and CSS for the effect:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ul&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"list"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"list-item"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;A&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"list-item"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;B&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"list-item"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;C&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"list-item"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;D&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.list-item&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;animation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;fade-in&lt;/span&gt; &lt;span class="m"&gt;300ms&lt;/span&gt; &lt;span class="n"&gt;ease&lt;/span&gt; &lt;span class="n"&gt;forwards&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.list-item&lt;/span&gt;&lt;span class="nd"&gt;:nth-child&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;animation-delay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100ms&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.list-item&lt;/span&gt;&lt;span class="nd"&gt;:nth-child&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;3&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;animation-delay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;200ms&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.list-item&lt;/span&gt;&lt;span class="nd"&gt;:nth-child&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;4&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;animation-delay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;300ms&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@keyframes&lt;/span&gt; &lt;span class="n"&gt;fade-in&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nt"&gt;to&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2 key points from the above code:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;opacity: 0&lt;/code&gt; to hide the elements before they animate.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;forwards&lt;/code&gt; as the &lt;code&gt;animation-fill-mode&lt;/code&gt; value so that the end frame of the animation persists. In this scenario, &lt;code&gt;fade-in&lt;/code&gt; will bring the element's opacity to 1 and persist. Without this, element will disappear as soon as the animation ends.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  SCSS
&lt;/h3&gt;

&lt;p&gt;With SCSS we can achieve the same CSS output with the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="nv"&gt;$n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nc"&gt;.list-item&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;animation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;fade-in&lt;/span&gt; &lt;span class="m"&gt;300ms&lt;/span&gt; &lt;span class="n"&gt;ease&lt;/span&gt; &lt;span class="n"&gt;forwards&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;@for&lt;/span&gt; &lt;span class="nv"&gt;$x&lt;/span&gt; &lt;span class="ow"&gt;from&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="ow"&gt;through&lt;/span&gt; &lt;span class="nv"&gt;$n&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nd"&gt;:nth-child&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nv"&gt;$x&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;animation-delay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100ms&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$x&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;We do a &lt;code&gt;@for&lt;/code&gt; loop that starts from 2, and ends at 4. &lt;/li&gt;
&lt;li&gt;Print / interpolate variable &lt;code&gt;$x&lt;/code&gt; with &lt;code&gt;#{}&lt;/code&gt; to append it into &lt;code&gt;nth-child()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Calculate the delay by multiplying 100ms with &lt;code&gt;($x - 1)&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Do note that the number of loops is dependant on the number of HTML elements to be animated. This does make the SCSS solution to be inflexible if the number of HTML elements are dynamic. So depending on your needs, SCSS might not be enough. In cases where you can safely determine the number of HTML elements, this little snippet can prove to be a valuable tool to staggering animations. Areas where I have applied this technique are such as navigation menu and cover text animations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Formula
&lt;/h3&gt;

&lt;p&gt;The formula to calculating the delay can be the key to manipulating the staggered timing to get the ideal effect. Here are a few that I find commonly applicable:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reverse stagger
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="k"&gt;@for&lt;/span&gt; &lt;span class="nv"&gt;$x&lt;/span&gt; &lt;span class="ow"&gt;from&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="ow"&gt;through&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nd"&gt;:nth-child&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nv"&gt;$x&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;animation-delay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nv"&gt;$x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="m"&gt;100ms&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Ease-in stagger
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="k"&gt;@for&lt;/span&gt; &lt;span class="nv"&gt;$x&lt;/span&gt; &lt;span class="ow"&gt;from&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="ow"&gt;through&lt;/span&gt; &lt;span class="nv"&gt;$n&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nd"&gt;:nth-child&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nv"&gt;$x&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;animation-delay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100ms&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$x&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nv"&gt;$x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;$n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Ease-out stagger
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="k"&gt;@for&lt;/span&gt; &lt;span class="nv"&gt;$x&lt;/span&gt; &lt;span class="ow"&gt;from&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="ow"&gt;through&lt;/span&gt; &lt;span class="nv"&gt;$n&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nd"&gt;:nth-child&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nv"&gt;$x&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;animation-delay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100ms&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$x&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nv"&gt;$n&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;$x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Codepen
&lt;/h3&gt;

&lt;p&gt;Here's a pen to show what's discussed in this post:&lt;br&gt;
&lt;iframe height="600" src="https://codepen.io/jenning/embed/bGVNvqM?height=600&amp;amp;default-tab=css,result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Application
&lt;/h3&gt;

&lt;p&gt;Here are some of my pens where this technique is applied:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://codepen.io/jenning/full/WNQNwVg" rel="noopener noreferrer"&gt;CATS pets store&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://codepen.io/jenning/full/ExarqGq" rel="noopener noreferrer"&gt;Navigation menu&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://codepen.io/jenning/full/bQvqMm" rel="noopener noreferrer"&gt;Interactive progress bar&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Happy animating!&lt;/p&gt;

</description>
      <category>animation</category>
      <category>css</category>
      <category>scss</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Masonry with CSS grid</title>
      <dc:creator>Jenning Ho</dc:creator>
      <pubDate>Mon, 17 Feb 2020 11:23:20 +0000</pubDate>
      <link>https://dev.to/j3nnning/masonry-with-css-grid-1e59</link>
      <guid>https://dev.to/j3nnning/masonry-with-css-grid-1e59</guid>
      <description>&lt;p&gt;A month ago &lt;a href="https://codepen.io/" rel="noopener noreferrer"&gt;codepen&lt;/a&gt; published a challenge to create &lt;a href="https://codepen.io/challenges/2020/january/3" rel="noopener noreferrer"&gt;a photo gallery&lt;/a&gt;. Oh, I know photo gallery, I've made a gallery or two, I thought. So I decided to give it a go.&lt;/p&gt;

&lt;p&gt;What you see in the cover photo is &lt;a href="https://codepen.io/jenning/pen/LYEqgjy" rel="noopener noreferrer"&gt;my submission&lt;/a&gt; for the challenge. Thanks &lt;code&gt;thecatapi.com&lt;/code&gt; for the amusing cat photos.&lt;/p&gt;

&lt;p&gt;Masonry layout can be unimaginative when it comes to photo gallery (&lt;a href="https://masonry.desandro.com/" rel="noopener noreferrer"&gt;what's masonry layout?&lt;/a&gt;), but I had an idea to build it with CSS grid. &lt;a href="https://css-tricks.com/snippets/css/complete-guide-grid/" rel="noopener noreferrer"&gt;CSS grid&lt;/a&gt; is powerful and you should pick it up if you haven't already. It allows you to effectively layout a webpage, but using it to build masonry layout can still be considered fairly novel. What's the secret?&lt;/p&gt;

&lt;p&gt;There are a few key points that I'll cover:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;square grid layout&lt;/li&gt;
&lt;li&gt;varying item sizes and packing them together&lt;/li&gt;
&lt;li&gt;content that doesn't disrupt the container size&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1. Square grids&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;We need square grids to allow the photos to be laid out in a way that makes sense. The square grids will also need to be responsive where it will take up available space. To do that I applied a &lt;a href="https://www.geeksforgeeks.org/maintain-the-aspect-ratio-of-a-div-with-css/" rel="noopener noreferrer"&gt;technique to size an element to specific aspect ratio&lt;/a&gt;. The trick is sizing an element vertically with &lt;code&gt;padding&lt;/code&gt; as opposed to &lt;code&gt;height&lt;/code&gt;. Percentage &lt;code&gt;padding&lt;/code&gt;value is calculated based on the element's &lt;code&gt;width&lt;/code&gt;. i.e. equal % of &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;padding-bottom&lt;/code&gt; will give you a square.&lt;/p&gt;

&lt;p&gt;We don't have to apply this to every grid item (the children of a grid container). This is only applied to 1 element, the &lt;code&gt;:before&lt;/code&gt; pseudo element of the grid container, like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.container&lt;/span&gt;&lt;span class="nd"&gt;:before&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding-bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This squared &lt;code&gt;:before&lt;/code&gt; pseudo element will serve as the blueprint for all other grid item. However, this itself is not enough to generate a square grid layout yet. We will need to couple it with CSS grid's property &lt;code&gt;grid-auto-rows: 1fr&lt;/code&gt; and &lt;code&gt;grid-template-columns: repeat(var(--number-of-columns), 1fr)&lt;/code&gt; to form the layout.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;grid-template-columns: repeat(var(--number-of-columns), 1fr)&lt;/code&gt; to setup the number of columns for your layout&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;grid-auto-rows: 1fr&lt;/code&gt; will force each row to be of equal size.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;grid-auto-rows&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;grid-template-columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this the grid items will be sized into squares, and will be laid out in 6 columns. This is still not the end of square grids. You'll notice that there is an empty gap at the first grid. That is the &lt;code&gt;:before&lt;/code&gt; pseudo element taking up space. To seal this up, move &lt;strong&gt;both&lt;/strong&gt; the pseudo element and the first grid item to the first block.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.container&lt;/span&gt;&lt;span class="nd"&gt;:before&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding-bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;grid-column&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;grid-row&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.grid-item&lt;/span&gt;&lt;span class="nd"&gt;:first-child&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;grid-column&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;grid-row&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now your square grid layout is ready.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;2. Varying item sizes and packing them together&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;To create the varying sizes of a masonry block, we size the grid items using &lt;code&gt;grid-column: span&lt;/code&gt; and &lt;code&gt;grid-row: span&lt;/code&gt;. Then we use &lt;code&gt;:nth-child&lt;/code&gt; to simulate the randomness of a masonry layout. In my pen, I only size items up to 2 blocks, so the code looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/**
  every 3rd item takes up 2 blocks horizontally (2 x 1)
**/&lt;/span&gt;
&lt;span class="nc"&gt;.grid-item&lt;/span&gt;&lt;span class="nd"&gt;:nth-child&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;3&lt;/span&gt;&lt;span class="nt"&gt;n&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;grid-row&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;span&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/**
  every 4th and 7th item takes up only 1 block (1 x 1),
  to overwrite the previous 3n rule
**/&lt;/span&gt;
&lt;span class="nc"&gt;.grid-item&lt;/span&gt;&lt;span class="nd"&gt;:nth-child&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;4&lt;/span&gt;&lt;span class="nt"&gt;n&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
&lt;span class="nc"&gt;.grid-item&lt;/span&gt;&lt;span class="nd"&gt;:nth-child&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;7&lt;/span&gt;&lt;span class="nt"&gt;n&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;grid-column&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;span&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;grid-row&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;span&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/**
  every 5th item takes up 2 blocks vertically (1 x 2),
  also every 15th block will be a big one (2 x 2)
**/&lt;/span&gt;
&lt;span class="nc"&gt;.grid-item&lt;/span&gt;&lt;span class="nd"&gt;:nth-child&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;5&lt;/span&gt;&lt;span class="nt"&gt;n&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;grid-column&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;span&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are some numbers you can tweak to get the gallery to cut off perfectly, (i.e. column count vs item count), and you can tweak the numbers to get a layout that you like. There are no hard rules here. This happen to be the layout that I'm happy with.&lt;/p&gt;

&lt;p&gt;The grid items are now seemingly sized randomly like a masonry, but there are still empty blocks scattered in between, due to the grid item not able to fit in after sizing up.&lt;/p&gt;

&lt;p&gt;To fix that we apply &lt;code&gt;grid-auto-flow: dense&lt;/code&gt; to pack them up. This will force the single block item squeeze into the empty blocks.&lt;/p&gt;

&lt;p&gt;Now you'll see a respectable but empty gallery.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;2. Content that doesn't disrupt the container size&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;To maintain the perfectly squared grid item, the content (the photos) cannot be pulling or pushing the container (the grid item itself), as that'll cause the square to collapse at the next row. We can do this by inline-styling the image url with &lt;code&gt;background-image&lt;/code&gt; property, but that would be terrible for accessibility. So we'll do it the hard way (just kidding), by using the &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tag and styling it with CSS.&lt;/p&gt;

&lt;p&gt;First we want the image to not affect the container. To do that we apply &lt;code&gt;position: absolute&lt;/code&gt; to the image and that will take it out of the document flow.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.grid-item&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;relative&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.photo&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;absolute&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next we want to size the image so that it'll fill up the container of varying sizes. To do this we apply&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.photo&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;absolute&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;object-fit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;cover&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you get a beautifully filled up photo gallery!&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/jenning/embed/LYEqgjy?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Originally I only wanted to highlight the square grid layout technique, but figured a tutorial to build a full feldged photo gallery with css might be more interesting. There are other designs where I've applied the square grid technique too, where you need responsive squares or circles, i.e. the Olympic logo. Be creative! I hope you'll add this to your arsenal of CSS techniques!&lt;/p&gt;

&lt;p&gt;Some related helpful resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://cssgridgarden.com/" rel="noopener noreferrer"&gt;Grid Garden&lt;/a&gt; for CSS grid practices&lt;/li&gt;
&lt;li&gt;&lt;a href="https://every-layout.dev/" rel="noopener noreferrer"&gt;Every layout&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gridbyexample.com/examples/" rel="noopener noreferrer"&gt;Grid examples&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.geeksforgeeks.org/maintain-the-aspect-ratio-of-a-div-with-css/" rel="noopener noreferrer"&gt;Maintaining aspect ratio with CSS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>css</category>
      <category>tutorial</category>
      <category>layout</category>
    </item>
    <item>
      <title>Reusable @keyframes with CSS custom properties</title>
      <dc:creator>Jenning Ho</dc:creator>
      <pubDate>Mon, 13 Jan 2020 11:34:30 +0000</pubDate>
      <link>https://dev.to/j3nnning/reusable-keyframes-with-css-custom-properties-58jn</link>
      <guid>https://dev.to/j3nnning/reusable-keyframes-with-css-custom-properties-58jn</guid>
      <description>&lt;p&gt;In this article, I will share with you an application of CSS custom properties that I have found useful.&lt;/p&gt;

&lt;p&gt;If you're like me, who like to cramp as many animations in the page as possible for micro interactions sake (just kidding, don't do that), you would be writing a lot of CSS animations with &lt;code&gt;@keyframes&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;@keyframes&lt;/code&gt; is notorious for its inflexibility, once it is declared, the values are then set in stone. If you have a set of &lt;code&gt;@keyframes&lt;/code&gt; with the same behavior but different values, you'll need to make another set. This result in a lot of &lt;code&gt;@keyframes&lt;/code&gt; that are similar but with a little variations in the numbers. Let’s take a look at the example below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@keyframes&lt;/span&gt; &lt;span class="n"&gt;fade-in&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="err"&gt;100&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@keyframes&lt;/span&gt; &lt;span class="n"&gt;fade-in-a-little&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="err"&gt;100&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.item-1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;animation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;fade-in&lt;/span&gt; &lt;span class="m"&gt;300ms&lt;/span&gt; &lt;span class="n"&gt;ease&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.item-2&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;animation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;fade-in-a-little&lt;/span&gt; &lt;span class="m"&gt;300ms&lt;/span&gt; &lt;span class="n"&gt;ease&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the example above, we have 2 items with 2 different animations that are similar, with only slight difference in the &lt;code&gt;opacity&lt;/code&gt; value at &lt;code&gt;100%&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now imagine what this would turn into when applied to more items. As the website scale up, what you'll end up with is 100s of similar &lt;code&gt;@keyframes&lt;/code&gt;, bloating up the CSS file. We can't have that. 😐&lt;/p&gt;

&lt;h2&gt;
  
  
  CSS custom properties to the rescue
&lt;/h2&gt;

&lt;p&gt;CSS custom properties (also known as CSS variables), are most widely applied for theming. It can also be used to make &lt;code&gt;@keyframes&lt;/code&gt; reusable! (If you want to learn about CSS custom properties, see &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/--*" rel="noopener noreferrer"&gt;here&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Let's refactor our previous example with CSS custom properties!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@keyframes&lt;/span&gt; &lt;span class="n"&gt;fade&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--fade-start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="err"&gt;100&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--fade-end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.item-1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;animation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;fade&lt;/span&gt; &lt;span class="m"&gt;300ms&lt;/span&gt; &lt;span class="n"&gt;ease&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.item-2&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--fade-end&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;animation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;fade&lt;/span&gt; &lt;span class="m"&gt;300ms&lt;/span&gt; &lt;span class="n"&gt;ease&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;fade-in-a-little&lt;/code&gt; &lt;code&gt;@keyframes&lt;/code&gt; is taken out as it is not needed anymore. We now have only 1 set of &lt;code&gt;@keyframes&lt;/code&gt; &lt;code&gt;fade&lt;/code&gt;, and apply CSS custom properties to the starting opacity value and the ending opacity value with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;opacity: var(--fade-start, 0); // start

opacity: var(--fade-end, 1); // end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, we have 2 custom properties: &lt;code&gt;--fade-start&lt;/code&gt; and &lt;code&gt;--fade-end&lt;/code&gt;. These variables are applied using &lt;code&gt;var()&lt;/code&gt; function (read more about it &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties" rel="noopener noreferrer"&gt;here&lt;/a&gt;). The &lt;code&gt;var()&lt;/code&gt; function accepts 2 parameters, a value and a fallback (default value).&lt;/p&gt;

&lt;p&gt;So with this line &lt;code&gt;opacity: var(--fade-start, 0);&lt;/code&gt;, if &lt;code&gt;--fade-start&lt;/code&gt; is not set, 0 will be applied instead. The same goes to &lt;code&gt;--fade-end&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The end result we get here is a set of &lt;code&gt;@keyframes&lt;/code&gt; that can &lt;code&gt;fade&lt;/code&gt; between &lt;code&gt;opacity: 0&lt;/code&gt; and &lt;code&gt;opacity: 1&lt;/code&gt; by default and be tuned within the scope of a CSS selector. 🤯&lt;/p&gt;

&lt;p&gt;Wait... so to fade out? Yes! Instead of declaring another set of &lt;code&gt;@keyframes&lt;/code&gt; for &lt;code&gt;fade-out&lt;/code&gt;, you can reuse &lt;code&gt;fade&lt;/code&gt; and set &lt;code&gt;--fade-start&lt;/code&gt; as 1, and &lt;code&gt;--fade-end&lt;/code&gt; to 0, like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.item-to-fade-out&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--fade-start&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--fade-end&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;animation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;fade&lt;/span&gt; &lt;span class="m"&gt;300ms&lt;/span&gt; &lt;span class="n"&gt;ease&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With CSS custom properties, &lt;code&gt;@keyframes&lt;/code&gt; can now be function like, where the variable parts can be defined at a later stage, making &lt;code&gt;@keyframes&lt;/code&gt; reusable. Yay &lt;strong&gt;DRY&lt;/strong&gt; ❤️️&lt;/p&gt;

&lt;h2&gt;
  
  
  Time to bust out the Codepen
&lt;/h2&gt;

&lt;p&gt;One &lt;code&gt;@keyframes&lt;/code&gt; to &lt;code&gt;fade&lt;/code&gt; it all&lt;br&gt;
&lt;iframe height="600" src="https://codepen.io/jenning/embed/ZEYxNNG?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h1&gt;
  
  
  Summary
&lt;/h1&gt;

&lt;p&gt;Fading animation is one of the most common animation on the web, now with CSS custom properties we can reduce our CSS bloat significantly while having as many variations of it as we'd like.&lt;/p&gt;

&lt;p&gt;Consider applying this to &lt;code&gt;@keyframes&lt;/code&gt; that you find yourself repeating a lot with many little variations. &lt;/p&gt;

&lt;p&gt;Hope you'll find this useful!&lt;/p&gt;

</description>
      <category>css</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
