<?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>Forem: Thomas Collardeau</title>
    <description>The latest articles on Forem by Thomas Collardeau (@collardeau).</description>
    <link>https://forem.com/collardeau</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F215669%2F45aeefd1-2e02-463f-a514-79368a1be71d.jpeg</url>
      <title>Forem: Thomas Collardeau</title>
      <link>https://forem.com/collardeau</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/collardeau"/>
    <language>en</language>
    <item>
      <title>Building BiasDetector: My Journey into AI Text Analysis with n8n and LLMs</title>
      <dc:creator>Thomas Collardeau</dc:creator>
      <pubDate>Mon, 07 Jul 2025 13:51:04 +0000</pubDate>
      <link>https://forem.com/collardeau/building-biasdetector-my-journey-into-ai-text-analysis-with-n8n-and-llms-54k9</link>
      <guid>https://forem.com/collardeau/building-biasdetector-my-journey-into-ai-text-analysis-with-n8n-and-llms-54k9</guid>
      <description>&lt;p&gt;The way text frames information can profoundly shape our understanding of events and ideas. As AI and Large Language Models (LLMs) become more prevalent, exploring how these tools can help us identify and understand linguistic nuances presents a fascinating challenge. This curiosity, combined with a passion for automation, led me to create BiasDetector — a project focused on using AI to analyze text for potential bias.&lt;/p&gt;

&lt;p&gt;This post shares the journey, technical approach, and lessons learned while building this tool using n8n and LLMs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvssa2tfv3ta9dktuvzxj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvssa2tfv3ta9dktuvzxj.png" alt="Tech meets text: AI analyzes bias in the written word." width="800" height="800"&gt;&lt;/a&gt;&lt;em&gt;Tech meets text: AI analyzes bias in the written word.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The Core Challenge: Focusing AI on Language, Not Just Entities
&lt;/h3&gt;

&lt;p&gt;My interest in this area stemmed from exploring how LLMs could move beyond simple text generation or summarization to tackle more subtle analytical tasks. Early on, a key challenge emerged: LLMs possess vast knowledge from their training data. When analyzing text mentioning specific politicians or organizations, their pre-existing associations with these entities can inadvertently influence or distract from assessing linguistic bias.&lt;/p&gt;

&lt;p&gt;This challenge led to BiasDetector’s central architectural decision: a multi-stage LLM chain designed to isolate and analyze linguistic patterns. The core concept involves a sequential process:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Redactor LLM:&lt;/strong&gt; “Neutralizes” the text by identifying specific entities — people, organizations, locations — and replacing them with generic placeholders. For example, “John Smith visited London” becomes “[PERSON_1] visited [CITY_1]”. This helps focus subsequent analysis while standardizing varied entity references for more consistent outcomes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Bias Analyzer LLM:&lt;/strong&gt; Scrutinizes the anonymized text. Freed from specific entity knowledge, it can better focus on the language itself — phrasing, sentiment, and structure — to identify and analyze bias patterns.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Descrambler LLM:&lt;/strong&gt; Takes the placeholder-based analysis and original entity mappings (the “legend”) to intelligently reconstruct a fully human-readable report.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This chained approach enables more targeted and reliable analysis of how text frames its subject matter, providing greater consistency in outputs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Orchestrating with n8n: From Web Form to Emailed Report
&lt;/h3&gt;

&lt;p&gt;n8n served as the engine for this entire operation, providing the perfect platform to connect sequential LLM calls and manage data flow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhv5n0vp64a30qprafqk1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhv5n0vp64a30qprafqk1.png" alt="The BiasDetector n8n workflow: chaining LLMs for nuanced text analysis." width="800" height="278"&gt;&lt;/a&gt;&lt;em&gt;The BiasDetector n8n workflow: chaining LLMs for nuanced text analysis.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  User Input via JotForm
&lt;/h3&gt;

&lt;p&gt;For the public demo, I created a simple JotForm (try it here: &lt;a href="https://form.jotform.com/251364670893061" rel="noopener noreferrer"&gt;https://form.jotform.com/251364670893061&lt;/a&gt;). Users can paste text (up to 4,000 characters for the demo) and provide an email address. I focused on clear instructions and mandatory fields to ensure a smooth user experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  The n8n Workflow in Action
&lt;/h3&gt;

&lt;p&gt;The workflow follows a clean sequence:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Form Submission:&lt;/strong&gt; JotForm submission triggers the n8n workflow&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Redaction:&lt;/strong&gt; Text goes to the Redactor LLM node, which returns anonymized text and a “legend” mapping placeholders back to original terms&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Analysis:&lt;/strong&gt; Anonymized text passes to the Bias Analysis LLM node, prompted to identify bias patterns and output structured, four-part analysis in JSON format using placeholders&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Descrambling:&lt;/strong&gt; The Bias Analyzer output and legend go to the Descrambler LLM node, which weaves original entity names back into the analysis&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Email Delivery:&lt;/strong&gt; n8n’s data transformation assembles all components into an HTML email sent via Gmail&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;n8n’s visual interface, robust LLM integration nodes, and data handling features made managing this sequence and iterating on the logic incredibly efficient.&lt;/p&gt;

&lt;h3&gt;
  
  
  What BiasDetector Delivers
&lt;/h3&gt;

&lt;p&gt;Users receive a detailed email report offering a multi-faceted look at their submitted text:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Original text&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Clear explanation of the anonymization step&lt;/strong&gt; (showing anonymized text snippet and sample legend)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Comprehensive four-part bias analysis&lt;/strong&gt; with original terms restored&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Bias Analysis Summary&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Potential Impact of Bias&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Alternative Framing Strategies&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This report helps users understand not just how language can convey bias, but how to discern the likely intended impact or persuasive goal of a piece of text. For example, it might highlight not just overtly critical language toward a person, but reveal patterns like consistently associating an organization with negative outcomes — even subtly — that collectively work to frame that organization unfavorably.&lt;/p&gt;

&lt;p&gt;By analyzing these linguistic patterns in isolation from our existing knowledge about the entities involved, BiasDetector can help users recognize when an article might be attempting to shift public opinion, build support for a particular viewpoint, or prime readers to view certain actors favorably or unfavorably. This makes it easier to identify the underlying persuasive intent that might not be immediately obvious when reading the text normally.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lessons from the Redactor: Iterating Towards Intelligent Anonymization
&lt;/h3&gt;

&lt;p&gt;A significant part of this journey involved iteratively refining the Redactor LLM’s prompt — the instructions guiding its anonymization task. This wasn’t simple find-and-replace; it was an exercise in guiding an LLM to understand nuanced requirements.&lt;/p&gt;

&lt;p&gt;Early on, I grappled with optimal redaction levels. Too little redaction leaves the Bias Analyzer potentially influenced by prior entity knowledge. Too aggressive redaction strips away crucial contextual clues or linguistic patterns that indicate bias. Removing descriptive common nouns associated with entities, for instance, might make text too abstract for meaningful analysis.&lt;/p&gt;

&lt;p&gt;The real challenge lay in ensuring redaction was thorough and semantically intelligent. If text mentioned “Rome” and later referred to it as “the Eternal City,” how could the system recognize these as the same entity? The goal was for the Bias Analyzer to understand that bias expressed toward “the Eternal City” was actually bias related to “Rome.”&lt;/p&gt;

&lt;p&gt;This required the Redactor to do more than assign [CITY_1] to “Rome” — it needed to link related terms.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Power of LLMs for Semantic Understanding
&lt;/h3&gt;

&lt;p&gt;Through cycles of prompt testing and adjustment, I experimented with different ways to instruct the Redactor to identify not just primary entities but also their aliases, acronyms, or descriptive references. Success came through careful prompt engineering that guided the LLM to generate linked placeholders. The refined Redactor could identify “Rome” as [CITY_1] and recognize “the Eternal City” as [CITY_1_NICKNAME], with explicit linking in the placeholder nomenclature itself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This is precisely where LLMs shine for such tasks.&lt;/strong&gt; Their inherent understanding of semantic meaning and context allows them to identify relationships — like linking a city to its well-known nickname — that would be extraordinarily complex and brittle to achieve with traditional rule-based programming, and impossibly laborious to do manually at scale. The LLM’s ability to grasp these nuances was fundamental to developing a Redactor that could intelligently prepare text for analysis.&lt;/p&gt;

&lt;p&gt;This iterative dialogue with the Redactor LLM — defining problems with increasing precision, crafting nuanced instructions, observing outputs across diverse texts, and continually refining prompts — was where much of the project’s learning occurred. It highlighted that effective AI application often lies in this detailed, persistent conversation with the model.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Road Ahead
&lt;/h3&gt;

&lt;p&gt;While BiasDetector’s V1 demo is now functional and represents a significant milestone, the potential for further development is substantial. Future possibilities include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Refining analytical depth&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Exploring applications to different content types (government press releases, children’s literature, academic papers)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Expanding into related areas like logical fallacy detection&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The core architecture built with n8n provides a solid foundation for these future explorations, demonstrating how modern no-code platforms can orchestrate sophisticated AI workflows to tackle complex analytical challenges.&lt;/p&gt;

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

&lt;p&gt;BiasDetector has been an incredibly rewarding project. It pushed me to combine thoughtful prompt engineering, workflow automation with n8n, and a critical approach to AI-driven text analysis. Building it involved not just connecting APIs, but truly designing an intelligent process to navigate the complexities of LLM behavior and natural language. It’s a clear demonstration of how these modern tools can be orchestrated to create applications that offer genuine insight. The journey from initial concept to a functioning, user-facing demo has been a significant and fulfilling experience in applied AI.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>automation</category>
      <category>n8n</category>
    </item>
    <item>
      <title>From Data to Delight: Using n8n and LLMs to Automate Insightful Weather Updates</title>
      <dc:creator>Thomas Collardeau</dc:creator>
      <pubDate>Thu, 19 Jun 2025 13:49:12 +0000</pubDate>
      <link>https://forem.com/collardeau/from-data-to-delight-using-n8n-and-llms-to-automate-insightful-weather-updates-55m4</link>
      <guid>https://forem.com/collardeau/from-data-to-delight-using-n8n-and-llms-to-automate-insightful-weather-updates-55m4</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnkpp82ckmnyw3bnyo4w3.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnkpp82ckmnyw3bnyo4w3.webp" alt="The Kairos automation: From data nodes to a sunny forecast, powered by n8n and LLMs." width="800" height="800"&gt;&lt;/a&gt;&lt;em&gt;The Kairos automation: From data nodes to a sunny forecast, powered by n8n and LLMs.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Throughout my exploration of automation’s vast potential, I’ve documented various experiences—from &lt;a href="https://medium.com/@collardeau/hands-free-ai-video-how-i-connected-google-sheets-and-luma-via-make-com-8cd1c435aa90" rel="noopener noreferrer"&gt;grappling with conditional JSON challenges in Make.com&lt;/a&gt; to uncovering more streamlined &lt;a href="https://medium.com/@collardeau/leveling-up-my-automation-game-when-visual-builders-led-me-to-n8ns-code-7d51e05de770" rel="noopener noreferrer"&gt;solutions with n8n’s Code Node during a Luma API integration&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Each project provided valuable insights, but my latest venture stands apart. Building Kairos, an &lt;strong&gt;AI-powered weather scout&lt;/strong&gt;, has vividly demonstrated how integrating robust automation tools with the advanced reasoning capabilities of Large Language Models (LLMs) can effectively address complex, real-world problems with remarkable efficiency.&lt;/p&gt;

&lt;p&gt;The initial idea was simple: find the best weather in Europe and tweet about it. But “best” is subjective, and sifting through forecasts for dozens of cities, each with multiple data points (temperature, conditions, precipitation probability over several days), to make a human-like judgment and then craft an engaging tweet? That’s not a trivial coding task. Traditionally, this would mean complex conditional logic, weighting systems, and perhaps even sentiment analysis libraries to get the tone right for a tweet.&lt;/p&gt;

&lt;p&gt;This is where the synergy of n8n and LLMs truly shines.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Challenge: Drowning in Data, Dreaming of Simplicity
&lt;/h3&gt;

&lt;p&gt;My n8n workflow diligently fetches detailed 5-day forecasts for 30 European cities from OpenWeatherMap. Using n8n’s Split Out and HTTP Request nodes, this part is fairly standard. Then, a Code Node steps in to transform and clean this data, stripping unnecessary fields, formatting values, and crucially, adding city names to each forecast. The result is a single, clean JSON object — an array where each element represents a city’s detailed weather report, all under a top-level fetch_date.&lt;/p&gt;

&lt;p&gt;Here’s a conceptual glimpse of what that data structure looks like before it heads to the AI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"fetch_date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"May 16, 2025"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"weather_reports"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"city_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Paris, FR"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"daily_forecast"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"day"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"temp_max"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"condition"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Sunny"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"precip_prob"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"day"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"temp_max"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"condition"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Clear"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"precip_prob"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;more&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;days&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"city_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Oslo, NO"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"daily_forecast"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"day"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"temp_max"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"condition"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Partly Cloudy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"precip_prob"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;more&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;days&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;points&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;28&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;more&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;cities&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

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

&lt;/div&gt;



&lt;p&gt;Now, imagine writing the code to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Parse this for 30 cities.&lt;/li&gt;
&lt;li&gt;Define what “best weather” means. Is it just warmest? What about “sunny but not too hot”? Or “surprisingly good for this time of year”?&lt;/li&gt;
&lt;li&gt;Compare all 30 cities based on these nuanced criteria.&lt;/li&gt;
&lt;li&gt;Select a single winner.&lt;/li&gt;
&lt;li&gt;Compose a tweet that sounds natural, engaging, and includes relevant details like temperature ranges and emojis.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The logic would be extensive and brittle.&lt;/p&gt;

&lt;h3&gt;
  
  
  The LLM Breakthrough: Outsourcing Complex Logic and Creativity
&lt;/h3&gt;

&lt;p&gt;Instead of coding that mountain of logic, I turned to an LLM (Gemini 2.5 Pro, accessed via n8n’s OpenAI node configured for OpenRouter). I fed it the entire JSON object of weather reports and, through careful prompt engineering, asked it to do the heavy lifting.&lt;/p&gt;

&lt;p&gt;My prompt instructed the LLM to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Act as Kairos, whose mission is to find appealing weather for spontaneous trips.&lt;/li&gt;
&lt;li&gt;Analyze all provided city forecasts.&lt;/li&gt;
&lt;li&gt;Identify the city with the overall “best weather in Europe,” considering factors like pleasant temperatures (e.g., 18–28°C), sunshine, and low precipitation.&lt;/li&gt;
&lt;li&gt;Crucially, give preference to cities experiencing “unusually pleasant” weather for their location/season (this was a key refinement for more interesting picks).&lt;/li&gt;
&lt;li&gt;Return its findings in a structured JSON format, including the chosen city, reasoning, and, importantly, a suggested_tweet.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result? The LLM not only intelligently analyzed the data — weighing multiple factors across numerous cities in a way that mimics human intuition — but it also drafted a ready-to-post tweet, complete with relevant emojis and a call to action.&lt;/p&gt;

&lt;p&gt;This ability to hand off complex data analysis and creative content generation to an LLM, simply by providing structured data and clear instructions, felt like a superpower. The hundreds, if not thousands, of lines of conventional code I might have written were replaced by a well-crafted prompt.&lt;/p&gt;

&lt;h3&gt;
  
  
  n8n: The Indispensable Orchestrator
&lt;/h3&gt;

&lt;p&gt;The LLM, powerful as it is, needs a robust platform to manage the overall workflow. Here’s how n8n played that crucial role:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Data Ingestion &amp;amp; Iteration&lt;/strong&gt;: Efficiently fetching data from OpenWeatherMap for each city using HTTP Request and Split Out nodes.
Data Preparation: The Code Node ensured the LLM received clean, well-structured JSON tailored for analysis.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI Integration&lt;/strong&gt;: The OpenAI node seamlessly handled the LLM call, abstracting the API complexities.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Action &amp;amp; Communication&lt;/strong&gt;: The X (Twitter) node took the LLM’s suggested_tweet and posted it, while the Gmail node sends me a confirmation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reliability &amp;amp; Scheduling&lt;/strong&gt;: n8n also handles scheduling the workflow to run twice a week and incorporates a separate error-handling workflow that emails me if anything goes amiss, ensuring robust operation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The platform’s visual interface allowed me to design the overall flow, while specific nodes like the Code Node and OpenAI node provided the power needed for the more intricate parts.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Learnings for an AI &amp;amp; Automation Toolkit:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;LLMs as Data Analysts&lt;/strong&gt;: LLMs can ingest large, structured datasets and extract nuanced insights based on natural language instructions, saving vast amounts of custom coding.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LLMs as Content Generators&lt;/strong&gt;: Beyond analysis, they can generate contextually relevant and stylistically appropriate content (like tweets) based on that analysis.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prompt Engineering is Key:&lt;/strong&gt; The quality of the LLM’s output is directly proportional to the clarity, specificity, and iterative refinement of the prompt. This is a skill in itself.
n8n + LLMs = A Power Duo: n8n provides the robust framework for data flow, service integration, scheduling, and error handling, while the LLM provides the “brain” for complex decision-making and generation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Future is Orchestration:&lt;/strong&gt; My role increasingly feels like an orchestrator of these powerful tools, designing the interaction points and guiding the AI, rather than coding every single logical step from scratch.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This Kairos project has been incredibly rewarding, not just for the functional automation it produced, but for the deeper understanding it gave me of how AI can be practically integrated into workflows to solve real-world problems in surprisingly elegant ways.&lt;/p&gt;

&lt;p&gt;You can see the results of this automation live on the &lt;a href="https://x.com/kairos_sun" rel="noopener noreferrer"&gt;@kairos_sun X (Twitter)&lt;/a&gt; account, which is now autonomously tweeting its weather picks. It’s a small demonstration, but for me, it represents a big step forward in leveraging AI within automation.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>automation</category>
      <category>n8n</category>
    </item>
    <item>
      <title>Leveling Up My Automation Game: When Visual Builders Led Me to n8n’s Code</title>
      <dc:creator>Thomas Collardeau</dc:creator>
      <pubDate>Thu, 05 Jun 2025 13:49:17 +0000</pubDate>
      <link>https://forem.com/collardeau/leveling-up-my-automation-game-when-visual-builders-led-me-to-n8ns-code-3g1o</link>
      <guid>https://forem.com/collardeau/leveling-up-my-automation-game-when-visual-builders-led-me-to-n8ns-code-3g1o</guid>
      <description>&lt;p&gt;A little while ago, I shared my journey &lt;a href="https://dev.tourl"&gt;building an automated workflow&lt;/a&gt; to generate AI videos with Luma Labs directly from a Google Sheet using Make.com. It was a success, but one piece of the puzzle — handling optional API inputs requiring specific JSON structures — necessitated a slightly cumbersome workaround involving Make.com’s Router module and duplicate steps.&lt;/p&gt;

&lt;p&gt;While functional, that Router-based solution felt like using a visual sledgehammer for a logic nut that needed cracking. It worked, but the repetition highlighted a limitation: sometimes, intricate conditional logic, especially when dealing with nested data structures for APIs, can become awkward in a purely visual builder. This itch — the feeling that there must be a cleaner way — prompted me to look at other automation tools.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9hqyot39ky107i41zffw.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9hqyot39ky107i41zffw.webp" alt="Simplifying visual workflows: Sometimes, a little code is the best eraser." width="800" height="800"&gt;&lt;/a&gt;&lt;em&gt;Simplifying visual workflows: Sometimes, a little code is the best eraser.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Exploring n8n: The Promise of Integrated Code
&lt;/h3&gt;

&lt;p&gt;n8n often came up in discussions about flexible automation, particularly its “Code Node” which allows running custom JavaScript directly within a workflow. Could this be the answer to the JSON construction challenge? I decided to find out by replicating my exact Luma API automation in n8n.&lt;/p&gt;

&lt;p&gt;Setting up the basic flow in n8n was straightforward. The real test came when it was time to dynamically create that tricky JSON payload for the Luma API — the part that had required the Router detour in Make.com. This time, I dropped in n8n’s Code Node.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Breakthrough: Solving Logic with Logic
&lt;/h3&gt;

&lt;p&gt;The difference was immediate. Instead of visual branching, I wrote a small JavaScript snippet. Using simple if statements, the code checked which input fields (like start or end image URLs) were present and built the exact JSON payload required by the Luma API for that specific combination, adding or omitting keys and nested objects as needed.&lt;/p&gt;

&lt;p&gt;This single Code Node, containing just a handful of logical JavaScript lines, cleanly replaced the Router and multiple duplicated HTTP modules I’d used in Make.com. It directly addressed the core challenge — conditional data structure generation — in a way that felt much more direct and maintainable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Visual vs. Code-Enhanced: Finding the Balance
&lt;/h3&gt;

&lt;p&gt;This experience was illuminating. Make.com’s visual approach is brilliant for connecting services and mapping data in many scenarios. But for that specific task, the rigid structure of the API’s conditional requirements was simply easier to express programmatically.&lt;/p&gt;

&lt;p&gt;n8n’s ability to seamlessly integrate these small code snippets within the visual flow provided the flexibility I needed. It wasn’t about abandoning visual building entirely, but about having the right tool — sometimes code — available for specific, tricky parts of the process. It felt like unlocking a new level in automation, combining the ease of visual flow design with the precision of code when necessary.&lt;/p&gt;

&lt;p&gt;This discovery has definitely shifted my perspective. Having experienced the power of code-enhanced automation, I’m eager to tackle more complex projects with n8n, knowing I have that extra layer of flexibility available when the drag-and-drop approach meets its limits. Sometimes, the path to a more elegant solution involves embracing a little bit of code.&lt;/p&gt;

</description>
      <category>automation</category>
      <category>lowcode</category>
      <category>n8n</category>
    </item>
    <item>
      <title>Hands-Free AI Video: How I Connected Google Sheets and Luma via Make.com</title>
      <dc:creator>Thomas Collardeau</dc:creator>
      <pubDate>Mon, 02 Jun 2025 11:34:17 +0000</pubDate>
      <link>https://forem.com/collardeau/hands-free-ai-video-how-i-connected-google-sheets-and-luma-via-makecom-35c9</link>
      <guid>https://forem.com/collardeau/hands-free-ai-video-how-i-connected-google-sheets-and-luma-via-makecom-35c9</guid>
      <description>&lt;p&gt;The rise of AI video generation tools like Luma Labs is incredibly exciting, opening up new possibilities for creators. However, manually generating clips, especially for ongoing projects, can quickly become time-consuming. As part of refining my automated workflows, I set out to build a system that could trigger Luma video generations directly from a simple Google Sheet, using Make.com as the automation platform. The goal? A truly "hands-free" video pipeline.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Dream Workflow
&lt;/h2&gt;

&lt;p&gt;The plan seemed straightforward enough:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Add details for a new video job (like prompts, image URLs, settings) to a row in a Google Sheet and mark its status as "Ready".&lt;/li&gt;
&lt;li&gt; Have Make.com detect this "Ready" row.&lt;/li&gt;
&lt;li&gt; Make.com calls the Luma Labs API with the details from the sheet.&lt;/li&gt;
&lt;li&gt; Luma does its magic and generates the video.&lt;/li&gt;
&lt;li&gt; Luma sends a notification (webhook) back to Make.com when the job is complete.&lt;/li&gt;
&lt;li&gt; Make.com receives this notification, grabs the video URL, and updates the original Google Sheet row with the URL and a "Completed" status. (Optionally, it could also save the video file to cloud storage like Dropbox).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This setup would allow me to queue up multiple video jobs just by filling out a spreadsheet – pretty neat!&lt;/p&gt;

&lt;h2&gt;
  
  
  The API Curveball: Handling Optional Inputs
&lt;/h2&gt;

&lt;p&gt;Connecting Google Sheets and setting up the basic Make.com scenarios (one to "Call" Luma, one to "Receive" the callback) went smoothly. However, I soon hit an unexpected hurdle when constructing the actual API request to Luma.&lt;/p&gt;

&lt;p&gt;The Luma API allows for generating video from a text prompt, a starting image (&lt;code&gt;frame0&lt;/code&gt;), an ending image (&lt;code&gt;frame1&lt;/code&gt;), or both images. These image inputs are nested within a &lt;code&gt;keyframes&lt;/code&gt; object in the JSON payload sent to the API.&lt;/p&gt;

&lt;p&gt;The challenge? If you only provide one image (or none), the API doesn't just want an empty string for the missing image URL. It requires the entire key for the missing frame (e.g., &lt;code&gt;"frame1": {...}&lt;/code&gt;) or potentially even the parent &lt;code&gt;keyframes&lt;/code&gt; object itself to be completely omitted from the JSON request. Sending incorrect structures, like &lt;code&gt;frame1: {}&lt;/code&gt; or &lt;code&gt;frame1: { "url": "" }&lt;/code&gt;, results in an error. This kind of strictness is fairly common with APIs, requiring careful payload construction.&lt;/p&gt;

&lt;h2&gt;
  
  
  Navigating Make.com's Visual Logic
&lt;/h2&gt;

&lt;p&gt;My first instinct was to use Make.com's built-in functions. Functions like &lt;code&gt;ifempty(variable, ignore)&lt;/code&gt; worked perfectly for top-level optional fields, like the main text prompt. If the prompt cell in my Google Sheet was empty, &lt;code&gt;ignore&lt;/code&gt; would correctly remove the &lt;code&gt;prompt&lt;/code&gt; key from the final JSON.&lt;/p&gt;

&lt;p&gt;However, applying this logic to nested objects like &lt;code&gt;frame0&lt;/code&gt; or &lt;code&gt;frame1&lt;/code&gt; within &lt;code&gt;keyframes&lt;/code&gt; proved trickier within the visual interface. Trying to ignore just the &lt;code&gt;url&lt;/code&gt; inside &lt;code&gt;frame0&lt;/code&gt; would leave an empty &lt;code&gt;frame0: {}&lt;/code&gt; object, which the API rejected. I needed a way to conditionally remove the entire &lt;code&gt;frame0&lt;/code&gt; or &lt;code&gt;frame1&lt;/code&gt; object, or the &lt;code&gt;keyframes&lt;/code&gt; object altogether, based on the input data from the Google Sheet.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Router Workaround
&lt;/h2&gt;

&lt;p&gt;After some experimentation, the most reliable solution within Make.com's visual builder involved using the &lt;code&gt;Router&lt;/code&gt; module. Here’s how it works in my "Luma Caller" scenario:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; The scenario triggers and finds "Ready" rows in Google Sheets.&lt;/li&gt;
&lt;li&gt; It iterates through each job.&lt;/li&gt;
&lt;li&gt; Initial Validation: A first router checks if essential data (like model, aspect ratio) is present.&lt;/li&gt;
&lt;li&gt; Status Update: The Google Sheet row is updated to "Processing".&lt;/li&gt;
&lt;li&gt; The Core Logic (Router): A second &lt;code&gt;Router&lt;/code&gt; module checks the input columns for the &lt;code&gt;First Frame (C)&lt;/code&gt; and &lt;code&gt;Last Frame (D)&lt;/code&gt; image URLs from the Google Sheet.&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Path 1: If only &lt;code&gt;First Frame (C)&lt;/code&gt; has a URL, it proceeds down a path with an HTTP module configured only with the JSON structure for &lt;code&gt;frame0&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Path 2: If only &lt;code&gt;Last Frame (D)&lt;/code&gt; has a URL, it uses a different HTTP module configured only for &lt;code&gt;frame1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Path 3 (Fallback): If both &lt;code&gt;C&lt;/code&gt; and &lt;code&gt;D&lt;/code&gt; have URLs, it uses a third HTTP module configured for both &lt;code&gt;frame0&lt;/code&gt; and &lt;code&gt;frame1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;API Call &amp;amp; Update: The appropriate HTTP module calls the Luma API. On success, another Google Sheets module updates the row to "Generating" and stores the Luma Job ID.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's a look at that part of the Make.com scenario:&lt;/p&gt;

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

&lt;p&gt;&lt;em&gt;The Make.com 'Luma Caller' scenario flow. The crucial Router module branches the process based on input data (presence of first/last image frames), sending the job to one of three dedicated HTTP modules configured with the correct Luma API payload structure.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A separate "Luma Receiver" scenario listens for the webhook callback from Luma, filters for the "completed" status message, finds the matching row in the Google Sheet using the Job ID, and updates the status to "Completed", pasting in the final video URL.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reflections and What's Next
&lt;/h2&gt;

&lt;p&gt;This Router-based solution works reliably and achieves the goal: I can now trigger Luma video generations simply by adding rows to a Google Sheet. It's a functional hands-free pipeline!&lt;/p&gt;

&lt;p&gt;From a Make.com perspective, the solution feels a bit repetitive, requiring separate, almost identical HTTP modules for each conditional path. I was genuinely surprised I couldn't find a more direct visual method to dynamically build or omit those nested JSON structures based on input variables. It works well, though I do wonder if the Make.com community has found more streamlined visual methods for handling such conditional nested structures.&lt;/p&gt;

&lt;p&gt;This project was a valuable practical exercise, deepening my understanding of Make.com's capabilities, the practicalities of API integration, and the importance of carefully handling API requirements. It also highlighted the trade-offs between visual builders and code. For future projects involving more complex conditional logic, exploring platforms like n8n, which often integrate code modules more directly, might be worth comparing.&lt;/p&gt;

&lt;p&gt;For now, I have a working automation that saves significant time and effort, demonstrating the practical power of tools like Make.com for streamlining creative and technical workflows.&lt;/p&gt;

</description>
      <category>automation</category>
      <category>makecom</category>
      <category>api</category>
      <category>ai</category>
    </item>
    <item>
      <title>Lazy Loading Images in Svelte</title>
      <dc:creator>Thomas Collardeau</dc:creator>
      <pubDate>Wed, 20 Nov 2019 13:34:38 +0000</pubDate>
      <link>https://forem.com/collardeau/lazy-loading-images-in-svelte-1mk6</link>
      <guid>https://forem.com/collardeau/lazy-loading-images-in-svelte-1mk6</guid>
      <description>&lt;p&gt;Let's imagine we have ourselves a little web app that displays a &lt;strong&gt;column of images&lt;/strong&gt; (of kittens, of course).&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/lazy-loading-1-lt539"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;We open the code and see that we have 3 friendly &lt;a href="https://svelte.dev" rel="noopener noreferrer"&gt;Svelte&lt;/a&gt; components greeting us. Let's take a look at each one in turn:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;App.svelte&lt;/code&gt; sets some basic styles and renders a &lt;code&gt;List&lt;/code&gt; component. We won't be editing this file but here it is for clarity:
&lt;/li&gt;
&lt;/ul&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;script&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;List&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./List.svelte&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;main&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;300px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;text-align&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;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;main&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Kittens&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;List&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/main&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;List.svelte&lt;/code&gt; generates a list of images (such as &lt;code&gt;https://placekitten.com/g/300/500?image=01&lt;/code&gt;) and renders a &lt;code&gt;ListItem&lt;/code&gt; component for each of them:
&lt;/li&gt;
&lt;/ul&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;script&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;ListItem&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./ListItem.svelte&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// generate image data:&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;prefix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://placekitten.com/g/300/500?image=&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;items&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="s2"&gt;01&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="s2"&gt;02&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="s2"&gt;03&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="s2"&gt;04&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="s2"&gt;05&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;prefix&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

{#each items as item}
  &lt;span class="nt"&gt;&amp;lt;ListItem&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;&lt;span class="na"&gt;item&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
{/each}

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

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ListItem.svelte&lt;/code&gt; is in charge of rendering an individual image inside an article tag:
&lt;/li&gt;
&lt;/ul&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;script&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;src&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="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;article&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;300px&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;500px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;margin-bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.5rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;article&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;&lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;'kitten'&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/article&amp;gt;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;So we're loading and rendering a few images that are 300 pixels wide and 500 pixels tall from &lt;a href="https://placekitten.com" rel="noopener noreferrer"&gt;placekitten.com&lt;/a&gt;. Nice and easy.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Issue At Hand
&lt;/h3&gt;

&lt;p&gt;Most of the images (each being 500px tall) are naturally &lt;strong&gt;off screen&lt;/strong&gt; when the user lands on the page. They might never scroll down to see all our awesome content below the fold. So they're downloading &lt;strong&gt;data for nothing&lt;/strong&gt; on initial load, and slowing down their experience.&lt;/p&gt;

&lt;p&gt;Even if they do scroll all the way down, it would be nice to load the images only when they are about to enter the viewport and &lt;strong&gt;lighten the initial load&lt;/strong&gt;. We can improve the user's experience and serve fewer images on our end. Win-win. &lt;/p&gt;

&lt;h1&gt;
  
  
  When Lazy is Good
&lt;/h1&gt;

&lt;p&gt;So let's &lt;strong&gt;lazy load our images&lt;/strong&gt;! But not the first 2, we want to fetch those right away, and then load the rest as we scroll down.&lt;/p&gt;

&lt;p&gt;First, let's have our &lt;code&gt;List&lt;/code&gt; component pass down a &lt;code&gt;lazy&lt;/code&gt; prop to &lt;code&gt;ListItem&lt;/code&gt;, which will be &lt;code&gt;true&lt;/code&gt; starting from the third image. When it's &lt;code&gt;true&lt;/code&gt;, &lt;code&gt;ListItem&lt;/code&gt; will &lt;strong&gt;set src to an empty string&lt;/strong&gt; so that &lt;em&gt;no&lt;/em&gt; image is requested at first.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;List.svelte&lt;/code&gt;, we pass down a new &lt;code&gt;lazy&lt;/code&gt; prop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;{#each items as item, i}
  &lt;span class="nt"&gt;&amp;lt;ListItem&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;&lt;span class="na"&gt;item&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;lazy=&lt;/span&gt;&lt;span class="s"&gt;{i&lt;/span&gt; &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; 1} /&amp;gt;
{/each}

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

&lt;/div&gt;



&lt;p&gt;In &lt;code&gt;ListItem.svelte&lt;/code&gt;, we set the image &lt;code&gt;src&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;lazy&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;lazy&lt;/span&gt; &lt;span class="p"&gt;?&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, at this stage, we're loading the first two images but the rest is never loading. How shall we trigger this effect?&lt;/p&gt;

&lt;h3&gt;
  
  
  Intersection Observer
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API" rel="noopener noreferrer"&gt;Intersection Observer&lt;/a&gt; is a web API that allows us to know when an element is intersecting (or about to intersect) with the viewport. It's got solid &lt;a href="https://caniuse.com/#feat=intersectionobserver" rel="noopener noreferrer"&gt;browser support&lt;/a&gt; (it's just not available in IE11).&lt;/p&gt;

&lt;p&gt;How does it work? We &lt;strong&gt;create an observer&lt;/strong&gt; using &lt;code&gt;IntersectionObserver&lt;/code&gt; and give it a function that will run when a DOM node that we've registered is intersecting with the viewport.&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;observer&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;IntersectionObserver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;onIntersect&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;onIntersect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
  &lt;span class="c1"&gt;// todo: update relevant img src&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 observe (and unobserve) a node using a &lt;a href="https://svelte.dev/docs#use_action" rel="noopener noreferrer"&gt;Svelte action&lt;/a&gt;:&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;script&amp;gt;&lt;/span&gt;
  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;lazyLoad&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;observe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&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="nf"&gt;destroy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="nx"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unobserve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&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="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;article&lt;/span&gt; &lt;span class="na"&gt;use:lazyLoad&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- img --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/article&amp;gt;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Putting it together our &lt;code&gt;ListItem.svelte&lt;/code&gt; looks like this (minus the styles which haven't changed):&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;script&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;lazy&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="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;src&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="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;observer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&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;lazy&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;observer&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;IntersectionObserver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;onIntersect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;rootMargin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;200px&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;function&lt;/span&gt; &lt;span class="nf"&gt;onIntersect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entries&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;src&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;entries&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="nx"&gt;isIntersecting&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;src&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="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;lazyLoad&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;observer&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;observe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&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="nf"&gt;destroy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;observer&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unobserve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&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="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;article&lt;/span&gt; &lt;span class="na"&gt;use:lazyLoad&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;&lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;'kitten'&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/article&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the &lt;code&gt;lazy&lt;/code&gt; prop is passed in as &lt;code&gt;true&lt;/code&gt;, we immediately set the &lt;code&gt;src&lt;/code&gt; to empty string and create an &lt;code&gt;observer&lt;/code&gt;. We add a &lt;code&gt;rootMargin&lt;/code&gt; option so that the &lt;code&gt;onIntersect&lt;/code&gt; function is triggered 200 pixels before the element comes into view. In &lt;code&gt;lazyLoad&lt;/code&gt;, we register the article node that we want to watch.&lt;/p&gt;

&lt;p&gt;Effectively, we are creating an observer with a &lt;strong&gt;single&lt;/strong&gt; node for each &lt;code&gt;ListItem&lt;/code&gt;, so we can check if that node (&lt;code&gt;entries[0]&lt;/code&gt;) is in fact intersecting in our &lt;code&gt;OnIntersect&lt;/code&gt; function and set &lt;code&gt;src = item&lt;/code&gt; which will request the image.&lt;/p&gt;

&lt;p&gt;And just like that, we're lazy loading our images! We can see in the devtools that we are &lt;em&gt;not&lt;/em&gt; requesting all images upfront, as illustrated in this GIF:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/http%3A%2F%2Fg.recordit.co%2F4IL2u8eZiE.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/http%3A%2F%2Fg.recordit.co%2F4IL2u8eZiE.gif" alt="lazy load demo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Last thing, Let's make sure our app doesn't blow up if &lt;code&gt;intersectionObserver&lt;/code&gt; isn't available (IE11) by adding a &lt;code&gt;hasAPI&lt;/code&gt; check in &lt;code&gt;List.svelte&lt;/code&gt;&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;script&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;ListItem&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./ListItem.svelte&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;prefix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://placekitten.com/g/300/500?image=&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;items&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="s2"&gt;01&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="s2"&gt;02&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="s2"&gt;03&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="s2"&gt;04&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="s2"&gt;05&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;prefix&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;img&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;hasAPI&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;IntersectionObserver&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// new&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;


{#each items as item, i}
  &lt;span class="nt"&gt;&amp;lt;ListItem&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;&lt;span class="na"&gt;item&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="na"&gt;lazy=&lt;/span&gt;&lt;span class="s"&gt;{hasAPI&lt;/span&gt; &lt;span class="err"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="na"&gt;i&lt;/span&gt; &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; 1} /&amp;gt;
{/each}

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

&lt;/div&gt;



&lt;p&gt;Here is the updated sandbox shall you want to tinker with this code:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/lazy-loading-2-g6gcm"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;This is a technique I recently implemented for a painter's portfolio website that I built using &lt;a href="https://sapper.svelte.dev/" rel="noopener noreferrer"&gt;Sapper&lt;/a&gt;. You can see it at &lt;a href="https://john-hong-studio.com" rel="noopener noreferrer"&gt;https://john-hong-studio.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thanks for reading! Don't hesitate to leave a comment or connect with me on &lt;a href="https://twitter.com/collardeau" rel="noopener noreferrer"&gt;twitter&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>svelte</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>html</category>
    </item>
    <item>
      <title>Props up with Svelte</title>
      <dc:creator>Thomas Collardeau</dc:creator>
      <pubDate>Mon, 07 Oct 2019 17:19:06 +0000</pubDate>
      <link>https://forem.com/collardeau/props-up-with-svelte-4cjk</link>
      <guid>https://forem.com/collardeau/props-up-with-svelte-4cjk</guid>
      <description>&lt;h2&gt;
  
  
  Passing props down (React)
&lt;/h2&gt;

&lt;p&gt;Let's present the paradigm by creating a small &lt;strong&gt;Counter&lt;/strong&gt; component in &lt;a href="https://reactjs.org/"&gt;React&lt;/a&gt; first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;Counter&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="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;incr&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;setCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;c&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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;incr&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;+1&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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



&lt;p&gt;And let's use it an &lt;strong&gt;App&lt;/strong&gt; component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./Counter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;App&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Counter&lt;/span&gt; &lt;span class="o"&gt;/&amp;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;Now, let us imagine that we need to know &lt;strong&gt;if the count is more than 1&lt;/strong&gt; in our &lt;code&gt;App&lt;/code&gt; component (maybe we need to pluralize a string if that's the case).&lt;/p&gt;

&lt;p&gt;Mmh... we don't have access to &lt;code&gt;count&lt;/code&gt; from &lt;code&gt;App&lt;/code&gt;. We have to &lt;a href="https://reactjs.org/docs/lifting-state-up.html"&gt;lift the state up&lt;/a&gt; and pass it back down as a prop to &lt;code&gt;&amp;lt;Counter /&amp;gt;&lt;/code&gt;. As a result, we also need to pass down the increment function to update said &lt;code&gt;count&lt;/code&gt;. Here is an implementation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&gt;
&lt;span class="c1"&gt;// App.js&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Counter&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;./Counter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// state is now in the parent&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;incr&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;setCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;c&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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Counter&lt;/span&gt; &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;incr&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;incr&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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





&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&gt;
&lt;span class="c1"&gt;// Counter.js&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;Counter&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="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// the child uses props&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;incr&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;props&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;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;incr&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;+1&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;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;Nice, it works (&lt;a href="https://codesandbox.io/embed/lifting-state-up-mynfw"&gt;sandbox&lt;/a&gt;). Yet it's slightly odd to me that our &lt;code&gt;Counter&lt;/code&gt;component has become a shell of itself (it seems). It doesn't do any counting anymore. It wires in a click handler. Maybe we'd have to rename it? But I digress.&lt;/p&gt;

&lt;h2&gt;
  
  
  Component Bindings (Svelte)
&lt;/h2&gt;

&lt;p&gt;Let's try to handle the same issue in &lt;a href="https://svelte.dev/"&gt;Svelte&lt;/a&gt;. Here is our &lt;code&gt;Counter&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&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;incr&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="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;count&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="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;{count}&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;on:click=&lt;/span&gt;&lt;span class="s"&gt;{incr}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;+1&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;

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



&lt;p&gt;And a parent component, &lt;code&gt;App&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
   &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Counter&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;./Counter.svelte&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;Counter&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;So we're back in the same situation: we want to use &lt;code&gt;count&lt;/code&gt; from &lt;code&gt;Counter&lt;/code&gt; in the &lt;code&gt;App&lt;/code&gt; component. We &lt;em&gt;could&lt;/em&gt; lift state up again as before. But this time, we can actually &lt;strong&gt;pass props up&lt;/strong&gt; without having to re-wire any state. We need to:&lt;/p&gt;

&lt;p&gt;1/ &lt;code&gt;export&lt;/code&gt; the variable in the &lt;code&gt;Counter&lt;/code&gt; (child) component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;2/ bind to the component value in the &lt;code&gt;App&lt;/code&gt; (parent) component&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nt"&gt;Counter&lt;/span&gt; &lt;span class="na"&gt;bind:count&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We declare the variable in the &lt;code&gt;script&lt;/code&gt; tag, and we grab it via &lt;a href="https://svelte.dev/examples#component-bindings"&gt;component bindings&lt;/a&gt; (&lt;code&gt;bind:count&lt;/code&gt;). So, we have access to the count in the parent component! Let's actually solve the problem in full, using &lt;a href="https://svelte.dev/docs#3_%24_marks_a_statement_as_reactive"&gt;reactive declarations&lt;/a&gt; as well.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;App.svelte&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Counter&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;./Counter.svelte&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;isMoreThan1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;Counter&lt;/span&gt; &lt;span class="na"&gt;bind:count&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;is More than 1: {isMoreThan1} &lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;

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



&lt;p&gt;&lt;code&gt;Counter.svelte&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&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;incr&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="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;count&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="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;{count}&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;on:click=&lt;/span&gt;&lt;span class="s"&gt;{incr}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  +1
&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;

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



&lt;p&gt;&lt;a href="https://svelte.dev/repl/b4a321999c7a4894ac04aa325bfed2c0?version=3.12.1"&gt;View it in the REPL&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I'm interested in your thoughts. What do you think are the repercussion for componentization in Svelte coming from React? Is there a similar mechanism in Vue or Angular? &lt;/p&gt;

&lt;p&gt;Give me a follow &lt;a href="https://twitter.com/collardeau"&gt;on Twitter&lt;/a&gt; for more explorations with Svelte :)&lt;/p&gt;

</description>
      <category>svelte</category>
      <category>react</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Building a Headroom-Style Header in Svelte</title>
      <dc:creator>Thomas Collardeau</dc:creator>
      <pubDate>Wed, 02 Oct 2019 19:51:13 +0000</pubDate>
      <link>https://forem.com/collardeau/building-a-headroom-style-header-in-svelte-e12</link>
      <guid>https://forem.com/collardeau/building-a-headroom-style-header-in-svelte-e12</guid>
      <description>&lt;p&gt;Let us build a &lt;strong&gt;headroom-style header&lt;/strong&gt; in &lt;a href="https://svelte.dev"&gt;Svelte&lt;/a&gt;! Our objective in this blog post is to create a header that slides up (and out-of-view) when the user scrolls down, and re-appears when they scroll up (no matter how far down the page they are).&lt;/p&gt;

&lt;p&gt;This is a technique used to &lt;strong&gt;save room on the screen&lt;/strong&gt; while sparing the user from having to scroll all the way back up the page to get to the header and navigation.&lt;/p&gt;

&lt;p&gt;We won't use the popular &lt;a href="https://wicky.nillia.ms/headroom.js"&gt;headroom.js&lt;/a&gt; but roll up a our own simple solution while honing our Svelte skills along the way. Are you ready?&lt;/p&gt;

&lt;h1&gt;
  
  
  The Layout
&lt;/h1&gt;

&lt;p&gt;We'll begin with a component that has a &lt;code&gt;fixed&lt;/code&gt; header as if it was already "pinned". Let's give our header a &lt;code&gt;height&lt;/code&gt; and &lt;code&gt;background-color&lt;/code&gt; so we can actually see it. Our Svelte component sees the light of day:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
 &lt;span class="nt"&gt;header&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="n"&gt;darkgrey&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;80px&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;fixed&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="nt"&gt;main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;min-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;150vh&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;padding-top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;header&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;main&amp;gt;&lt;/span&gt;Lorem ipsum&lt;span class="nt"&gt;&amp;lt;/main&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You can see that we're giving our &lt;code&gt;main&lt;/code&gt; tag a &lt;code&gt;padding-top&lt;/code&gt; equal to the &lt;code&gt;height&lt;/code&gt; of the header otherwise the header (being &lt;code&gt;fixed&lt;/code&gt;) would cover the top of &lt;code&gt;main&lt;/code&gt;. We're also giving &lt;code&gt;main&lt;/code&gt; some &lt;code&gt;min-height&lt;/code&gt; so we can be sure that we're able to scroll up and down and test our component manually.&lt;/p&gt;

&lt;p&gt;As it stands, we've created a fixed header that stays put as you scroll down. &lt;a href="https://www.youtube.com/watch?v=Mg5HOnq7zD0"&gt;Not great, not terrible&lt;/a&gt;. Here is our &lt;strong&gt;starting point&lt;/strong&gt; in a code sandbox:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/svelte-header-1-eexq8?module=/App.svelte"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h1&gt;
  
  
  The Plan: Pin or Unpin
&lt;/h1&gt;

&lt;p&gt;In order to hide or show the &lt;code&gt;header&lt;/code&gt;, we shall target it with a conditional class so that we can joyfully control its CSS. One class will serve to &lt;strong&gt;pin&lt;/strong&gt; the header by setting the &lt;code&gt;top&lt;/code&gt; property to &lt;code&gt;0&lt;/code&gt;, and the other will bravely &lt;strong&gt;unpin&lt;/strong&gt; it by setting &lt;code&gt;top&lt;/code&gt; to &lt;code&gt;-80px&lt;/code&gt;, which will hide it out of view (based on its own height of 80px). &lt;/p&gt;

&lt;p&gt;Let's add a &lt;strong&gt;transition&lt;/strong&gt; on &lt;code&gt;header&lt;/code&gt; while we're dealing with the CSS so any change will occur over 0.3 second instead of being instantaneous and jarring and, quite frankly, unusable. I dutifully propose this extra bit of CSS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight css"&gt;&lt;code&gt; &lt;span class="nt"&gt;header&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;/* ... existing properties */&lt;/span&gt;
    &lt;span class="nl"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;all&lt;/span&gt; &lt;span class="m"&gt;0.3s&lt;/span&gt; &lt;span class="n"&gt;linear&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="nc"&gt;.pin&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nc"&gt;.unpin&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;-80px&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;It will be up to us to &lt;strong&gt;add and remove the appropriate class in response to the user actively scrolling&lt;/strong&gt;. Fingers crossed, everybody.&lt;/p&gt;

&lt;h1&gt;
  
  
  Using Svelte State
&lt;/h1&gt;

&lt;p&gt;Let's create some state to hold the value of a &lt;code&gt;headerClass&lt;/code&gt; that we can then refer to in the HTML. Well, &lt;strong&gt;state is simply a JavaScript assignment&lt;/strong&gt; in Svelte! Let's give our header a starting class of &lt;code&gt;pin&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;headerClass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;header&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;{headerClass}&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

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



&lt;p&gt;Gotta love it. A simple re-assignment like &lt;code&gt;headerClass = "whatever"&lt;/code&gt; will update our view. We'll do that in just a moment. But let's get our bearings and take stock of our &lt;em&gt;entire&lt;/em&gt; component as it stands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;headerClass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
 &lt;span class="nt"&gt;header&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="n"&gt;darkgrey&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;80px&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;fixed&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;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;all&lt;/span&gt; &lt;span class="m"&gt;0.3s&lt;/span&gt; &lt;span class="n"&gt;linear&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nt"&gt;main&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;150vh&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;padding-top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="nc"&gt;.pin&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nc"&gt;.unpin&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;-80px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;header&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;{headerClass}&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;main&amp;gt;&lt;/span&gt;Lorem ipsum&lt;span class="nt"&gt;&amp;lt;/main&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Our code is taking shape but everything is the same visually: still a boring old fixed header. Clearly, we have to react in some way to the user actively scrolling (and eventually update &lt;code&gt;headerClass&lt;/code&gt;)!&lt;/p&gt;

&lt;h1&gt;
  
  
  Scrolling Detection
&lt;/h1&gt;

&lt;p&gt;How do we detect vertical scrolling in the first place?&lt;/p&gt;

&lt;p&gt;Well... there &lt;em&gt;is&lt;/em&gt; a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Document/scroll_event"&gt;scroll event&lt;/a&gt; listener on &lt;code&gt;window&lt;/code&gt; and we can read the vertical scroll position at any time from &lt;code&gt;window.scrollY&lt;/code&gt;. So we &lt;em&gt;could&lt;/em&gt; wire up something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// meh&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;scroll&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;scroll_position&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;scrollY&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="c1"&gt;// figure out class name&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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



&lt;p&gt;We would have to do this when the component mounts and remember to remove the listener when the component is destroyed. Certainly, it's a possibility.&lt;/p&gt;

&lt;p&gt;However, we can do less typing in Svelte: we can use the &lt;a href="https://svelte.dev/docs#svelte_window"&gt;&lt;code&gt;&amp;lt;svelte:window&amp;gt;&lt;/code&gt;&lt;/a&gt; element and even bind to the &lt;code&gt;window.scrollY&lt;/code&gt; position so it's available to us as it's changing. In code, it looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
   &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;svelte:window&lt;/span&gt; &lt;span class="na"&gt;bind:scrollY=&lt;/span&gt;&lt;span class="s"&gt;{y}/&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;{ y }&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The above code is a valid component. The value of &lt;code&gt;y&lt;/code&gt; in the &lt;code&gt;span&lt;/code&gt; will change as you scroll up and down the page (&lt;a href="https://codesandbox.io/embed/svelte-scrolly-binding-fh5il"&gt;try it in a sandbox&lt;/a&gt;). Furthermore, we don't have to worry about removing the listener when using &lt;code&gt;svelte:window&lt;/code&gt;, nor worry about checking if &lt;code&gt;window&lt;/code&gt; even exists (shall the code be ran server-side). Well, that's pretty cool!&lt;/p&gt;

&lt;h1&gt;
  
  
  Reactive Declarations
&lt;/h1&gt;

&lt;p&gt;So we have our scroll position &lt;code&gt;y&lt;/code&gt; over time. From this stream of data, we can derive our class name. But how shall we even store a new value every time &lt;code&gt;y&lt;/code&gt; changes? Svelte offers &lt;strong&gt;reactive declarations&lt;/strong&gt; with the &lt;code&gt;$:&lt;/code&gt; syntax. Check out this introductory example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;count&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="nl"&gt;$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;double&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&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;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;
  { double }
&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;span&lt;/code&gt; will hold a value of 4 as soon as we've re-assigned &lt;code&gt;count&lt;/code&gt; to &lt;code&gt;2&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;In our case, we want &lt;code&gt;headerClass&lt;/code&gt; to be reactive to the &lt;code&gt;y&lt;/code&gt; position. We'll move our logic in a function of its own, much like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
   &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;headerClass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
   &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;changeClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;y&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 stuff&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="nl"&gt;$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;headerClass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;changeClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In short, we can update the &lt;code&gt;class&lt;/code&gt; of the &lt;code&gt;header&lt;/code&gt; whenever the scroll position &lt;code&gt;y&lt;/code&gt; changes. Well, it seems we are getting closer to our objective!&lt;/p&gt;

&lt;h1&gt;
  
  
  What Class Name?
&lt;/h1&gt;

&lt;p&gt;So we must focus on this newly introduced &lt;code&gt;changeClass&lt;/code&gt; function which is in fact &lt;strong&gt;the last bit of implementation&lt;/strong&gt;. It should return a string,'"pin"' or '"unpin"', and then our CSS can swing (actually, slide) into action. &lt;/p&gt;

&lt;h3&gt;
  
  
  Base Case
&lt;/h3&gt;

&lt;p&gt;If the scroll direction doesn't change, for example if the user was scrolling down and is still scrolling down, we don't need to do anything at all but return the class name as it was. Let's make that our default case:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;headerClass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;changeClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;headerClass&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="c1"&gt;// todo: change result as needed&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;So that's our base case taken care of. But the function should return &lt;strong&gt;'pin'&lt;/strong&gt; if the user starts scrolling up, and &lt;strong&gt;'unpin'&lt;/strong&gt; if they start scrolling down. We're jumping a bit ahead of ourselves because right now we don't even know which way the user is scrolling; we only have a stream of &lt;code&gt;y&lt;/code&gt; positions, so let's figure that out. &lt;/p&gt;

&lt;h3&gt;
  
  
  Scroll Direction
&lt;/h3&gt;

&lt;p&gt;We need to compare the last &lt;code&gt;y&lt;/code&gt; position to the one we're currently holding to know the distance that was scrolled in pixels. So we need to store some &lt;code&gt;lastY&lt;/code&gt; at the end of each scroll cycle, then the next scroll event can use it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;headerClass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;lastY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

   &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;changeClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;headerClass&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="c1"&gt;// do stuff, then&lt;/span&gt;
      &lt;span class="c1"&gt;// just before returning the result:&lt;/span&gt;
      &lt;span class="nx"&gt;lastY&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;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&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 we have a &lt;code&gt;lastY&lt;/code&gt; to work with so let's get our scroll direction with it. If &lt;code&gt;lastY - y&lt;/code&gt; is positive the user is scrolling down, else they're scrolling up.&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;headerClass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;lastY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

   &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;changeClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;headerClass&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="c1"&gt;// new:&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;scrolledPxs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;lastY&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;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;scrollDirection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;scrolledPxs&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;down&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="s2"&gt;up&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="c1"&gt;// todo: did the direction change?&lt;/span&gt;
      &lt;span class="nx"&gt;lastY&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;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&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 determine if the scrolling direction changed, we can compare it to the last scroll direction, much like we did for &lt;code&gt;lastY&lt;/code&gt; in fact. We'll initialize it to &lt;code&gt;"up"&lt;/code&gt; so we can trigger our effect (hiding the header) on the initial scroll down.&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;headerClass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;lastY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;lastDirection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;up&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// new&lt;/span&gt;

   &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;changeClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;headerClass&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;scrollPxs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;lastY&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;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;scrollDirection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;scrolledPxs&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;down&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="s2"&gt;up&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="c1"&gt;// new:&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;changedDirection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;scrollDirection&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;lastDirection&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="c1"&gt;// todo: change result if the direction has changed&lt;/span&gt;
      &lt;span class="nx"&gt;lastDirection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;scrollDirection&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;lastY&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;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&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;
  
  
  The Right Class
&lt;/h3&gt;

&lt;p&gt;If my calculations are correct, there is only one step left: to re-assign &lt;code&gt;result&lt;/code&gt; when the scrolling has actually changed direction, which we now know.&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;headerClass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;lastY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;lastDirection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;up&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

   &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;changeClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;headerClass&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;scrollPxs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;lastY&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;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;scrollDirection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;scrolledPxs&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;down&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="s2"&gt;up&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;changedDirection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;scrollDirection&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;lastDirection&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;changedDirection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// new&lt;/span&gt;
        &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;scrollDirection&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;down&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;pin&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;unpin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;lastDirection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;scrollDirection&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;lastY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And that does trick! Thanks to our conditional class on &lt;code&gt;header&lt;/code&gt; and our CSS, we find ourselves with a headroom-style header!&lt;/p&gt;

&lt;h1&gt;
  
  
  The Whole Thing
&lt;/h1&gt;

&lt;p&gt;Let's see the whole Svelte component, shall we? Let's treat ourselves to a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties"&gt;CSS Variable&lt;/a&gt; so we don't have that hard-coded &lt;code&gt;80px&lt;/code&gt; header height in multiple places.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;headerClass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;lastY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;lastDirection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;up&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;changeClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;headerClass&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;scrolledPxs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;lastY&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;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;scrollDirection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;scrolledPxs&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;down&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="s2"&gt;up&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;changedDirection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;scrollDirection&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;lastDirection&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;changedDirection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;scrollDirection&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;down&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="s2"&gt;unpin&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="s2"&gt;pin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;lastDirection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;scrollDirection&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;lastY&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;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nl"&gt;$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;headerClass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;changeClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;svelte:window&lt;/span&gt; &lt;span class="na"&gt;bind:scrollY=&lt;/span&gt;&lt;span class="s"&gt;{y}/&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
  &lt;span class="nd"&gt;:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="py"&gt;--header-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nt"&gt;header&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="n"&gt;darkgrey&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="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--header-height&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;fixed&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;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;all&lt;/span&gt; &lt;span class="m"&gt;0.3s&lt;/span&gt; &lt;span class="n"&gt;linear&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nt"&gt;main&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;150vh&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;padding-top&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;--header-height&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nc"&gt;.pin&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nc"&gt;.unpin&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;top&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;--header-height&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;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;header&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;{headerClass}&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;main&amp;gt;&lt;/span&gt;Lorem ipsum&lt;span class="nt"&gt;&amp;lt;/main&amp;gt;&lt;/span&gt;


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



&lt;p&gt;Here is a sandbox with this code for your enjoyment:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/svelte-header-blog-post-8vv15?module=/App.svelte"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Thanks for reading and happy coding! Please feel free to leave a comment or connect with me on &lt;a href="https://twitter.com/collardeau/"&gt;twitter&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>svelte</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>css</category>
    </item>
    <item>
      <title>Two Simple Tips For Debugging In the Console</title>
      <dc:creator>Thomas Collardeau</dc:creator>
      <pubDate>Tue, 20 Aug 2019 22:00:40 +0000</pubDate>
      <link>https://forem.com/collardeau/two-simple-tips-for-debugging-in-the-console-f87</link>
      <guid>https://forem.com/collardeau/two-simple-tips-for-debugging-in-the-console-f87</guid>
      <description>&lt;p&gt;For my first post, I thought I would share 2 simple tips that I use when debugging Javascript in the console. You might very well know these already!&lt;/p&gt;

&lt;h2&gt;
  
  
  Reigning in the console
&lt;/h2&gt;

&lt;p&gt;Not necessarily saying it's ideal, but if you're in the midst of an epic debugging sesh, you might end up in a situation with loads of &lt;code&gt;console.log&lt;/code&gt; sprinkled all over your beautiful code like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isLoggedIn&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// sometime later:&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&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="c1"&gt;// in another file:&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;likes&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// more logs all over the place...&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;followers&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The flurry of logs in the console can quickly become a burden of confusion. What data belongs to what value, assuming we don't know what order they're even ran amidst the flow of our code?&lt;/p&gt;

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

&lt;p&gt;One solution is that we can &lt;code&gt;console.log('data: ', data)&lt;/code&gt;, but we can also accomplish the same in fewer characters. What we can do instead is wrap our value in an object as such: &lt;code&gt;console.log({ data })&lt;/code&gt; and the console will print out the name of the variable before the data:&lt;/p&gt;

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

&lt;p&gt;We're basically using ES6 shorthand syntax to log out an object that we create on the fly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Refactoring Functions
&lt;/h2&gt;

&lt;p&gt;Talk about ES6, another situation is that you might be writing your functions using more shorthand syntax like this:&lt;br&gt;
&lt;code&gt;const exclaim = txt =&amp;gt; text + "!"&lt;/code&gt;&lt;br&gt;
but then, some time later, you want to log &lt;code&gt;txt&lt;/code&gt;, so you have to refactor the code to something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;exclaim&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;txt&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;txt&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="c1"&gt;// needs to become:&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;exclaim&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;txt&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;txt&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;text&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;!&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;Almost makes you want to skip the whole task. Well, you can also do the following and still log the parameter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;exclaim&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;txt&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="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;txt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;txt&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;!&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;What happens here is that the &lt;code&gt;console.log&lt;/code&gt; runs as normal and evaluates to false, so the parser evaluates the second expression of the OR clause &lt;code&gt;txt + "!"&lt;/code&gt; and returns it as they are no more expressions to check. We sneaked in that log along the way and threw it away essentially. As such we can keep our functions as one-liners and still inspect them without jumping around in the editor.&lt;/p&gt;

&lt;h3&gt;
  
  
  Until Next Time!
&lt;/h3&gt;

&lt;p&gt;Looking forward to being part of this community and learning along with everybody!&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
