<?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: michaelb</title>
    <description>The latest articles on Forem by michaelb (@michaelpb).</description>
    <link>https://forem.com/michaelpb</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%2F1161608%2F359af9c1-5ee1-4c2b-b61b-72c731a45739.png</url>
      <title>Forem: michaelb</title>
      <link>https://forem.com/michaelpb</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/michaelpb"/>
    <language>en</language>
    <item>
      <title>Learn for-loop template tags and data types building a train schedule web component (Learn Modulo.js - Part 7 of 10)</title>
      <dc:creator>michaelb</dc:creator>
      <pubDate>Wed, 16 Oct 2024 14:49:44 +0000</pubDate>
      <link>https://forem.com/michaelpb/learn-for-loop-template-tags-and-data-types-building-a-train-schedule-web-component-learn-modulojs-part-7-of-10-3ohn</link>
      <guid>https://forem.com/michaelpb/learn-for-loop-template-tags-and-data-types-building-a-train-schedule-web-component-learn-modulojs-part-7-of-10-3ohn</guid>
      <description>&lt;p&gt;👋 Hey all, welcome back this week! Each tutorial is self-contained, so feel free to start at the beginning, or just plunge in here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing: The TrainSchedule Component
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1g60eishvq9jc20wphf6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1g60eishvq9jc20wphf6.png" alt="Demonstrating code for Train Schedule component and DOM structure" width="795" height="384"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our task in this tutorial will be to build a data table TrainSchedule component that can loop through an array of JavaScript data. We want it to be re-usable, so we can, in the future, simply "plug in" a new data set (e.g., a JSON file, or even a CSV). In doing so, we'll learn about the different data types available, and how to attach them to &lt;em&gt;State&lt;/em&gt; and other Modulo Component Parts. We'll also learn the "for loop" template tag. Let's begin!&lt;/p&gt;

&lt;h2&gt;
  
  
  Starting snippet
&lt;/h2&gt;

&lt;p&gt;In this tutorial, we will start with a bunch of "flat" &lt;em&gt;State&lt;/em&gt; variables that only contains text. See below:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;As with previous tutorials, you can simply copy and paste this code into any HTML file to start:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;Modulo&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Component&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"TrainSchedule"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;Template&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;h3&amp;gt;&lt;/span&gt;Station&lt;span class="nt"&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;h3&amp;gt;&lt;/span&gt;Line&lt;span class="nt"&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;  &lt;span class="nt"&gt;&amp;lt;h3&amp;gt;&lt;/span&gt;Arrival (Departure)&lt;span class="nt"&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.station&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.line&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;state.late&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;&lt;span class="s"&gt;background: #ffaaaa&lt;/span&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endif&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.minutes&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt; min (&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.minutes&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt; min)&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/Template&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;State&lt;/span&gt;
            &lt;span class="na"&gt;line=&lt;/span&gt;&lt;span class="s"&gt;"Red Line"&lt;/span&gt;
            &lt;span class="na"&gt;station=&lt;/span&gt;&lt;span class="s"&gt;"Embarcadero"&lt;/span&gt;
            &lt;span class="na"&gt;minutes=&lt;/span&gt;&lt;span class="s"&gt;"5"&lt;/span&gt;
            &lt;span class="na"&gt;late=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;gt;&amp;lt;/State&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;Style&amp;gt;&lt;/span&gt;
            :host {
                display: block;
                text-align: center;
                display: grid;
                grid-template-columns: 1fr 1fr 1fr;
            }
            div {
                background: #ffffffaa;
            }
        &lt;span class="nt"&gt;&amp;lt;/Style&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/Component&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/mdu.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;x-TrainSchedule&amp;gt;&amp;lt;/x-TrainSchedule&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Introducing Part 7: Data Types
&lt;/h2&gt;

&lt;p&gt;As of right now, there are several glaring issues with our code: The first bug is that it shows the train as late (highlighted in red), yet it should not be. The second bug is that it says it will depart in "51 min", instead of "6 min", when it's supposed to have 1 minute for boarding. In both these cases, it's because of the wrong data type: We are only dealing with &lt;em&gt;Strings&lt;/em&gt;, when we want to be using &lt;em&gt;Numbers&lt;/em&gt; and &lt;em&gt;Booleans&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The final omission is that there is only one station showing. Not a very useful data table!&lt;/p&gt;

&lt;p&gt;We'll learn one more syntax next: The Data Prop, or &lt;code&gt;:=&lt;/code&gt; syntax. Typically, when we add attributes to anything, whether it is a Component Part or even just in regular HTML, the attribute value can only be a string. This means when we did &lt;code&gt;&amp;lt;State minutes="5" ... &amp;gt;&lt;/code&gt; previously, we made a mistake: The &lt;code&gt;minutes&lt;/code&gt; variable didn't get assigned to &lt;code&gt;5&lt;/code&gt; the &lt;em&gt;Number&lt;/em&gt;, but rather &lt;code&gt;"5"&lt;/code&gt; the &lt;em&gt;String&lt;/em&gt;. Similarly, when we did &lt;code&gt;late="false"&lt;/code&gt;, we once again were creating a string with the word "false", instead of the &lt;em&gt;Boolean&lt;/em&gt; value of false. Also, for one word values, quotes are optional.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Why don't we use "strings" for numbers?&lt;/strong&gt; Using strings of digits (i.e. in  quotes) instead of the numbers themselves means that things like arithmetic won't work as intended. Example: If state variable &lt;code&gt;count="1"&lt;/code&gt;, then &lt;code&gt;state.count + 10&lt;/code&gt; will result in &lt;code&gt;"110"&lt;/code&gt; instead of the desired &lt;code&gt;11&lt;/code&gt;, since it's a string of digits, so &lt;code&gt;"1" + "10" = "110"&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Arrays
&lt;/h3&gt;

&lt;p&gt;Continuing on our tour of data types, let's examine "container types" (ones that contain other data). In our case, container types are also "iterable types" (ones you can "loop on", e.g. with a for loop, as we'll learn later).&lt;/p&gt;

&lt;p&gt;Arrays are the most important type of "container type" or "iterable type" in JavaScript. This means, a type that can contain other types.  This means you can say it's an "Array of Numbers" (to refer to a certain collection of numbers, e.g. data you want to chart or graph), or an "Array of Strings" (to&lt;br&gt;
refer to a collection of items of text, e.g. the usernames of people who are present in a chat room).&lt;/p&gt;
&lt;h4&gt;
  
  
  Objects
&lt;/h4&gt;

&lt;p&gt;Objects are like arrays in that they contain other data, but instead of having an ordered sequence of items, they have them behind "keys", which are strings designations or labels for values, which can be any other type. The format for objects is like: &lt;code&gt;{ "key": "value", "key2": "another value" }&lt;/code&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Arrays of Objects
&lt;/h4&gt;

&lt;p&gt;When we access real-world data, whether those are blog articles in a publishing site, or a data items in a dashboard, they often "arrive formatted" as what's called a JSON array of objects. Here's an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;State
    stations:='[
        {
            "name": "Embarcadero Station - San Francisco",
            "trafficRating": 1353
        },
        {
            "name": "19th Street Station - Oakland",
            "trafficRating": 732
        }
    ]'
&amp;gt;&amp;lt;/State&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Summary: JSON type list
&lt;/h4&gt;

&lt;p&gt;To summarize this, look at this list of JSON types, and see if you can&lt;br&gt;
understand the examples given of each type of data:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;String&lt;/strong&gt; - &lt;code&gt;"Hello!"&lt;/code&gt;, &lt;code&gt;"how are you"&lt;/code&gt;, &lt;code&gt;"f$J^&amp;amp;m$j"&lt;/code&gt;, or the empty &lt;code&gt;""&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Number&lt;/strong&gt; - &lt;code&gt;42&lt;/code&gt; or &lt;code&gt;32.5&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Array&lt;/strong&gt; - &lt;code&gt;[ ]&lt;/code&gt; or &lt;code&gt;[ 1, "a", true ]&lt;/code&gt; &lt;em&gt;(can contain other data)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Object&lt;/strong&gt; - &lt;code&gt;{ }&lt;/code&gt; or &lt;code&gt;{ "a": 123, "b": "XYZ" }&lt;/code&gt; &lt;em&gt;(can contain other data)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Boolean&lt;/strong&gt; - &lt;code&gt;true&lt;/code&gt; and &lt;code&gt;false&lt;/code&gt; &lt;em&gt;(no other possible values)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Other:&lt;/em&gt; &lt;code&gt;null&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Step 1: Fixing with Data Props
&lt;/h3&gt;

&lt;p&gt;To fix it, we do the following:&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;State&lt;/span&gt;
    &lt;span class="na"&gt;line=&lt;/span&gt;&lt;span class="s"&gt;"Red Line"&lt;/span&gt;
    &lt;span class="na"&gt;station=&lt;/span&gt;&lt;span class="s"&gt;"Embarcadero"&lt;/span&gt;
    &lt;span class="na"&gt;minutes:=&lt;/span&gt;&lt;span class="s"&gt;5&lt;/span&gt;
    &lt;span class="na"&gt;late:=&lt;/span&gt;&lt;span class="s"&gt;false&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&amp;lt;/State&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Data type?&lt;/strong&gt; If you are new to coding, you might be confused by this term. It's a little like a file format for variables: Instead of JPG, DOCX, and ZIP, we have Numbers, Strings, Arrays, Objects, Booleans, etc. This collection of types is what makes up the "JSON" format, which Modulo uses.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is called a &lt;em&gt;data prop&lt;/em&gt; directive. You can identify a &lt;em&gt;data prop&lt;/em&gt; directive (&lt;code&gt;:=&lt;/code&gt;), by spotting an attribute name that is suffixed with a colon right before the equal sign, like this: &lt;code&gt;attributeName:=value&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Adding More Trains with Arrays and Objects
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Array syntax summary: &lt;code&gt;'[&lt;/code&gt; (opening), &lt;code&gt;]'&lt;/code&gt; (closing), and contents seperated
with comma: &lt;code&gt;,&lt;/code&gt;. Object syntax summary: &lt;code&gt;'{&lt;/code&gt; (opening), &lt;code&gt;}'&lt;/code&gt; (closing), &lt;code&gt;:&lt;/code&gt; (seperates the key
from the value) and &lt;code&gt;,&lt;/code&gt; (seperates each entry)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, let's transform our &lt;em&gt;State&lt;/em&gt; into having only a single state variable, an &lt;em&gt;Array&lt;/em&gt; of &lt;em&gt;Objects&lt;/em&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;State&lt;/span&gt;
    &lt;span class="na"&gt;trains:=&lt;/span&gt;&lt;span class="s"&gt;'[
        {
            "line": "Red Line",
            "station": "Embarcadero",
            "minutes": 5,
            "late": false
        },
        {
            "line": "Blue Line",
            "station": "Embarcadero",
            "minutes": 7,
            "late": true
        },
        {
            "line": "Red Line",
            "station": "West Oakland",
            "minutes": 1,
            "late": false
        }
    ]'&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&amp;lt;/State&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Using a for-loop to show all trains
&lt;/h3&gt;

&lt;p&gt;We looked at the &lt;code&gt;{% if %}&lt;/code&gt; template tag previously. Now we'll practice the &lt;code&gt;{% for %}&lt;/code&gt; template tag.&lt;/p&gt;

&lt;p&gt;The "for-tag" is for when we want to duplicate a bit of template over and over for a repetitive bit of data. For example, if we want to template "for every article", or "for every pin in a world map", or "for every post in an article comment section". Each of these "for" statements refers to some plural thing that we want to have a similar style duplicated across, using the same HTML template for each item in that collection.&lt;/p&gt;

&lt;h4&gt;
  
  
  The for-tag syntax
&lt;/h4&gt;

&lt;p&gt;For example, imagine showing a paragraph for every student in a class's roster&lt;br&gt;
(assuming data like in the &lt;code&gt;students:=&lt;/code&gt;  &lt;em&gt;State&lt;/em&gt; data example above):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;state.students&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Name on roster: &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endfor&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A for loop can also loop through other types of data, such as the very popular &lt;em&gt;Array of Objects&lt;/em&gt; mentioned previously, formatting it in a reasonable way (assuming data like in the &lt;code&gt;trains:=&lt;/code&gt;  &lt;em&gt;State&lt;/em&gt; data example above):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;    &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nv"&gt;train&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;state.trains&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;train.station&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt; | &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;train.minutes&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endfor&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, the &lt;code&gt;{{ train.station }}&lt;/code&gt; and &lt;code&gt;{{ train.minutes }}&lt;/code&gt; refer to templating the individual values within the station object in the array of stations.&lt;/p&gt;

&lt;p&gt;Like the "if", for has an "endfor", which it uses to designate the portion of the temlpate it will repeat. Unlike "if", it can use the template it 0 times, 1 time, or 2+ times (&lt;code&gt;if-tags&lt;/code&gt; can use the template only 0 times or 1 time, but can never "duplicate" the template and use it 2+ times).&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Using a for-loop to show all trains
&lt;/h3&gt;

&lt;p&gt;Let's apply our for-loop knowledge below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nv"&gt;train&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;state.trains&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;train.station&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;train.line&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;train.late&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;&lt;span class="s"&gt;background: #ffaaaa&lt;/span&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endif&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;train.minutes&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt; min (&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;train.minutes&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt; min)&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endfor&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;code&gt;&amp;lt;x-TrainSchedule&amp;gt;&lt;/code&gt; - Complete Example
&lt;/h2&gt;

&lt;p&gt;Finally, we put everything together, add in some font and sizing adjustments and a background, and we end up with the final results. Feel free to copy and paste the following to try it out:&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;template&lt;/span&gt; &lt;span class="na"&gt;Modulo&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Component&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"TrainSchedule"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;Template&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;h3&amp;gt;&lt;/span&gt;Station&lt;span class="nt"&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;h3&amp;gt;&lt;/span&gt;Line&lt;span class="nt"&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;  &lt;span class="nt"&gt;&amp;lt;h3&amp;gt;&lt;/span&gt;Arrival (Departure)&lt;span class="nt"&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;
            {% for train in state.trains %}
                &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;{{ train.station }}&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;{{ train.line }}&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"{% if train.late %}background: #ffaaaa{% endif %}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{ train.minutes }} min ({{ train.minutes|add:1 }} min)&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
            {% endfor %}
        &lt;span class="nt"&gt;&amp;lt;/Template&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;State&lt;/span&gt;
            &lt;span class="na"&gt;trains:=&lt;/span&gt;&lt;span class="s"&gt;'[
                {
                    "line": "Red Line",
                    "station": "Embarcadero",
                    "minutes": 5,
                    "late": false
                },
                {
                    "line": "Blue Line",
                    "station": "Embarcadero",
                    "minutes": 7,
                    "late": true
                },
                {
                    "line": "Red Line",
                    "station": "West Oakland",
                    "minutes": 1,
                    "late": false
                }
            ]'&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;gt;&amp;lt;/State&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;Style&amp;gt;&lt;/span&gt;
            :host {
                background: url("https://upload.wikimedia.org/wikipedia/commons/thumb/2/29/BART_train_from_Farallones_Street_footbridge_%281%29%2C_July_2023.JPG/800px-BART_train_from_Farallones_Street_footbridge_%281%29%2C_July_2023.JPG");
                display: block;
                font-size: 1.1rem;
                font-family: sans-serif;
                text-align: center;
                display: grid;
                grid-template-columns: 1fr 1fr 1fr;
                min-height: 380px;
            }
            div {
                background: #ffffffaa;
                padding: 10px;
                margin: 10px;
            }
        &lt;span class="nt"&gt;&amp;lt;/Style&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/Component&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/mdu.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;x-TrainSchedule&amp;gt;&amp;lt;/x-TrainSchedule&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;In this section, we practiced using &lt;em&gt;:=&lt;/em&gt; data props to use different types of data in our component, and learned how we can use how to go deeper with &lt;em&gt;Template&lt;/em&gt; and use a combo of &lt;code&gt;{% for %}&lt;/code&gt;, &lt;code&gt;{% if %}&lt;/code&gt; and other control-flow &lt;code&gt;template-tags&lt;/code&gt;. Next tutorial will really ramp it up, and show how to import data from online sources or APIs using the &lt;em&gt;StaticData&lt;/em&gt; Component Part. Definitely follow and watch out for the next tutorial, since with that technique you can import your data and build data tables quicker than ever! As always, let me know if there is something you'd like covered in the comments.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>javascript</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Learn template-tags while creating interactive forms in a web component (Learn Modulo.js - Part 6 of 10)</title>
      <dc:creator>michaelb</dc:creator>
      <pubDate>Thu, 03 Oct 2024 18:17:00 +0000</pubDate>
      <link>https://forem.com/michaelpb/learn-template-tags-while-creating-interactive-forms-in-a-web-component-learn-modulojs-part-6-of-10-5bik</link>
      <guid>https://forem.com/michaelpb/learn-template-tags-while-creating-interactive-forms-in-a-web-component-learn-modulojs-part-6-of-10-5bik</guid>
      <description>&lt;p&gt;👋 Hey all, welcome back this week! Each tutorial is self-contained, so feel free to start at the beginning, or just plunge in here.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note:&lt;/em&gt; Due to a bug with Dev.To, I'm unable to publish this tutorial normally. The fenced code blocks do not support template syntax, causing the markdown parser to crash.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing: The NewsletterSubscribe Component
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frk4uot6on9u81f2g1vqj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frk4uot6on9u81f2g1vqj.png" alt="Showing the final result of NewsletterSubscriber"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In Part 6, we'll be creating a custom, interactive sign-up form that only shows the newsletters to subscribe when the user chooses. This will give us practice with some very useful techniques, while building up our knowledge of &lt;em&gt;template-tags&lt;/em&gt;, a core concept in templating.&lt;/p&gt;

&lt;h2&gt;
  
  
  Starting snippet
&lt;/h2&gt;

&lt;p&gt;In this tutorial, we will start with &lt;em&gt;Props&lt;/em&gt;, just like with the PictureFrame component in &lt;a href="https://dev.to/michaelpb/creating-a-styled-picture-frame-web-component-made-reusable-with-props-learn-modulojs-part-2-of-10-4lh1"&gt;Part 2&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;As with previous tutorials, you can simply copy and paste this code into any HTML file to start:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;Modulo&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Component&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"NewsletterSubscribe"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;Template&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;method=&lt;/span&gt;&lt;span class="s"&gt;"POST"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;Learn Modulo.js - Sign-Up Component&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;label&amp;gt;&amp;lt;strong&amp;gt;&lt;/span&gt;Email:&lt;span class="nt"&gt;&amp;lt;/strong&amp;gt;&amp;lt;input&lt;/span&gt; &lt;span class="err"&gt;[&lt;/span&gt;&lt;span class="na"&gt;state.bind&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;label&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="err"&gt;[&lt;/span&gt;&lt;span class="na"&gt;state.bind&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"subscribe"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"checkbox"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
                    I want to subscribe to receive news and special offers
                &lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;label&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="err"&gt;[&lt;/span&gt;&lt;span class="na"&gt;state.bind&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"newsletters.kombucha"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"checkbox"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
                    Kombucha Enthusiast Newsletter
                &lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;button&amp;gt;&lt;/span&gt;Submit&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/Template&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;State&lt;/span&gt;
            &lt;span class="na"&gt;email=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;
            &lt;span class="na"&gt;subscribe:=&lt;/span&gt;&lt;span class="s"&gt;false&lt;/span&gt;
            &lt;span class="na"&gt;newsletters:=&lt;/span&gt;&lt;span class="s"&gt;{}&lt;/span&gt;
            &lt;span class="na"&gt;newsletters.kombucha:=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
            &lt;span class="na"&gt;newsletters.soda:=&lt;/span&gt;&lt;span class="s"&gt;false&lt;/span&gt;
            &lt;span class="na"&gt;newsletters.wine:=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
            &lt;span class="na"&gt;newsletters.beer:=&lt;/span&gt;&lt;span class="s"&gt;false&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;gt;&amp;lt;/State&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/Component&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/mdu.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;x-NewsletterSubscribe&amp;gt;&amp;lt;/x-NewsletterSubscribe&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Important things to note: Look at how "State" is set-up. Do you see how &lt;code&gt;newsletters:={}&lt;/code&gt; assigns to a JavaScript Object (designated with &lt;code&gt;{}&lt;/code&gt;), and how then &lt;code&gt;kombucha&lt;/code&gt;, &lt;code&gt;soda&lt;/code&gt;, &lt;code&gt;wine&lt;/code&gt;, and &lt;code&gt;beer&lt;/code&gt; are all assigned with the syntax &lt;code&gt;newsletters.kombucha&lt;/code&gt;, etc? This creates an &lt;em&gt;Object&lt;/em&gt; that ends up looking like: &lt;code&gt;{ "kombucha": true, "soda": false ... }&lt;/code&gt;. This is a short-hand in Modulo for creating such objects. Also, note how &lt;code&gt;name="newsletters.kombucha"&lt;/code&gt; must specify the full name, including the dot (&lt;code&gt;.&lt;/code&gt;), to access that &lt;code&gt;true&lt;/code&gt;/&lt;code&gt;false&lt;/code&gt; value.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing Part 6: Template Tags
&lt;/h2&gt;

&lt;p&gt;In addition to filters, the Modulo templating language also support powerful "template tags", which allow for more complicated custom behavior.  This includes the next two topics in this tutorial: "if" template-tag, which allows for conditional rendering (e.g.  "only show the submit button if a form is filled correctly", or "only show the modal if the user has clicked the button"), and the "for" template-tag, which allows for HTML to be repeated for each item of some given data (e.g. "every blog post gets it's own &lt;code&gt;&amp;lt;li&amp;gt;&lt;/code&gt; element", or "every field of data gets it's own form field").&lt;/p&gt;

&lt;h3&gt;
  
  
  Syntax
&lt;/h3&gt;

&lt;p&gt;Unlike template variables or filters, they use &lt;code&gt;{%&lt;/code&gt; and &lt;code&gt;%}&lt;/code&gt; (instead of &lt;code&gt;{{&lt;/code&gt; and &lt;code&gt;}}&lt;/code&gt;) to designate where they are in the &lt;em&gt;Template&lt;/em&gt; code. Template tags are in the format of &lt;code&gt;{% tag %}&lt;/code&gt;. They allow for more complicated transformations to the HTML code generated. For example, here are a few: &lt;code&gt;{% include other_template %} {% comment %} ... {% endcomment %}&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The if-tag
&lt;/h3&gt;

&lt;p&gt;One of the most useful template tags you will use is the if tag, written like this: &lt;code&gt;{% if %}&lt;/code&gt;.  The if-tag allows for conditional rendering of HTML code based on the condition supplied.&lt;/p&gt;

&lt;p&gt;See below for two examples of using the "if" tag:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;{% if state.expanded %}&lt;/code&gt;&lt;br&gt;
&lt;code&gt;&amp;lt;p&amp;gt;Details: {{ props.details }}&amp;lt;/p&amp;gt;&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;br&gt;
&lt;code&gt;{% endif %}&lt;/code&gt;&lt;br&gt;
&lt;code&gt;{% if props.link %}&lt;/code&gt;&lt;br&gt;
&lt;code&gt;&amp;lt;a href="{{ props.link }}"&amp;gt;Read more...&amp;lt;/a&amp;gt;&lt;/code&gt;&lt;br&gt;
&lt;code&gt;{% else %}&lt;/code&gt;&lt;br&gt;
&lt;code&gt;&amp;lt;em&amp;gt;(No link provided)&amp;lt;/em&amp;gt;&lt;/code&gt;&lt;br&gt;
&lt;code&gt;{% endif %}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Note that there are two other tags in the mix. These a related to the &lt;code&gt;if&lt;/code&gt; tag, and will only show up after the &lt;code&gt;if&lt;/code&gt; tag. The first is the &lt;code&gt;{% endif %}&lt;/code&gt; tag. This is required, since it shows Modulo what you want the &lt;code&gt;if&lt;/code&gt; tag to conditionally include. The second is the &lt;code&gt;{% else %}&lt;/code&gt; tag. The &lt;code&gt;{% else %}&lt;/code&gt; is optional, as evidenced by the first example: You don't need it for all uses of the &lt;code&gt;if&lt;/code&gt; tag.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Optionally show the Kombucha checkbox
&lt;/h2&gt;

&lt;p&gt;Let's start with an if-statement based on &lt;code&gt;state.subscribe&lt;/code&gt;. The logic is that if the user doesn't want to subscribe at all, we shouldn't even show the extra newsletter options. We can accomplish this with the following:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;{% if state.subscribe %}&lt;/code&gt;&lt;br&gt;
&lt;code&gt;&amp;lt;label&amp;gt;&lt;/code&gt;&lt;br&gt;
&lt;code&gt;&amp;lt;input [state.bind] name="newsletters.kombucha" type="checkbox" /&amp;gt;&lt;/code&gt;&lt;br&gt;
&lt;code&gt;Kombucha Enthusiast Newsletter&lt;/code&gt;&lt;br&gt;
&lt;code&gt;&amp;lt;/label&amp;gt;&lt;/code&gt;&lt;br&gt;
&lt;code&gt;{% endif %}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This will now only show the option to choose which newsletter when you click "subscribe".&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Use "else" to show a hint about filling in the email
&lt;/h2&gt;

&lt;p&gt;Now, let's get practice using a more complex if statement to show a hint instead of the "subscribe" form button, until they start typing a few characters. Emails should (probably) never be shorter than 4 characters, so let's use that as the thresh-hold. We can use the &lt;code&gt;lt&lt;/code&gt; (less-than, a.k.a. &lt;code&gt;&amp;lt;&lt;/code&gt;) operator to compare. See below:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;{% if state.email|length lt 4 %}&lt;/code&gt;&lt;br&gt;
&lt;code&gt;&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;Hint: Start by entering your email&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;&lt;/code&gt;&lt;br&gt;
&lt;code&gt;{% else %}&lt;/code&gt;&lt;br&gt;
&lt;code&gt;(... subscribe form goes here ...)&lt;/code&gt;&lt;br&gt;
&lt;code&gt;{% endif %}&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Use for loop to list the newsletters
&lt;/h2&gt;

&lt;p&gt;Let's start with a simple for-loop "test", and then we'll expand on it in the next step:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;{% for key, value in state.newsletters %}&lt;/code&gt;&lt;br&gt;
&lt;code&gt;&amp;lt;label style="{% if value %}background-color: #11991133;{% endif %}"&amp;gt;&lt;/code&gt;&lt;br&gt;
&lt;code&gt;{{ key }}&lt;/code&gt;&lt;br&gt;
&lt;code&gt;&amp;lt;/label&amp;gt;&lt;/code&gt;&lt;br&gt;
&lt;code&gt;{% endfor %}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important Note:&lt;/strong&gt; Always put your template tags &lt;em&gt;inside&lt;/em&gt; your HTML values! Do not do something like &lt;code&gt;{% if value %}style="color: blue"{% endif %}&lt;/code&gt;, instead do &lt;code&gt;style="{% if value %}color: blue{% endif %}"&lt;/code&gt;. Otherwise, the &lt;code&gt;{%&lt;/code&gt; and such could get interpretted as value-less attributes, your code to get littered with &lt;code&gt;{%=""&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Adding back in the input
&lt;/h2&gt;

&lt;p&gt;This will loop through each newsletter, and render it as green if "value" is &lt;code&gt;true&lt;/code&gt;. However, it won't create toggle inputs. We'll need to use the &lt;code&gt;{{ key }}&lt;/code&gt; property inside of the &lt;code&gt;name=&lt;/code&gt; attribute. Examine the following tweak to the input:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;input [state.bind] name="newsletters.{{ key }}" type="checkbox" /&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Put this inside the for-loop, and it will auto-generate checkboxes, no matter how many newsletters you might have!&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;&amp;lt;x-NewsletterSubscribe&amp;gt;&lt;/code&gt; - Complete Example
&lt;/h2&gt;

&lt;p&gt;Finally, we put everything together, add a &lt;code&gt;|capfirst&lt;/code&gt; for formatting, and toss in a &lt;em&gt;Style&lt;/em&gt; part with some very basic styling, to make the form look a little better, and we end up with the final results. Feel free to copy and paste the following to try it out:&lt;/p&gt;

&lt;p&gt;Due to a bug with Dev.To, I cannot include the source code. However, you can see it in the following Gist:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gist.github.com/michaelpb/9bac99ba0985859742961c3d1e1f310a" rel="noopener noreferrer"&gt;https://gist.github.com/michaelpb/9bac99ba0985859742961c3d1e1f310a&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;In this section, we practice using &lt;em&gt;template-tags&lt;/em&gt; to make more user-friendly forms. In the next tutorial we'll start digging into some of Modulo's strengths, with data-types, &lt;em&gt;StaticData&lt;/em&gt; and API integration, so be sure to follow to learn how to write declarative code to hook up APIs in just a few lines!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Learn how to isolate CSS with Shadow DOM and Slots in a gallery web component (Learn Modulo.js - Part 5 of 10)</title>
      <dc:creator>michaelb</dc:creator>
      <pubDate>Fri, 27 Sep 2024 18:00:00 +0000</pubDate>
      <link>https://forem.com/michaelpb/learn-how-to-isolate-css-with-shadow-dom-and-slots-in-to-make-a-gallery-web-component-learn-modulojs-part-5-of-10-18a4</link>
      <guid>https://forem.com/michaelpb/learn-how-to-isolate-css-with-shadow-dom-and-slots-in-to-make-a-gallery-web-component-learn-modulojs-part-5-of-10-18a4</guid>
      <description>&lt;p&gt;👋 Hey all, welcome back this week! Each tutorial is self-contained, so feel free to start at the beginning, or just plunge in here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing: The PhotoGallery Component
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd80eitxgloj8ssa33hsf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd80eitxgloj8ssa33hsf.png" alt="Demonstrating code for vanishing component with images and DOM structure"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our task in this tutorial will be to build a Photo Gallery component, that can take any number of image tags and display them. Our goal is to make this convenient: HTML developers should be able to immediately know how to use it and use it effectively.&lt;/p&gt;

&lt;h2&gt;
  
  
  Starting snippet
&lt;/h2&gt;

&lt;p&gt;In this tutorial, we will start with &lt;em&gt;Props&lt;/em&gt;, just like with the PictureFrame component in &lt;a href="https://dev.to/michaelpb/creating-a-styled-picture-frame-web-component-made-reusable-with-props-learn-modulojs-part-2-of-10-4lh1"&gt;Part 2&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;As with previous tutorials, you can simply copy and paste this code into any HTML file to start:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;Modulo&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Component&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"PhotoGallery"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;Props&lt;/span&gt;
             &lt;span class="na"&gt;image1&lt;/span&gt;
             &lt;span class="na"&gt;image2&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;gt;&amp;lt;/Props&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;Template&amp;gt;&lt;/span&gt;
           &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex-gallery"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
               &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;props.image1&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nf"&gt;safe&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;
               &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;props.image2&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nf"&gt;safe&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;
           &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/Template&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;Style&amp;gt;&lt;/span&gt;
            .flex-gallery {
                border: 2px ridge gray;
                padding: 10px;
                display: flex;
                flex-wrap: wrap;
            }
            img {
                border: 2px ridge goldenrod;
                margin: 10px;
                border-radius: 10px;
            }
        &lt;span class="nt"&gt;&amp;lt;/Style&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/Component&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/mdu.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;x-PhotoGallery&lt;/span&gt;
    &lt;span class="na"&gt;image1=&lt;/span&gt;&lt;span class="s"&gt;"&amp;lt;img src='https://upload.wikimedia.org/wikipedia/commons/thumb/f/f7/Helen_KellerA.jpg/193px-Helen_KellerA.jpg' title='Hellen Keller' /&amp;gt;"&lt;/span&gt;
    &lt;span class="na"&gt;image2=&lt;/span&gt;&lt;span class="s"&gt;"&amp;lt;img src='https://upload.wikimedia.org/wikipedia/commons/thumb/9/9d/Mark_Twain_1907.jpg/187px-Mark_Twain_1907.jpg' title='Mark Twain' /&amp;gt;"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&amp;lt;/x-PhotoGallery&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One important new filter we added is the &lt;code&gt;|safe&lt;/code&gt; filter. This tells Modulo to interpret the variable as HTML (not text), and thus correctly render the image. Otherwise, the user would see the code for the images, not the image itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing Part 5: slots
&lt;/h2&gt;

&lt;p&gt;As of right now, there are two glaring issues with our code:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;We only support 2 images. If we wanted more images, we'd have to manually define them in &lt;em&gt;Props&lt;/em&gt;. If we wanted dozens (or even hundreds) of images, it would become very quickly unmanageable.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Putting HTML into quotes as HTML attributes (&lt;em&gt;Props&lt;/em&gt;) is really messy. We need to watch out for quotations, and the code quickly becomes hard to manage.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The &lt;code&gt;&amp;lt;slot&amp;gt;&amp;lt;/slot&amp;gt;&lt;/code&gt; tag solves both of this. It allows you to use the &lt;em&gt;content&lt;/em&gt; of the HTML tag, allowing you to write HTML much more naturally. In Part 5, we'll get practice with Slots, but also learn about the related ShadowDOM, and about CSS isolation in general.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Slots&lt;/em&gt; allow there to be "empty spots" in your HTML that proceed to get filled by arbitrary content supplied when your component is used. Adding a slot is as simple as including a &lt;code&gt;&amp;lt;slot&amp;gt;&amp;lt;/slot&amp;gt;&lt;/code&gt; HTML element in your component's &lt;em&gt;Template&lt;/em&gt; definition. To fill up a &lt;em&gt;slot&lt;/em&gt; with HTML content, add the content between the opening and closing tags of your HTML element.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Adding a slot
&lt;/h3&gt;

&lt;p&gt;The quickest thing to do is just replacing the &lt;code&gt;div&lt;/code&gt; tag with the special &lt;code&gt;slot&lt;/code&gt; tag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Component&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"PhotoGallery"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Template&amp;gt;&lt;/span&gt;
       &lt;span class="nt"&gt;&amp;lt;slot&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex-gallery"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/slot&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/Template&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Style&amp;gt;&lt;/span&gt;/* ... */&lt;span class="nt"&gt;&amp;lt;/Style&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Component&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, to use it, we do the following:&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;x-PhotoGallery&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;'https://upload.wikimedia.org/wikipedia/commons/thumb/f/f7/Helen_KellerA.jpg/193px-Helen_KellerA.jpg'&lt;/span&gt; &lt;span class="na"&gt;title=&lt;/span&gt;&lt;span class="s"&gt;'Hellen Keller'&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="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;'https://upload.wikimedia.org/wikipedia/commons/thumb/9/9d/Mark_Twain_1907.jpg/187px-Mark_Twain_1907.jpg'&lt;/span&gt; &lt;span class="na"&gt;title=&lt;/span&gt;&lt;span class="s"&gt;'Mark Twain'&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/x-PhotoGallery&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Adding a default
&lt;/h3&gt;

&lt;p&gt;To make our PhotoGallery a bit more useful to whoever might use it, let's add a default appearance, so "empty" photo galleries have a message:&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;Template&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;slot&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex-gallery"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
       &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;&lt;/span&gt;No photos found.&lt;span class="nt"&gt;&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;/slot&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To test an empty gallery, write the tag without any space between the opening and closing: &lt;code&gt;&amp;lt;x-PhotoGallery&amp;gt;&amp;lt;/x-PhotoGallery&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Aside: Named slots
&lt;/h2&gt;

&lt;p&gt;While not used here, it's good to know you can have multiple slots by giving them names (with &lt;code&gt;name=&lt;/code&gt;), and specifying the name with the special &lt;code&gt;slot=&lt;/code&gt; attribute. For example: &lt;code&gt;&amp;lt;slot name="sidebar-photos"&amp;gt;&amp;lt;/slot&amp;gt;&lt;/code&gt;, and &lt;code&gt;&amp;lt;img slot="sidebar-photos" /&amp;gt;&lt;/code&gt; would create a new, separate slot from the default, nameless slot, which can have it's own default and it's own content.&lt;/p&gt;

&lt;h2&gt;
  
  
  CSS Isolation: Enter the Shadow
&lt;/h2&gt;

&lt;p&gt;Our &lt;code&gt;&amp;lt;x-PhotoGallery&amp;gt;&lt;/code&gt; component is complete at this point, for certain purposes. However, let's imagine this is in a larger page, and that existing CSS in that page is interfering with our styling. This is the use for CSS isolation. Let's start with practicing "shadow", set on the &lt;em&gt;Component&lt;/em&gt; itself, as such: &lt;code&gt;&amp;lt;Component mode="shadow"&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;When &lt;code&gt;shadowDOM&lt;/code&gt; is activated, then the component switches to&lt;br&gt;
using a somewhat new feature of HTML: the Shadow DOM. This dramatically named feature -- sounds kind of like a super villain -- allows a Web Component to create a protected or hidden DOM fragment (e.g. portion of an HTML page) that can be manipulated, while "protecting it" from outside CSS. This will dramatically change how the component renders, since the browser will treat it quite differently, and all of it's children will be "removed" from the DOM in the hidden Shadow DOM, making it appear "empty" when you right click and do &lt;strong&gt;Inspect&lt;/strong&gt; (but with more clicking, you can find the "shadow root" where the hidden content is).&lt;/p&gt;

&lt;p&gt;When a component is in shadow mode, and you launch your site or build your site, it's CSS &lt;em&gt;will NOT&lt;/em&gt; be put into the main CSS file. That means that it will be stored in the JavaScript file and only added whenever that component appears on the screen. Furthermore, due to the what the browser works, the CSS will be fully isolated in both directions: Outside CSS won't affect your component's children, and inner CSS is incapable of affecting anything else, and won't even be added until the component gets on the screen. Since it's fully isolated, there is no need to prefix, so CSS will be inserted as is.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 3: Entering the Shadow DOM
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd13fvq1je6q6019z7oad.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd13fvq1je6q6019z7oad.png" alt="Showing shadow root version of photo gallery"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Examine the image above. Do you see how it shows a "shadow-root"? That's what we want. Let's "switch on" Shadow mode for our component:&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;Component&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"PhotoGallery"&lt;/span&gt; &lt;span class="na"&gt;mode=&lt;/span&gt;&lt;span class="s"&gt;"shadow"&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;Check out what happens. The first thing you will notice is the images no longer get the border. This is intentional: The Component's CSS will not affect it's slots, since they are "protected" by the shadow DOM. This means we'll need to move the &lt;code&gt;img&lt;/code&gt; CSS to be global, regular / global CSS:&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;x-PhotoGallery&amp;gt;&lt;/span&gt;...&lt;span class="nt"&gt;&amp;lt;/x-PhotoGallery&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2px&lt;/span&gt; &lt;span class="nb"&gt;ridge&lt;/span&gt; &lt;span class="no"&gt;goldenrod&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;10px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, if we have an image in the template itself (that is, &lt;em&gt;not&lt;/em&gt; using slots), then it &lt;em&gt;will&lt;/em&gt; get the internal style. Let's add a decorative camera that floats to the right:&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;Template&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://upload.wikimedia.org/wikipedia/commons/thumb/f/f4/Studijskifotoaparat.JPG/312px-Studijskifotoaparat.JPG"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;slot&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex-gallery"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;&lt;/span&gt;No photos found.&lt;span class="nt"&gt;&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/slot&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Template&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;Style&amp;gt;&lt;/span&gt;
    img { float: right }
&lt;span class="nt"&gt;&amp;lt;/Style&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that this &lt;em&gt;does not&lt;/em&gt; get the global style, but &lt;em&gt;does&lt;/em&gt; get the component style.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Vanishing act
&lt;/h3&gt;

&lt;p&gt;Finally, let's practice one more component mode: &lt;em&gt;vanish&lt;/em&gt;. Note the image at the top of this tutorial doesn't show any &lt;code&gt;&amp;lt;x-PhotoGallery&amp;gt;&lt;/code&gt; component. That's because it &lt;em&gt;vanished&lt;/em&gt;!&lt;/p&gt;

&lt;p&gt;This will &lt;em&gt;not&lt;/em&gt; use the ShadowDOM, but still provide partial isolation: Outer CSS will influence inside the component, but the component's CSS will remain isolated and not influence slots. More importantly, the component will "vanish" -- that is, it will remove itself when it is displayed, leaving no trace of the web component, and a simpler / potentially more performant DOM structure.&lt;/p&gt;

&lt;p&gt;This is done just like &lt;code&gt;mode="shadow"&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;Component&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"PhotoGallery"&lt;/span&gt; &lt;span class="na"&gt;mode=&lt;/span&gt;&lt;span class="s"&gt;"vanish"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;code&gt;&amp;lt;x-PhotoGallery&amp;gt;&lt;/code&gt; - Complete Example
&lt;/h2&gt;

&lt;p&gt;Finally, we put everything together, and we end up with the final results. Feel free to copy and paste the following to try it out:&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;template&lt;/span&gt; &lt;span class="na"&gt;Modulo&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Component&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"PhotoGallery"&lt;/span&gt; &lt;span class="na"&gt;mode=&lt;/span&gt;&lt;span class="s"&gt;"vanish"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;Template&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://upload.wikimedia.org/wikipedia/commons/thumb/f/f4/Studijskifotoaparat.JPG/312px-Studijskifotoaparat.JPG"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;slot&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex-gallery"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;&lt;/span&gt;No photos found.&lt;span class="nt"&gt;&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/slot&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/Template&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;Style&amp;gt;&lt;/span&gt;
            .flex-gallery {
                border: 2px ridge gray;
                padding: 10px;
                display: flex;
                flex-wrap: wrap;
            }
            img {
                float: right;
            }
        &lt;span class="nt"&gt;&amp;lt;/Style&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/Component&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/mdu.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;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;img&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2px&lt;/span&gt; &lt;span class="nb"&gt;ridge&lt;/span&gt; &lt;span class="no"&gt;goldenrod&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;10px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&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;x-PhotoGallery&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://upload.wikimedia.org/wikipedia/commons/thumb/f/f7/Helen_KellerA.jpg/193px-Helen_KellerA.jpg"&lt;/span&gt; &lt;span class="na"&gt;title=&lt;/span&gt;&lt;span class="s"&gt;"Hellen Keller"&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="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://upload.wikimedia.org/wikipedia/commons/thumb/9/9d/Mark_Twain_1907.jpg/187px-Mark_Twain_1907.jpg"&lt;/span&gt; &lt;span class="na"&gt;title=&lt;/span&gt;&lt;span class="s"&gt;"Mark Twain"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/x-PhotoGallery&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;In this section, we practice using &lt;em&gt;slots&lt;/em&gt; to make more user-friendly components, and learned how we can use &lt;em&gt;shadow&lt;/em&gt; and &lt;em&gt;vanish&lt;/em&gt; rendering modes to isolate our components in different ways. Consider these all to be "tools" for your web component "toolbox", and very handy when dealing with conflicting CSS. In the next tutorial we'll be going deeper with &lt;em&gt;Template&lt;/em&gt;, so be sure to follow to catch how to use &lt;code&gt;{% for %}&lt;/code&gt;, &lt;code&gt;{% if %}&lt;/code&gt; and other control-flow &lt;code&gt;template-tags&lt;/code&gt;!&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>javascript</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Learn template filters and state binding to quickly build a button designer tool (Learn Modulo.js - Part 4 of 10)</title>
      <dc:creator>michaelb</dc:creator>
      <pubDate>Mon, 23 Sep 2024 18:33:00 +0000</pubDate>
      <link>https://forem.com/michaelpb/learn-template-filters-and-state-binding-to-quickly-build-a-button-designer-tool-learn-modulojs-part-4-of-10-nam</link>
      <guid>https://forem.com/michaelpb/learn-template-filters-and-state-binding-to-quickly-build-a-button-designer-tool-learn-modulojs-part-4-of-10-nam</guid>
      <description>&lt;p&gt;👋 Hey all, welcome back this week! Each tutorial is self-contained, so feel free to start at the beginning, or just plunge in here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing: The ButtonDesigner Component
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1s3m937kptsh1ei4m33b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1s3m937kptsh1ei4m33b.png" alt="Showing button x-ButtonDesigner component with Click me button in orange" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This time, our task is super useful and practical. Our task in this tutorial will be to build a button customizer component. You could use this to try out different CSS styles, or create a tool like this for your team customized for particular parameters to enable them to generate new CSS ideas quickly. These types of little CSS design tools are very popular to make, and thanks to Modulo and the power of State, we can create one with less than 40 lines of code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Filtering it up
&lt;/h2&gt;

&lt;p&gt;Today we'll introduce an important new concept: &lt;em&gt;Template filters&lt;/em&gt;. This enables us to modify state values slightly before displaying them (think "photo / Instagram filter for your data").&lt;/p&gt;

&lt;p&gt;Last time we ended with a snippet a little like the one below. However, in this tutorial, we've changed the "Template" to show a button with inline styles. We've changed the &lt;em&gt;State&lt;/em&gt; variables to now mostly be CSS values that are templated in the &lt;code&gt;style=&lt;/code&gt; attribute (&lt;em&gt;Style&lt;/em&gt; component parts don't support this, fyi). To begin this tutorial, copy and paste the following into a new file, and open in your browser:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;Modulo&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Component&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"ButtonDesigner"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;Template&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&amp;lt;label&amp;gt;&lt;/span&gt;Label&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="err"&gt;[&lt;/span&gt;&lt;span class="na"&gt;state.bind&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"
                    color: white;
                    background: &lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.color&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;;
                    border: &lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.size&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;px &lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.border&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt; #88888888;
                    padding: 4px;
                    font-size: 14px;
                    border-radius: 5px;
                "&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.text&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/Template&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;State&lt;/span&gt;
            &lt;span class="na"&gt;size=&lt;/span&gt;&lt;span class="s"&gt;"10"&lt;/span&gt;
            &lt;span class="na"&gt;border=&lt;/span&gt;&lt;span class="s"&gt;"solid"&lt;/span&gt;
            &lt;span class="na"&gt;color=&lt;/span&gt;&lt;span class="s"&gt;"#E66100"&lt;/span&gt;
            &lt;span class="na"&gt;text=&lt;/span&gt;&lt;span class="s"&gt;"click me"&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;gt;&amp;lt;/State&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/Component&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/mdu.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;x-ButtonDesigner&amp;gt;&amp;lt;/x-ButtonDesigner&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Why style attributes?&lt;/strong&gt; Note we can't template &lt;em&gt;Style&lt;/em&gt; tags, fyi, as those are get bundled into static CSS.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Introducing Part 4
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Why not change DOM directly?&lt;/strong&gt; Our previous tutorial ended with some musings on the importance to state. If you are a JavaScript veteran, you may know that earlier jQuery-style JS frameworks were more concerned with manipulating the DOM directly. Now, the modern approach is to combine templating and/or DOM building tools (e.g. JSX, virtual DOM) with "state management" (e.g. Redux, useState, context, refs, etc). Modulo takes the modern approach: The "moving parts" of the application are put into state, and then by changing state, the component re-displays itself, showing the new data. This "detangles" the spaghetti mess of DOM manipulation: Instead of one button inserting stuff over here, and one input reaching in and sending data over there, the "state" creates a single "choke-point" that keeps data "flowing" in&lt;br&gt;
one direction. No matter what you want changed, you do one thing: &lt;em&gt;Change state and rerender&lt;/em&gt;!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;State also allows binding of different inputs for different data types. For example, you can use &lt;code&gt;type="color"&lt;/code&gt; for a color picker, &lt;code&gt;type="range"&lt;/code&gt; for a range slider. There's also checkboxes, selects, number pickers, date pickers, and more! For starters, check out the following:&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;textarea&lt;/span&gt; &lt;span class="err"&gt;[&lt;/span&gt;&lt;span class="na"&gt;state.bind&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"body"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/textarea&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="err"&gt;[&lt;/span&gt;&lt;span class="na"&gt;state.bind&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"color"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"color"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="err"&gt;[&lt;/span&gt;&lt;span class="na"&gt;state.bind&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"size"&lt;/span&gt;
        &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"range"&lt;/span&gt; &lt;span class="na"&gt;min=&lt;/span&gt;&lt;span class="s"&gt;"12"&lt;/span&gt; &lt;span class="na"&gt;max=&lt;/span&gt;&lt;span class="s"&gt;"28"&lt;/span&gt; &lt;span class="na"&gt;step=&lt;/span&gt;&lt;span class="s"&gt;"2"&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;Clarification: These are all just HTML5, built-in input types.  To peruse a full selection of input types, consider &lt;a href="https://developer.mozilla.org/en-US/docs/Learn/Forms/HTML5_input_types" rel="noopener noreferrer"&gt;MDN's "The HTML5 input types" Guide in their &lt;em&gt;Learn Web Development&lt;/em&gt; series&lt;/a&gt;. The &lt;em&gt;State&lt;/em&gt; CPart will look at the &lt;code&gt;type&lt;/code&gt; attribute in order to use the right data types.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Adding select and color picker
&lt;/h3&gt;

&lt;p&gt;We can bind select tags and color picker inputs the same way we bind anything else:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&amp;lt;label&amp;gt;&lt;/span&gt;Border&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;select&lt;/span&gt; &lt;span class="err"&gt;[&lt;/span&gt;&lt;span class="na"&gt;state.bind&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"border"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;option&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"solid"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Solid&lt;span class="nt"&gt;&amp;lt;/option&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;option&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"outset"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Outset&lt;span class="nt"&gt;&amp;lt;/option&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;option&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"groove"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Groove&lt;span class="nt"&gt;&amp;lt;/option&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;option&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"dashed"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Dashed&lt;span class="nt"&gt;&amp;lt;/option&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/select&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&amp;lt;label&amp;gt;&lt;/span&gt;Color&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="err"&gt;[&lt;/span&gt;&lt;span class="na"&gt;state.bind&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"color"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"color"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Adding "range" slider and
&lt;/h3&gt;

&lt;p&gt;Note that sliders require specifying min, max, and step (e.g. distance between "snaps"):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&amp;lt;label&amp;gt;&lt;/span&gt;Size&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="err"&gt;[&lt;/span&gt;&lt;span class="na"&gt;state.bind&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"size"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"range"&lt;/span&gt; &lt;span class="na"&gt;min=&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt; &lt;span class="na"&gt;max=&lt;/span&gt;&lt;span class="s"&gt;"20"&lt;/span&gt; &lt;span class="na"&gt;step=&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Introducing: Template filters
&lt;/h2&gt;

&lt;p&gt;The Modulo templating language has two core features: &lt;em&gt;filters&lt;/em&gt; (for formatting values), and &lt;em&gt;template-tags&lt;/em&gt; (for control-flow). We will learn the first of these now.&lt;/p&gt;

&lt;h3&gt;
  
  
  "No-filter", no longer!
&lt;/h3&gt;

&lt;p&gt;Template &lt;em&gt;filters&lt;/em&gt; "format" or otherwise transform template variables. The template filter syntax consists of taking a template variable and adding a vertical bar followed the name of a filter (e.g. &lt;code&gt;varName|filterName&lt;/code&gt;). The following example will transform the text contained in the &lt;code&gt;props.name&lt;/code&gt; template variable to make it all uppercase:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;Hello &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;props.name&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nf"&gt;upper&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Filters can be combined together, one after the other. Think of them like a "transformation pipeline". For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;Hello &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;props.name&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nf"&gt;upper&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nf"&gt;reversed&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  No argument from me
&lt;/h3&gt;

&lt;p&gt;Some filters can also take extra modifiers or options. This is called the template filter &lt;em&gt;argument&lt;/em&gt;. In this next snippet, see how the &lt;code&gt;|allow&lt;/code&gt; template filter ensures that only "circle" or "square" are permitted values for "shape":&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;strong&amp;gt;&lt;/span&gt;Shape:&lt;span class="nt"&gt;&amp;lt;/strong&amp;gt;&lt;/span&gt; &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.shape&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nf"&gt;allow&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"circle,square"&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note how the argument is separated from the filter with a colon: The general syntax is &lt;code&gt;varName|filterName:"argument"&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Built-in Filters and Custom Filters&lt;/strong&gt; - Modulo comes with many filters pre-installed: Read &lt;a href="///docs/templating/filters.html"&gt;Templating Reference - Built-In Filters&lt;/a&gt; for examples of all filters available. Utilizing JavaScript, you can also define custom filters. Read &lt;a href="///docs/templating/index.html#filters"&gt;Templating - Filters&lt;/a&gt; for more information.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Steps to add
&lt;/h2&gt;

&lt;p&gt;Let's get back at our component and spice it up with some filters:&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Using filters  - &lt;code&gt;|add&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Recall that the slider specied as 0-20 by the range allowed. Using the &lt;code&gt;|add&lt;/code&gt; filter lets us quickly do some math to add numbers, allowing for the padding to track at &lt;code&gt;2px&lt;/code&gt; bigger than &lt;code&gt;state.size&lt;/code&gt; (and thus be 2-22px range), while font-size will be &lt;code&gt;14px&lt;/code&gt; bigger (and thus 14-34px range):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;padding: &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.size&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;2&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;px;
font-size: &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.size&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;14&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;px;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4: Multiple filters  - &lt;code&gt;|add|multiply&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;As mentioned previously, we can also combine filters. For example, we may want border-radius to "grow" even faster than anything else. We can do that with the &lt;code&gt;|multiply:&lt;/code&gt; filter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;border-radius: &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.size&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nf"&gt;multiply&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;2&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;5&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;px;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;code&gt;&amp;lt;x-ButtonDesigner&amp;gt;&lt;/code&gt; - Complete Example
&lt;/h2&gt;

&lt;p&gt;Finally, we put everything together and slap on a &lt;em&gt;Style&lt;/em&gt; to make the labels line up, along with "for" attributes to make the labels correctly correspond to their inputs for accessibility, and we end up with the final results. Feel free to copy and paste the following to try it out:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;Modulo&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Component&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"ButtonDesigner"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;Template&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Label&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="err"&gt;[&lt;/span&gt;&lt;span class="na"&gt;state.bind&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"border"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Border&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;select&lt;/span&gt; &lt;span class="err"&gt;[&lt;/span&gt;&lt;span class="na"&gt;state.bind&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"border"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;option&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"solid"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Solid&lt;span class="nt"&gt;&amp;lt;/option&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;option&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"outset"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Outset&lt;span class="nt"&gt;&amp;lt;/option&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;option&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"groove"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Groove&lt;span class="nt"&gt;&amp;lt;/option&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;option&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"dashed"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Dashed&lt;span class="nt"&gt;&amp;lt;/option&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/select&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"color"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Color&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="err"&gt;[&lt;/span&gt;&lt;span class="na"&gt;state.bind&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"color"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"color"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"size"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Size&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="err"&gt;[&lt;/span&gt;&lt;span class="na"&gt;state.bind&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"size"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"range"&lt;/span&gt; &lt;span class="na"&gt;min=&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt; &lt;span class="na"&gt;max=&lt;/span&gt;&lt;span class="s"&gt;"20"&lt;/span&gt; &lt;span class="na"&gt;step=&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"
                    background: &lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.color&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;;
                    color: white;
                    padding: &lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.size&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;2&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;px;
                    font-size: &lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.size&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;14&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;px;
                    border-radius: &lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.size&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nf"&gt;multiply&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;2&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;5&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;px;
                    border: &lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.size&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;px &lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.border&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt; #88888888;
                "&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.text&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nf"&gt;capfirst&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/Template&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;State&lt;/span&gt;
            &lt;span class="na"&gt;size:=&lt;/span&gt;&lt;span class="s"&gt;10&lt;/span&gt;
            &lt;span class="na"&gt;border=&lt;/span&gt;&lt;span class="s"&gt;"solid"&lt;/span&gt;
            &lt;span class="na"&gt;color=&lt;/span&gt;&lt;span class="s"&gt;"#E66100"&lt;/span&gt;
            &lt;span class="na"&gt;text=&lt;/span&gt;&lt;span class="s"&gt;"click me"&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;gt;&amp;lt;/State&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;Style&amp;gt;&lt;/span&gt;
            label {
                min-width: 100px;
                display: inline-block;
            }
        &lt;span class="nt"&gt;&amp;lt;/Style&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/Component&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/mdu.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;x-ButtonDesigner&amp;gt;&amp;lt;/x-ButtonDesigner&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;In this section, we learned how to use &lt;code&gt;[state.bind]&lt;/code&gt; directive to all types of inputs.  We learned how to use Modulo's templating language to include variables and format values using filters. At this point, you've learned enough to be dangerous! In the next step, you'll learn more about more component render and CSS options, along with the first template tags, which will let you make useful, simple interactive widgets for websites. We're almost half way there, but have &lt;em&gt;A LOT&lt;/em&gt; more ground to cover! Be sure to follow for more tutorials like this, and, as always, feel free to ask questions or suggestions in the comments.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>javascript</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Learn state management by making a (silly) story generator (Learn Modulo.js - Part 3 of 10)</title>
      <dc:creator>michaelb</dc:creator>
      <pubDate>Tue, 17 Sep 2024 23:35:00 +0000</pubDate>
      <link>https://forem.com/michaelpb/learn-how-to-use-state-by-building-a-silly-story-generator-web-component-learn-modulojs-part-3-of-10-3gfc</link>
      <guid>https://forem.com/michaelpb/learn-how-to-use-state-by-building-a-silly-story-generator-web-component-learn-modulojs-part-3-of-10-3gfc</guid>
      <description>&lt;p&gt;👋 Welcome back! Didn't catch &lt;a href="https://dev.to/michaelpb/writing-your-first-web-component-learn-modulojs-part-1-of-10-4okh"&gt;Part 1&lt;/a&gt;? No worries, you can start at the beginning, or just plunge in here!&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing: The SillyStory Web Component
&lt;/h2&gt;

&lt;p&gt;Our task in this tutorial will be to build a story generating component. This will give us lots of practice with using &lt;em&gt;State&lt;/em&gt;. Last time we ended with a snippet a little like the one below. However, in this tutorial, we've changed the "Template" to show a silly story, generated by words given as Props. This allows the component to be "re-used" with different silly words. To begin this tutorial, copy and paste the following into a new file, and open in your browser:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;Modulo&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Component&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"SillyStory"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;Props&lt;/span&gt;
            &lt;span class="na"&gt;name&lt;/span&gt;
            &lt;span class="na"&gt;count&lt;/span&gt;
            &lt;span class="na"&gt;verb&lt;/span&gt;
            &lt;span class="na"&gt;animal&lt;/span&gt;
            &lt;span class="na"&gt;noun&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;gt;&amp;lt;/Props&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;Template&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Professor &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;props.name&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt; had over &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;props.count&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt; degrees in &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;props.noun&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;-&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;props.verb&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;ing from &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;props.name&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt; University. One day, the Professor decided to travel to &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;props.name&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt; City, a magical land filled with talking &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;props.animal&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;s.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;The quest was bold: The Professor was to teach &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;props.count&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt; &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;props.animal&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;s how to &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;props.verb&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt; a &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;props.noun&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/Template&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/Component&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/mdu.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;x-SillyStory&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"Nonsense"&lt;/span&gt; &lt;span class="na"&gt;count=&lt;/span&gt;&lt;span class="s"&gt;"one million"&lt;/span&gt; &lt;span class="na"&gt;verb=&lt;/span&gt;&lt;span class="s"&gt;"toot"&lt;/span&gt; &lt;span class="na"&gt;animal=&lt;/span&gt;&lt;span class="s"&gt;"duck"&lt;/span&gt; &lt;span class="na"&gt;noun=&lt;/span&gt;&lt;span class="s"&gt;"kazoo"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/x-SillyStory&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Introducing Part 3
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Froryqyq2mpfd7cybwhva.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Froryqyq2mpfd7cybwhva.png" alt="Image showing Dev Tools open on a silly story generator with the code of an input showing it on the screen" width="800" height="354"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This tutorial introduces one of the central concepts of not just Modulo, but many popular modern web frameworks, including React.js, Vue.js and others. This is the concept of &lt;em&gt;State&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;So far, our components have been static and unchanging. They can't do a lot. They might be useful for refactoring HTML into more D.R.Y. ("Don't Repeat Yourself"), reusable components, but not much more than that. They can't validate form data, use APIs, or be used in complete applications. In fact, they can't have any sort of &lt;em&gt;interaction&lt;/em&gt; whatsoever, or any &lt;em&gt;dynamic&lt;/em&gt; or changing content. We want &lt;em&gt;reactivity&lt;/em&gt; in our components.&lt;/p&gt;

&lt;p&gt;You can think of the concept of these &lt;em&gt;state variables&lt;/em&gt; as being like "buckets for data", or "blanks that can be filled in". They allow us to "give a name" to refer to data, allowing for more generic code and templates to be written. That way, your component can have changing content: Change the state, see the result!&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Adding a State part
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;State&lt;/em&gt; Component Parts are defined much like &lt;em&gt;Props&lt;/em&gt;, except that instead of just listing the attribute names, initial values must be provided as defaults. We can "transform" our &lt;em&gt;Props&lt;/em&gt; into &lt;em&gt;State&lt;/em&gt; like this:&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;State&lt;/span&gt;
    &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"Nonsense"&lt;/span&gt;
    &lt;span class="na"&gt;verb=&lt;/span&gt;&lt;span class="s"&gt;"toot"&lt;/span&gt;
    &lt;span class="na"&gt;noun=&lt;/span&gt;&lt;span class="s"&gt;"kazoo"&lt;/span&gt;
    &lt;span class="na"&gt;count=&lt;/span&gt;&lt;span class="s"&gt;"one hundred"&lt;/span&gt;
    &lt;span class="na"&gt;animal=&lt;/span&gt;&lt;span class="s"&gt;"duck"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&amp;lt;/State&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Include &lt;em&gt;State&lt;/em&gt; in your template
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;State&lt;/em&gt; can be inserted into your &lt;em&gt;Template&lt;/em&gt; just like &lt;em&gt;Props&lt;/em&gt;. In fact, all we need to do to get the previous example working again with our new-fangled &lt;em&gt;State&lt;/em&gt; part is to just change &lt;code&gt;props&lt;/code&gt; to &lt;code&gt;state&lt;/code&gt;, as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Template&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Professor &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.name&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt; had over &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.count&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt; degrees in &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.noun&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;-&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.verb&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;ing from &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.name&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt; University. One day, the Professor decided to travel to &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.name&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt; City, a magical land filled with talking &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.animal&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;s.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;The quest was bold: The Professor was to teach &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.count&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt; &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.animal&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;s how to &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.verb&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt; a &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.noun&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you perform these two steps correctly, your story generator will still work, except it won't need the attributes any more, since the data will come from "state". This means you should remember to delete them from the use of the component at the bottom, so it looks like: &lt;code&gt;&amp;lt;x-SillyStory&amp;gt;&amp;lt;/x-SillyStory&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing: The &lt;code&gt;state.bind&lt;/code&gt; directive
&lt;/h2&gt;

&lt;p&gt;So far, we can manually change state in the source code, but our app is still not interactive, since the actual users (that is, non-coders) cannot change the state.  This is where "binding" comes into play, where user input is "bound" to state, such that users of your app  can also modify state variables while using your app.&lt;/p&gt;

&lt;p&gt;To "bind", we'll need to use a &lt;em&gt;directive&lt;/em&gt;. A &lt;em&gt;directive&lt;/em&gt; is a type of HTML attribute. You can recognize &lt;em&gt;directive&lt;/em&gt; by spotting certain special characters in the attribute name. There are other directives, but for now, we'll only care about one directive: &lt;em&gt;[state.bind]&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;What does this mean? It will "sync up" the input with the state after every keystroke. The binding is "two-way": Modifying state modifies the input, and modifying the input modifies state. For example, &lt;code&gt;&amp;lt;input [state.bind] name="animal" /&amp;gt;&lt;/code&gt; is an &lt;code&gt;input&lt;/code&gt; HTML tag with a &lt;code&gt;[state.bind]&lt;/code&gt; directive. In this case, it will "bind" the input to the "animal" state variable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Bind our first input to state
&lt;/h3&gt;

&lt;p&gt;In our case, to add an labelled input that's bound to our &lt;em&gt;State&lt;/em&gt; variable "animal", we can do this:&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;Template&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&amp;lt;label&amp;gt;&lt;/span&gt;Animal: &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="err"&gt;[&lt;/span&gt;&lt;span class="na"&gt;state.bind&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"animal"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&amp;lt;/label&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- story goes here... --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Template&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;State&lt;/span&gt;
    &lt;span class="na"&gt;animal=&lt;/span&gt;&lt;span class="s"&gt;"ducks"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&amp;lt;/State&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4: Finishing up and testing it out
&lt;/h3&gt;

&lt;p&gt;Now, "rinse and repeat" for all the remaining inputs:&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;p&amp;gt;&amp;lt;label&amp;gt;&lt;/span&gt;Name: &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="err"&gt;[&lt;/span&gt;&lt;span class="na"&gt;state.bind&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&amp;lt;/label&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&amp;lt;label&amp;gt;&lt;/span&gt;Verb: &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="err"&gt;[&lt;/span&gt;&lt;span class="na"&gt;state.bind&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"verb"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&amp;lt;/label&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&amp;lt;label&amp;gt;&lt;/span&gt;Noun: &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="err"&gt;[&lt;/span&gt;&lt;span class="na"&gt;state.bind&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"noun"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&amp;lt;/label&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&amp;lt;label&amp;gt;&lt;/span&gt;Count: &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="err"&gt;[&lt;/span&gt;&lt;span class="na"&gt;state.bind&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"count"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&amp;lt;/label&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&amp;lt;label&amp;gt;&lt;/span&gt;Animal: &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="err"&gt;[&lt;/span&gt;&lt;span class="na"&gt;state.bind&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"animal"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&amp;lt;/label&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's how to test it out: First, make sure all the inputs start filled in (if you had a typo in a name, it could cause this to not show -- check the Dev Tools for errors!). Then, try editing each of your different inputs. Do you see how it "reacts" to your typing, automatically re-rendering each story as you type new silly words?&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;&amp;lt;x-SillyStory&amp;gt;&lt;/code&gt; - Complete Example
&lt;/h2&gt;

&lt;p&gt;Combining it all, we get the following (silly) results:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;Modulo&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Component&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"SillyStory"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;Template&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&amp;lt;label&amp;gt;&lt;/span&gt;Name: &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="err"&gt;[&lt;/span&gt;&lt;span class="na"&gt;state.bind&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&amp;lt;/label&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&amp;lt;label&amp;gt;&lt;/span&gt;Verb: &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="err"&gt;[&lt;/span&gt;&lt;span class="na"&gt;state.bind&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"verb"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&amp;lt;/label&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&amp;lt;label&amp;gt;&lt;/span&gt;Noun: &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="err"&gt;[&lt;/span&gt;&lt;span class="na"&gt;state.bind&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"noun"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&amp;lt;/label&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&amp;lt;label&amp;gt;&lt;/span&gt;Count: &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="err"&gt;[&lt;/span&gt;&lt;span class="na"&gt;state.bind&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"count"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&amp;lt;/label&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&amp;lt;label&amp;gt;&lt;/span&gt;Animal: &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="err"&gt;[&lt;/span&gt;&lt;span class="na"&gt;state.bind&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"animal"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&amp;lt;/label&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Professor &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.name&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt; had over &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.count&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt; degrees in &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.noun&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;-&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.verb&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;ing from &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.name&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt; University. One day, the Professor decided to travel to &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.name&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt; City, a magical land filled with talking &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.animal&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;s.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;The quest was bold: The Professor was to teach &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.count&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt; &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.animal&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;s how to &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.verb&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt; a &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.noun&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/Template&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;State&lt;/span&gt;
            &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"Nonsense"&lt;/span&gt;
            &lt;span class="na"&gt;verb=&lt;/span&gt;&lt;span class="s"&gt;"toot"&lt;/span&gt;
            &lt;span class="na"&gt;noun=&lt;/span&gt;&lt;span class="s"&gt;"kazoo"&lt;/span&gt;
            &lt;span class="na"&gt;count=&lt;/span&gt;&lt;span class="s"&gt;"one hundred"&lt;/span&gt;
            &lt;span class="na"&gt;animal=&lt;/span&gt;&lt;span class="s"&gt;"duck"&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;gt;&amp;lt;/State&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/Component&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/mdu.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;x-SillyStory&amp;gt;&amp;lt;/x-SillyStory&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  State &amp;amp; beyond
&lt;/h2&gt;

&lt;p&gt;Some food for thought: How can this be used in UI development? Think about &lt;em&gt;State&lt;/em&gt; in every day web applications: Forms, tabs, modal pop-up interfaces... Really, anything that is dynamic or reactive. All of these are &lt;em&gt;State&lt;/em&gt; changing. &lt;em&gt;State&lt;/em&gt; can hold CSS classes, CSS values, be bound to sliders and other types of inputs, and so much more! In other words, we have a lot more to cover on &lt;em&gt;State&lt;/em&gt;, but we'll save that for Part 4. Be sure to follow for more tutorials like this, and, as always, feel free to ask questions or suggestions in the comments.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Learn how to make a styled picture frame web component with props (Learn Modulo.js - Part 2 of 10)</title>
      <dc:creator>michaelb</dc:creator>
      <pubDate>Wed, 11 Sep 2024 17:36:00 +0000</pubDate>
      <link>https://forem.com/michaelpb/creating-a-styled-picture-frame-web-component-made-reusable-with-props-learn-modulojs-part-2-of-10-4lh1</link>
      <guid>https://forem.com/michaelpb/creating-a-styled-picture-frame-web-component-made-reusable-with-props-learn-modulojs-part-2-of-10-4lh1</guid>
      <description>&lt;p&gt;👋 Welcome back! Didn't catch &lt;a href="https://dev.to/michaelpb/writing-your-first-web-component-learn-modulojs-part-1-of-10-4okh"&gt;Part 1&lt;/a&gt;? No worries, you can start at the beginning, or just plunge in here!&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing: The PictureFrame Component
&lt;/h2&gt;

&lt;p&gt;Our task in this tutorial will be to build a picture frame component, for styling photographs on a web app. Last time we ended with a snippet a little like the one below. However, in this tutorial, we've changed the "Template" to show instead a pink/salmon "picture frame" of a hippo with a caption below it. To begin this tutorial, copy and paste the following into a new file, and open in your browser:&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;template&lt;/span&gt; &lt;span class="na"&gt;Modulo&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Component&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"PictureFrame"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;Template&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"display: inline-block; border: 10px inset salmon; padding: 10px; margin: 10px; width: 100px; background: pink;"&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="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"width: 50px;"&lt;/span&gt;
                    &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://upload.wikimedia.org/wikipedia/commons/thumb/3/33/Hippo_walking.jpg/320px-Hippo_walking.jpg"&lt;/span&gt;
                &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Photograph: &lt;span class="nt"&gt;&amp;lt;em&amp;gt;&lt;/span&gt;The Return of the Hippo&lt;span class="nt"&gt;&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/Template&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/Component&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/mdu.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;x-PictureFrame&amp;gt;&amp;lt;/x-PictureFrame&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Introducing Part 2
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fucnbn1kilabafzcz52l8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fucnbn1kilabafzcz52l8.png" alt="Viewing x-PictureFrame component, displaying a hippo and the source code showing corresponding attributes" width="800" height="354"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this tutorial, we'll add a &lt;em&gt;Style&lt;/em&gt; to plain HTML components, along with a discussion on the first core concept in the Modulo framework: Component Parts, before finally peeking at one more important component part: &lt;em&gt;Props&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;First, you might notice something messy about the above code. All the style is rammed into a &lt;code&gt;style=&lt;/code&gt; attribute! When coding CSS, placing all our styles in inline &lt;code&gt;style=&lt;/code&gt; attributes is often hard to maintain. Modulo supports the "Style" Component Part to let us write CSS code more naturally. What's a Component Part? Well, we'll get to that as well. First, let's get &lt;em&gt;stylish&lt;/em&gt;!&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Creating a Style Component Part
&lt;/h3&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;Template&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"salmon-frame"&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="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://upload.wikimedia.org/wikipedia/commons/thumb/3/33/Hippo_walking.jpg/320px-Hippo_walking.jpg"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Photograph: &lt;span class="nt"&gt;&amp;lt;em&amp;gt;&lt;/span&gt;The Return of the Hippo&lt;span class="nt"&gt;&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Template&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;Style&amp;gt;&lt;/span&gt;
    img {
        width: 50px;
    }
    .salmon-frame {
        display: inline-block;
        border: 10px inset salmon;
        padding: 10px;
        margin: 10px;
        width: 100px;
        background: pink;
    }
&lt;span class="nt"&gt;&amp;lt;/Style&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Much better! This will look and behave much like a "Style" tag in HTML, allowing you to create classes and selectors to your heart's content.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Styling the host component itself
&lt;/h3&gt;

&lt;p&gt;Often, you'll want to style the Web Component itself (in this case, the &lt;code&gt;&amp;lt;x-PictureFrame&amp;gt;&lt;/code&gt; tag). We can use the special &lt;code&gt;:host&lt;/code&gt; selector for this:&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;Style&amp;gt;&lt;/span&gt;
    :host {
        text-align: center;
    }
    /* ... etc ... */
&lt;span class="nt"&gt;&amp;lt;/Style&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Introducing Component Parts
&lt;/h2&gt;

&lt;p&gt;The central concept to Modulo is that of Component Parts. All component definitions consist of some number of Component Parts. Thus, a component definition is really just a collection of Component Part definitions. "Under the hood" of your component, each Component Part will have a different role to contribute to the functionality of your component.&lt;/p&gt;

&lt;p&gt;We've already learned the two most basic Component Part:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Template&lt;/strong&gt; - &lt;code&gt;&amp;lt;Template&amp;gt;&lt;/code&gt; - Templates are where you put any arbitrary HTML code that you want your component to contain. For now, we'll just include some unchanging HTML. In the next tutorial, we'll learn how to use "templating language" to control what HTML is produced in what circumstance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Style&lt;/strong&gt; - &lt;code&gt;&amp;lt;Style&amp;gt;&lt;/code&gt; - Just like the &lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt; tag in HTML. However, it has one one import distinction: The styles contained will be limited to your component. This is because CSS written here will be automatically prefixed so that it will only apply to your component and any HTML generated by the Template Component Part. This is quite useful: It allows us to write isolated CSS for each component without even thinking about it. Keeping our CSS separate means fewer unexpected interactions.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Keep in mind both &lt;em&gt;Style&lt;/em&gt; and &lt;em&gt;Template&lt;/em&gt; have a lot of configurable options, but for our usage, the default is good enough.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing Props
&lt;/h2&gt;

&lt;p&gt;Now, let's introduce a third important Component Part: &lt;em&gt;Props&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In the previous section, we were mostly concerned with defining components. Recall that components are defined once, but can be used many times. The purpose of Props is to allow more flexibility in that second step: Props Component Part defines the properties that can be customized about a component each time it is reused.&lt;/p&gt;

&lt;h2&gt;
  
  
  Props to us!
&lt;/h2&gt;

&lt;p&gt;Right now, our picture frame doesn't have a way to be re-used for different photos or captions. We can't just all be chased by hippos forever! 🦛🦛🦛&lt;/p&gt;

&lt;p&gt;We want to eventually be able to do something like this:&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;x-PictureFrame&lt;/span&gt;
    &lt;span class="na"&gt;image=&lt;/span&gt;&lt;span class="s"&gt;"https://upload.wikimedia.org/wikipedia/commons/thumb/3/33/Hippo_walking.jpg/320px-Hippo_walking.jpg"&lt;/span&gt;
    &lt;span class="na"&gt;caption=&lt;/span&gt;&lt;span class="s"&gt;"Hippopotamus out of water"&lt;/span&gt;
    &lt;span class="na"&gt;photographer=&lt;/span&gt;&lt;span class="s"&gt;"Lee R. Berger"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&amp;lt;/x-PictureFrame&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, it'd feel like a "real" HTML tag -- that is, configurable via attributes.  Let's "peel back the layers" and examine out how this can be accomplished using &lt;em&gt;Props&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Adding Props
&lt;/h3&gt;

&lt;p&gt;In order for a component to be able to "receive" props when it is reused, we must define Props. Props definitions are like previous definitions, except they have no contents and are just an opening tag with attributes, followed by a closing tag. See the following:&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;Props&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;
    &lt;span class="na"&gt;caption&lt;/span&gt;
    &lt;span class="na"&gt;photographer&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&amp;lt;/Props&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: A common mistake is to forget to include &lt;em&gt;Props&lt;/em&gt;. Every attribute you expect your component to receive must be listed in &lt;em&gt;Props&lt;/em&gt; to be available for the next step.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Using Props in Template
&lt;/h3&gt;

&lt;p&gt;Now, we'll get our first sneak peak at the true power of &lt;em&gt;Templates&lt;/em&gt;: Adding in data and values into your HTML. You can use the following syntax to get your "props" and inject them into the generated HTML:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"salmon-frame"&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="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;props.image&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Photograph: &lt;span class="nt"&gt;&amp;lt;em&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;props.caption&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Photographer: &lt;span class="nt"&gt;&amp;lt;em&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;props.photographer&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note the &lt;code&gt;{{&lt;/code&gt; and &lt;code&gt;}}&lt;/code&gt;: This the &lt;em&gt;templating syntax&lt;/em&gt; that indicates where the "props" values get inserted.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;&amp;lt;x-PictureFrame&amp;gt;&lt;/code&gt; - Complete Example
&lt;/h2&gt;

&lt;p&gt;Combining it all, we get the following results. Note how our custom Web Component can be re-used with different attributes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;Modulo&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Component&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"PictureFrame"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;Props&lt;/span&gt;
            &lt;span class="na"&gt;image&lt;/span&gt;
            &lt;span class="na"&gt;caption&lt;/span&gt;
            &lt;span class="na"&gt;photographer&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;gt;&amp;lt;/Props&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;Template&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"salmon-frame"&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="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;props.image&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Photograph: &lt;span class="nt"&gt;&amp;lt;em&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;props.caption&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Photographer: &lt;span class="nt"&gt;&amp;lt;em&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;props.photographer&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/Template&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;Style&amp;gt;&lt;/span&gt;
            :host {
                text-align: center;
            }
            img {
                width: 130px;
            }
            .salmon-frame {
                display: inline-block;
                border: 10px inset salmon;
                padding: 10px;
                margin: 10px;
                width: 200px;
                background: pink;
            }
        &lt;span class="nt"&gt;&amp;lt;/Style&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/Component&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/mdu.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Learn Modulo.js: Part 2&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;Style and Props&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;x-PictureFrame&lt;/span&gt;
    &lt;span class="na"&gt;image=&lt;/span&gt;&lt;span class="s"&gt;"https://upload.wikimedia.org/wikipedia/commons/thumb/3/33/Hippo_walking.jpg/320px-Hippo_walking.jpg"&lt;/span&gt;
    &lt;span class="na"&gt;caption=&lt;/span&gt;&lt;span class="s"&gt;"Hippopotamus out of water"&lt;/span&gt;
    &lt;span class="na"&gt;photographer=&lt;/span&gt;&lt;span class="s"&gt;"Lee R. Berger"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&amp;lt;/x-PictureFrame&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;That's all for Part 2! Be sure to follow to catch the rest, and, as always, feel free to ask questions or suggestions in the comments.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Writing your first web component (Learn Modulo.js - Part 1 of 10)</title>
      <dc:creator>michaelb</dc:creator>
      <pubDate>Thu, 05 Sep 2024 17:37:00 +0000</pubDate>
      <link>https://forem.com/michaelpb/writing-your-first-web-component-learn-modulojs-part-1-of-10-4okh</link>
      <guid>https://forem.com/michaelpb/writing-your-first-web-component-learn-modulojs-part-1-of-10-4okh</guid>
      <description>&lt;p&gt;👋 Welcome, all new subscribers and returning component coders! I'm kicking off a new 10 part tutorial series. While my other tutorials have used Modulo.js to build specific, fun little apps like &lt;a href="https://dev.to/michaelpb/how-to-build-an-api-driven-pokemon-dance-party-component-in-less-than-30-lines-of-html-web-component-template-code-modulojs-3c2g"&gt;pokemon dance parties&lt;/a&gt;, &lt;a href="https://dev.to/michaelpb/creating-a-3d-extruded-text-word-art-picker-in-only-30-lines-of-pure-html-web-component-code-1-extra-file-3b86"&gt;retro extruded text editors&lt;/a&gt;, or &lt;a href="https://dev.to/michaelpb/learn-how-to-create-a-api-backed-zelda-botw-monster-gallery-web-component-in-40-lines-modulojs-10eb"&gt;video game galleries&lt;/a&gt;, this tutorial series will build up on basic principals, starting from square one: &lt;em&gt;What is a Web Component?&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Next Step After HTML and CSS
&lt;/h2&gt;

&lt;p&gt;Have you just learned the basics of HTML and CSS, and are curious about going taking the next step, and want to build bigger and more complete web applications? Or, are you already a web developer or JavaScript pro, and just want to build quick and light web apps without too much bloat, tooling, or excess dependencies?&lt;/p&gt;

&lt;p&gt;If so, Web Components are for you! They let you create reusable portions of code. By taking this tutorial, you'll learn how to fix repetitive, difficult-to-maintain HTML and CSS. It also uses only minimal tools and libraries, meaning you won't need Node.js, NPM, or a massive &lt;code&gt;node_modules&lt;/code&gt;. It also lets you hone your skills in modern frontend web development: In the future tutorials in this series, you'll learn concepts like &lt;em&gt;slots&lt;/em&gt;, &lt;em&gt;shadowDOM&lt;/em&gt;, &lt;em&gt;props&lt;/em&gt;, &lt;em&gt;templating&lt;/em&gt;, &lt;em&gt;state management&lt;/em&gt;, and more! These are concepts that are transferable to use other popular frameworks, and Modulo's simple, declarative approach could be a more inviting way to learn the core concepts without getting bogged down in complex setup. &lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing the Modulo Framework
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What is Modulo?&lt;/strong&gt;  Modulo is a free software / open source, small-but-mighty web framework written in JavaScript. It has no dependencies, and uses HTML syntax so it can set itself up on page load, with no need for Node.js or compilation. You can use it in a plain HTML "static site" (e.g. when you assemble HTML, CSS, and other static assets in a directory to launch on a static web host), or any other existing web app. This tutorial is about using Modulo as a tool to build Web Components.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing Part 1
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw5lijv77z68q3yik5vd6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw5lijv77z68q3yik5vd6.png" alt="Viewing source of x-HelloWorld in Dev tools" width="800" height="354"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In Part 1, we'll learn how to build a simple "Hello World" component. In future parts, we'll learn how to add in Style, Props, State, reactive forms, slots, APIs, and so much more, but for now, we'll start with the basics: &lt;strong&gt;Going beyond basic HTML and CSS by creating and re-using a Web Component with Modulo.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Including Modulo
&lt;/h3&gt;

&lt;p&gt;Before we can use Modulo, we'll have to include the framework. The entire framework is contained in "Modulo.js", a file containing 2000-lines of JavaScript. &lt;strong&gt;This means that starting a Modulo project requires &lt;em&gt;literally no dependencies&lt;/em&gt; beyond your browser and editor.&lt;/strong&gt; So, just open up a blank HTML file and get going with the following very simple starter code:&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;template&lt;/span&gt; &lt;span class="na"&gt;Modulo&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- our stuff will go here eventually... --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/mdu.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Defining your first component
&lt;/h3&gt;

&lt;p&gt;Now that we have included it, we can start writing &lt;em&gt;Modulo definitions&lt;/em&gt; and use the framework in general. We define our first component by creating a Modulo &lt;code&gt;&amp;lt;Component ...&amp;gt;&lt;/code&gt; definition, and putting inside of it a &lt;code&gt;&amp;lt;Template&amp;gt;&lt;/code&gt; definition, as below:&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;Component&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"HelloWorld"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Template&amp;gt;&lt;/span&gt;
        Hello &lt;span class="nt"&gt;&amp;lt;strong&amp;gt;&lt;/span&gt;Modulo&lt;span class="nt"&gt;&amp;lt;/strong&amp;gt;&lt;/span&gt; World!
    &lt;span class="nt"&gt;&amp;lt;/Template&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Component&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This "Template" thus becomes the "template" for our component: Every time our component shows up on the page, it will render the given template inside of it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Using your first component
&lt;/h3&gt;

&lt;p&gt;Once defined, you can use a component by referring to it's name as though it were a plain HTML tag:&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;x-HelloWorld&amp;gt;&amp;lt;/x-HelloWorld&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will cause the following to show on the screen:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Hello &lt;strong&gt;Modulo&lt;/strong&gt; World!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Note that once registered, components can go anywhere that plain HTML tags can go, and can be styled with CSS the same way as well. In other words, creating a component is like creating a brand-new type of HTML tag that can be used anywhere, just like the original HTML tags of &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt;, etc. For example, we can put our component into other tags like this:&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;p&amp;gt;&lt;/span&gt;One time: &lt;span class="nt"&gt;&amp;lt;x-HelloWorld&amp;gt;&amp;lt;/x-HelloWorld&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;Another time: &lt;span class="nt"&gt;&amp;lt;x-HelloWorld&amp;gt;&amp;lt;/x-HelloWorld&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4: Enhancing your first component
&lt;/h3&gt;

&lt;p&gt;The "Template" can have more advanced code if we want. We can mix in CSS and classes. For example:&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;Component&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"HelloWorld"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Template&amp;gt;&lt;/span&gt;
        Hello &lt;span class="nt"&gt;&amp;lt;strong&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"color: goldenrod"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Modulo&lt;span class="nt"&gt;&amp;lt;/strong&amp;gt;&lt;/span&gt; World!
        &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"neat"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Any HTML can be here!&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/Template&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Component&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that if you use the &lt;code&gt;.neat&lt;/code&gt; selector in your CSS, this will apply to that span element, just like normal.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;&amp;lt;x-HelloWorld&amp;gt;&lt;/code&gt; - Complete Example
&lt;/h2&gt;

&lt;p&gt;Combining it all, we get the following results. Note how our custom Web Component can be used and re-used as though it were a normal, HTML tag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;Modulo&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Component&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"HelloWorld"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;Template&amp;gt;&lt;/span&gt;
            Hello &lt;span class="nt"&gt;&amp;lt;strong&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"color: goldenrod"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Modulo&lt;span class="nt"&gt;&amp;lt;/strong&amp;gt;&lt;/span&gt; World!
            &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"neat"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Any HTML can be here!&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/Template&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/Component&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/mdu.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Learning Modulo Part 1&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;Your first Web Component&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;main&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"border: 3px solid violet; padding: 10px; margin: 10px; border-radius: 3px"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;section&amp;gt;&lt;/span&gt;One time: &lt;span class="nt"&gt;&amp;lt;x-HelloWorld&amp;gt;&amp;lt;/x-HelloWorld&amp;gt;&amp;lt;/section&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;Another time: &lt;span class="nt"&gt;&amp;lt;x-HelloWorld&amp;gt;&amp;lt;/x-HelloWorld&amp;gt;&amp;lt;/div&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;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;That's all for Part 1! There's another 9 parts to go, so follow for more tutorials like this, and, as always, feel free to ask questions or suggestions in the comments. Next time... we're getting &lt;em&gt;stylish&lt;/em&gt;!&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>javascript</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Learn how to create a API-backed Zelda BOTW monster gallery web component in &lt;40 lines (Modulo.js)</title>
      <dc:creator>michaelb</dc:creator>
      <pubDate>Mon, 02 Sep 2024 20:12:12 +0000</pubDate>
      <link>https://forem.com/michaelpb/learn-how-to-create-a-api-backed-zelda-botw-monster-gallery-web-component-in-40-lines-modulojs-10eb</link>
      <guid>https://forem.com/michaelpb/learn-how-to-create-a-api-backed-zelda-botw-monster-gallery-web-component-in-40-lines-modulojs-10eb</guid>
      <description>&lt;h2&gt;
  
  
  Modulo tutorials are back!
&lt;/h2&gt;

&lt;p&gt;Hey all! I'm back with Modulo tutorials after a summer hiatus. I've got a bunch more tutorials in the works -- so stay tuned. That said, if you have any particular ideas for my next topic, be sure to let me know in the comments!&lt;/p&gt;

&lt;p&gt;My last tutorial was a super quick and fun "HTML-only, no-JS" tutorial on &lt;a href="https://dev.to/michaelpb/how-to-build-an-api-driven-pokemon-dance-party-component-in-less-than-30-lines-of-html-web-component-template-code-modulojs-3c2g"&gt;API-driven Pokémon Dance Party component in less than 30 lines of HTML Web Component code&lt;/a&gt;. Some of my previous tutorials were a bit more serious, such as &lt;a href="https://dev.to/michaelpb/the-2000-line-framework-challenge-how-to-split-state-when-using-global-stores-with-no-extra-dependencies-beyond-modulojs-4o80"&gt;this more advanced tutorial on managing private and public state&lt;/a&gt;. If that sounds a little dry, then you're in luck, because today's tutorial is another fun one, and about yet another beloved video game... Zelda: Breath of the Wild!&lt;/p&gt;

&lt;p&gt;Of course, as always, the techniques learned in this tutorial are applicable to any API, so keep on reading to learn more about an API-driven gallery!&lt;/p&gt;

&lt;h2&gt;
  
  
  How to use the Hyrule Compendium API
&lt;/h2&gt;

&lt;p&gt;This tutorial is 100% thanks to the wonderful Aarav Borthakur's free, MIT-licensed, and generously hosted &lt;a href="https://github.com/gadhagod/Hyrule-Compendium-API" rel="noopener noreferrer"&gt;Hyrule Compendium API&lt;/a&gt;, which is a fun, fan-maintained database and API for retrieval of Zelda: Breath of the Wild franchise information and media. We will be using the "Monsters" endpoint, available here: &lt;a href="https://botw-compendium.herokuapp.com/api/v3/compendium/category/monsters" rel="noopener noreferrer"&gt;https://botw-compendium.herokuapp.com/api/v3/compendium/category/monsters&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Screenshot
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fun8unqtsqnxczwf56cna.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fun8unqtsqnxczwf56cna.png" alt="A screenshot of a gallery of Zelda monster images, with a description of " width="800" height="338"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try it out now, in less than 30 seconds:&lt;/strong&gt; 🚀🚀🚀 Wanna skip ahead? Scroll to the end and copy the 39 lines of HTML code into any local HTML file, and then open it in your browser. Modulo has no dependencies and even runs embedded in local HTML files, so it's really that easy!&lt;/p&gt;




&lt;h2&gt;
  
  
  Start with the data
&lt;/h2&gt;

&lt;p&gt;Let's start with just 6 lines of code, with a &lt;code&gt;StaticData&lt;/code&gt; and a &lt;code&gt;Template&lt;/code&gt; to display it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Template&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;pre&amp;gt;&lt;/span&gt;API DATA: &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;staticdata&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;2&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/pre&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Template&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;StaticData&lt;/span&gt;
  &lt;span class="na"&gt;-src=&lt;/span&gt;&lt;span class="s"&gt;"https://botw-compendium.herokuapp.com/api/v3/compendium/category/monsters"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&amp;lt;/StaticData&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this snippet, we have a very simple, one-line &lt;code&gt;&amp;lt;Template&amp;gt;&lt;/code&gt; that dumps the &lt;code&gt;staticdata.data&lt;/code&gt; property of the returned Hyrule Compendium API. We apply the &lt;code&gt;|json:2&lt;/code&gt; filter to display it in a more readable format. The &lt;code&gt;StaticData&lt;/code&gt; supports JSON (among other formats) out of the box, you just give it the URL to the API and you can then start using the data. Is &lt;code&gt;StaticData&lt;/code&gt; confusing? Try this tutorial &lt;a href="https://dev.to/michaelpb/the-2000-line-framework-challenge-how-to-template-json-or-apis-in-3-lines-of-component-code-1-extra-file-no-npm-needed-3771"&gt;on integrating the GitHub API&lt;/a&gt;, or the play around with the interactive examples in &lt;a href="https://modulojs.org/tutorial/ramping-up/part4.html#staticdata" rel="noopener noreferrer"&gt;the "StaticData" section of the tutorial&lt;/a&gt; of the Modulo.js tutorial.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try running that snippet.&lt;/strong&gt; See the resulting data? We'll need to loop through that with a &lt;em&gt;for loop&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating an image gallery
&lt;/h2&gt;

&lt;p&gt;Now that we can see that an attribute &lt;code&gt;.data&lt;/code&gt; contains an  &lt;em&gt;Array&lt;/em&gt; of &lt;em&gt;Objects&lt;/em&gt;, let's loop through it and generate a gallery:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Template&amp;gt;&lt;/span&gt;
    &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nv"&gt;monster&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;staticdata.data&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;monster.image&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"width: 200px;"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endfor&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will generate many &lt;code&gt;img&lt;/code&gt; tags, each with a &lt;code&gt;src=&lt;/code&gt; assigned to the "image" properties of the &lt;em&gt;Objects&lt;/em&gt; in the original JSON &lt;em&gt;Array&lt;/em&gt;, and the &lt;code&gt;{% for %}&lt;/code&gt; template-tag is the syntax to duplicate a bit of HTML for every item in the array (not to mention each &lt;em&gt;index&lt;/em&gt;, e.g. a number counting up from 0). For further practice, the for-loop has lots of interactive examples in &lt;a href="https://modulojs.org/tutorial/ramping-up/part4.html#theforlooptemplatetag" rel="noopener noreferrer"&gt;part 4 of the Modulo.js tutorial&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating State and Script
&lt;/h2&gt;

&lt;p&gt;The next most important thing to do is create a new Script tag, which we can use to write a simple, one-line JavaScript function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;State&lt;/span&gt;
    &lt;span class="na"&gt;selected:=&lt;/span&gt;&lt;span class="s"&gt;null&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&amp;lt;/State&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;Script&amp;gt;&lt;/span&gt;
    function select(payload) {
        state.selected = payload;
    }
&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;This is a core technique for scripting while using Modulo: Create functions that let you modify state using JavaScript. In this case, it does a very simple operation: "Save this monster for later". More precisely, it assigns the state variable "selected" to the given payload. This way, the state variable "selected" becomes a sort of "stash" for whatever monster was just picked from the API.&lt;/p&gt;

&lt;h2&gt;
  
  
  Attaching the click event
&lt;/h2&gt;

&lt;p&gt;Now, let's add another piece of the puzzle: Attaching the click event. See below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&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;click:=&lt;/span&gt;&lt;span class="s"&gt;script.select&lt;/span&gt; &lt;span class="na"&gt;payload:=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;monster&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;"&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;This was done with the event attachment syntax (&lt;code&gt;@click:=&lt;/code&gt;, in this&lt;br&gt;
case), and a payload attribute, that lets us pass along the monster we are choosing by clicking this image. Events and Script tags can be a confusing topics if you are new to JavaScript (and even if you aren't!), so peruse &lt;a href="https://modulojs.org/tutorial/ramping-up/part5.html" rel="noopener noreferrer"&gt;the examples on this page&lt;/a&gt; for more examples of using Script component parts and attaching events.&lt;/p&gt;
&lt;h2&gt;
  
  
  Attaching the click event
&lt;/h2&gt;

&lt;p&gt;Finally, let's conditionally render the monster info when a monster is selected:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;state.selected&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.selected.name&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nf"&gt;capfirst&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.selected.image&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.selected.description&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Welcome to Hyrule Monster Guide!&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;&lt;/span&gt;&lt;span class="ni"&gt;&amp;amp;larr;&lt;/span&gt; Select a monster to learn more&lt;span class="nt"&gt;&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endif&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will initially show the "Welcome" message (since state.selected begins as &lt;code&gt;null&lt;/code&gt;). Then, as soon as someone clicks on a monster image, the &lt;code&gt;state.selected&lt;/code&gt; variable will no longer be &lt;code&gt;null&lt;/code&gt;, and&lt;br&gt;
instead the contents will displayed formatted with &lt;code&gt;h1&lt;/code&gt; and &lt;code&gt;p&lt;/code&gt; tags, with some tweaks applied (&lt;code&gt;|capfirst&lt;/code&gt; makes the first letter capital).&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;code&gt;&amp;lt;x-MonsterGuide&amp;gt;&lt;/code&gt; - Embeddable snippet
&lt;/h2&gt;

&lt;p&gt;Combining it all, we then wrap everything in a &lt;code&gt;display: grid&lt;/code&gt; to make the side-by-side layout, and a &lt;code&gt;overflow: auto&lt;/code&gt; to the left div the scrollbar. Finally, we can add a few final CSS tweaks to the second div (&lt;code&gt;padding&lt;/code&gt;, &lt;code&gt;margin&lt;/code&gt;, and a &lt;code&gt;linear-gradient&lt;/code&gt;), and we get the following results that can be embedded anywhere:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;Modulo&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Component&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"MonsterGuide"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;Template&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;main&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"display: grid; grid-template-columns: 2fr 1fr"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"overflow: auto; height: 95vh;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nv"&gt;monster&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;staticdata.data&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;monster.image&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
                            &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;click:=&lt;/span&gt;&lt;span class="s"&gt;script.select&lt;/span&gt; &lt;span class="na"&gt;payload:=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;monster&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
                            &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"width: 200px;"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
                    &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endfor&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"padding: 10px; margin: 10px; background: linear-gradient(to bottom, lightyellow, goldenrod);"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;state.selected&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.selected.name&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nf"&gt;capfirst&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.selected.image&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.selected.description&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
                    &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Welcome to Hyrule Monster Guide!&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;&lt;/span&gt;&lt;span class="ni"&gt;&amp;amp;larr;&lt;/span&gt; Select a monster to learn more&lt;span class="nt"&gt;&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
                    &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endif&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/div&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;/Template&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;State&lt;/span&gt;
            &lt;span class="na"&gt;selected:=&lt;/span&gt;&lt;span class="s"&gt;null&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;gt;&amp;lt;/State&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;StaticData&lt;/span&gt;
            &lt;span class="na"&gt;-src=&lt;/span&gt;&lt;span class="s"&gt;"https://botw-compendium.herokuapp.com/api/v3/compendium/category/monsters"&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;gt;&amp;lt;/StaticData&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;Script&amp;gt;&lt;/span&gt;
            function select(payload) {
                state.selected = payload;
            }
        &lt;span class="nt"&gt;&amp;lt;/Script&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/Component&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/mdu.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;x-MonsterGuide&amp;gt;&amp;lt;/x-MonsterGuide&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I hope you enjoyed this tutorial, if so, follow for more like this!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>beginners</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to build an API-driven Pokémon Dance Party component in less than 30 lines of HTML Web Component template code (+ Modulo.js)</title>
      <dc:creator>michaelb</dc:creator>
      <pubDate>Sat, 23 Mar 2024 02:42:38 +0000</pubDate>
      <link>https://forem.com/michaelpb/how-to-build-an-api-driven-pokemon-dance-party-component-in-less-than-30-lines-of-html-web-component-template-code-modulojs-3c2g</link>
      <guid>https://forem.com/michaelpb/how-to-build-an-api-driven-pokemon-dance-party-component-in-less-than-30-lines-of-html-web-component-template-code-modulojs-3c2g</guid>
      <description>&lt;p&gt;Hey everyone! Are you excited about anything this beautiful Spring Friday? I am excited to be back to writing another tutorial after a month-long hiatus... and also excited to make it about one of my favorite video games of all time: Pokémon! As always, if you have an idea for a next topic, be sure to let me know in the comments!&lt;/p&gt;

&lt;h2&gt;
  
  
  "HTML-only, no JS!" ✨🪄
&lt;/h2&gt;

&lt;p&gt;In previous tutorials, I focused more on design: I showed how to make a simple &lt;a href="https://dev.to/michaelpb/the-2000-line-framework-challenge-making-a-gradient-picker-tool-in-13-lines-of-pure-html-code-1-extra-file-no-node-or-js-2jb1"&gt;gradient picker&lt;/a&gt;, or &lt;a href="https://dev.to/michaelpb/creating-a-3d-extruded-text-word-art-picker-in-only-30-lines-of-pure-html-web-component-code-1-extra-file-3b86"&gt;a more flashy 3D extruded text art effect&lt;/a&gt;, all written in pure HTML and templating, leaving the JS heavy-lifting to the framework.&lt;/p&gt;

&lt;p&gt;Today's tutorial takes a very different approach: It shows how you can quickly display public "web APIs" (that is, public data sets or web services) with just a few lines of code.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to use the PokéAPI
&lt;/h2&gt;

&lt;p&gt;This tutorial is 100% thanks to &lt;a href="https://pokeapi.co/" rel="noopener noreferrer"&gt;PokéAPI&lt;/a&gt;, which is a fun, fan-maintained database and API for retrieval of Pokémon franchise information and media. For example, this link provides info in JSON format for my favorite pink puff: &lt;a href="https://pokeapi.co/api/v2/pokemon/jigglypuff" rel="noopener noreferrer"&gt;https://pokeapi.co/api/v2/pokemon/jigglypuff&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The final result
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fci6tnn91lsek6eqmdfjp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fci6tnn91lsek6eqmdfjp.png" alt="A screenshot of eight dancing Jigglypuffs on a web page with the title " width="629" height="413"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Try it out now, in less than 30 seconds:&lt;/strong&gt; 🚀🚀🚀 Wanna skip ahead? Scroll to the end and copy the ~30 lines of HTML code into any local HTML file, and then open it in your browser. Modulo is a single-file framework with no dependencies and even runs embedded in local HTML files, so it's really that easy!&lt;/p&gt;

&lt;h2&gt;
  
  
  Starting with a basic H1 and StaticData
&lt;/h2&gt;

&lt;p&gt;Let's start with something super basic: Let's get info from the API. We can start with &lt;code&gt;&amp;lt;Template&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;StaticData&amp;gt;&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Template&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;staticdata.name&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nf"&gt;capfirst&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt; Party!&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Template&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;StaticData&lt;/span&gt;
  &lt;span class="na"&gt;-src=&lt;/span&gt;&lt;span class="s"&gt;"https://pokeapi.co/api/v2/pokemon/jigglypuff"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&amp;lt;/StaticData&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this snippet, we have a very simple, one-line &lt;code&gt;&amp;lt;Template&amp;gt;&lt;/code&gt; that shows the &lt;code&gt;name&lt;/code&gt; property of the returned PokéAPI. We apply the &lt;code&gt;|capfirst&lt;/code&gt; filter to capitalize it (it is all-lowercase by default). The &lt;code&gt;StaticData&lt;/code&gt; supports JSON (among other formats) out of the box, which means all it needs is the URL to the API and it will integrate it into your component. If the &lt;code&gt;StaticData&lt;/code&gt; concept is giving you conceptual trouble, try this tutorial &lt;a href="https://dev.to/michaelpb/the-2000-line-framework-challenge-how-to-template-json-or-apis-in-3-lines-of-component-code-1-extra-file-no-npm-needed-3771"&gt;on integrating the GitHub API&lt;/a&gt;, or the play around with the interactive examples in &lt;a href="https://modulojs.org/tutorial/ramping-up/part4.html" rel="noopener noreferrer"&gt;Part 4&lt;/a&gt; of the Modulo.js tutorial.&lt;/p&gt;

&lt;h2&gt;
  
  
  Looping through generations and the games
&lt;/h2&gt;

&lt;p&gt;We have to write 2 for loops now: One for the generations, and one for the games.&lt;/p&gt;

&lt;p&gt;How did I figure this out? I clicked through the results of the API, and deduced that &lt;code&gt;.sprites&lt;/code&gt;, and specifically &lt;code&gt;.sprites.versions&lt;/code&gt; has all the "generations" of games in the JSON &lt;em&gt;Object&lt;/em&gt; data structure. This is where the data gets tricky, since it's not accessible "at the top level" (like &lt;code&gt;.name&lt;/code&gt;). We'll need to "drill down" to the right data.&lt;/p&gt;

&lt;p&gt;So, nesting the two &lt;code&gt;for-loops&lt;/code&gt;, we get:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nv"&gt;generation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;games&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;staticdata.sprites.versions&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
    &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nv"&gt;game&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;images&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;games&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Showing the &lt;code&gt;front_default&lt;/code&gt; image in the loop
&lt;/h2&gt;

&lt;p&gt;Finally, we'll need to reference the &lt;code&gt;front_default&lt;/code&gt; image in an &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tag to display it. See below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nv"&gt;generation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;games&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;staticdata.sprites.versions&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
    &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nv"&gt;game&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;images&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;games&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;images.front_default&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"dancing-image"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endfor&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endfor&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;{% for %}&lt;/code&gt; loop repeats the HTML code contained within. This is how it "duplicates" the &lt;code&gt;&amp;lt;img src="..."&amp;gt;&lt;/code&gt; over and over to show all the images. For more practice on &lt;code&gt;{% for %}&lt;/code&gt; loops, play around with the &lt;a href="https://modulojs.org/docs/templating/tags.html#for" rel="noopener noreferrer"&gt;interactive examples in the documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding the CSS animation
&lt;/h2&gt;

&lt;p&gt;Finally, to wrap this up, we'll need to make 'em dance! I made a "PokeDance" animation, which rocks back and forth, notably making the &lt;code&gt;transform-origin: bottom center&lt;/code&gt; to make it look like their "center of gravity" is at the bottom (at their feet), as such:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;.dancing-image {
    transform-origin: bottom center;
    animation: PokeDance 3s ease-in-out infinite alternate;
    width: 200px;
}
@keyframes PokeDance {
   20% { transform: rotate(15deg); }    
   40% { transform: rotate(-10deg); }
   60% { transform: rotate(5deg); } 
   80% { transform: rotate(-5deg); }    
  100% { transform: rotate(10deg); }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;code&gt;&amp;lt;x-PokeParty&amp;gt;&lt;/code&gt; - Embeddable snippet
&lt;/h2&gt;

&lt;p&gt;Combining it all, and adding a few final tweaks (the &lt;code&gt;title&lt;/code&gt; on the image, and a tweak of adding &lt;code&gt;-auto-isolate:=false&lt;/code&gt; to prevent &lt;code&gt;PokeDance&lt;/code&gt; animation from being modified), we get the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;Modulo&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Component&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"PokeParty"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;Template&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;staticdata.name&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nf"&gt;capfirst&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt; Party!&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
            &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nv"&gt;generation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;games&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;staticdata.sprites.versions&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
                &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nv"&gt;game&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;images&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;games&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"dancing-image"&lt;/span&gt;
                        &lt;span class="na"&gt;title=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;generation&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;game&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
                        &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;images.front_default&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endfor&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
            &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endfor&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/Template&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;StaticData&lt;/span&gt;
            &lt;span class="na"&gt;-src=&lt;/span&gt;&lt;span class="s"&gt;"https://pokeapi.co/api/v2/pokemon/bellsprout"&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;gt;&amp;lt;/StaticData&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;Style&lt;/span&gt; &lt;span class="na"&gt;-auto-isolate:=&lt;/span&gt;&lt;span class="s"&gt;false&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            .dancing-image {
                transform-origin: bottom center;
                  animation: PokeDance 3s ease-in-out infinite alternate;
                  width: 200px;
            }
            @keyframes PokeDance {
                 20% { transform: rotate(15deg); }  
                 40% { transform: rotate(-10deg); }
                 60% { transform: rotate(5deg); }   
                 80% { transform: rotate(-5deg); }  
                100% { transform: rotate(10deg); }
            }
        &lt;span class="nt"&gt;&amp;lt;/Style&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/Component&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/mdu.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;x-PokeParty&amp;gt;&amp;lt;/x-PokeParty&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>javscript</category>
      <category>webdev</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Creating a 3D extruded text Word Art picker in only ~30 lines of pure HTML web component code + 1 extra file</title>
      <dc:creator>michaelb</dc:creator>
      <pubDate>Sat, 27 Jan 2024 15:09:12 +0000</pubDate>
      <link>https://forem.com/michaelpb/creating-a-3d-extruded-text-word-art-picker-in-only-30-lines-of-pure-html-web-component-code-1-extra-file-3b86</link>
      <guid>https://forem.com/michaelpb/creating-a-3d-extruded-text-word-art-picker-in-only-30-lines-of-pure-html-web-component-code-1-extra-file-3b86</guid>
      <description>&lt;h2&gt;
  
  
  "HTML-only, no JS!" ✨🪄
&lt;/h2&gt;

&lt;p&gt;Hey all! Today's Modulo.js tutorial will be another "HTML-only, no JS" tutorial. The 2000-line, small-but-mighty Modulo framework adds just enough JS magic that we can build these cool design tools in pure HTML. &lt;strong&gt;Have an idea for a next topic? Be sure to let me know in the comments!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In previous tutorials, I covered topics like &lt;a href="https://dev.to/michaelpb/the-2000-line-framework-challenge-how-to-template-json-or-apis-in-3-lines-of-component-code-1-extra-file-no-npm-needed-3771"&gt;adding an API or JSON/CSV file in a few lines of HTML&lt;/a&gt;, and more recently, I showed how to make &lt;a href="https://dev.to/michaelpb/making-a-90s-aesthetic-word-art-text-picker-in-only-20-lines-of-pure-html-web-component-code-1-extra-file-no-node-or-js-2oi8"&gt;word art skew adjusters&lt;/a&gt; or &lt;a href="https://dev.to/michaelpb/making-a-90s-aesthetic-text-shadow-design-tool-in-only-30-lines-of-pure-html-web-component-code-1-extra-file-no-node-or-js-29p6"&gt;a word art shadow throw and range picker tool&lt;/a&gt;. Today's tutorial will be similar to these last two, and could even be combined (lemme know if you try this!). However, today we're focused on generating a more advanced 3D effect from a palette of colors using the power of Modulo's &lt;code&gt;{% for %}&lt;/code&gt; loop template tag. Before we begin, a warning: Text-shadows are intensive and can slow down pages (especially on mobile), so use this technique cautiously on any public-facing pages!&lt;/p&gt;

&lt;h2&gt;
  
  
  The final result
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Animated GIF
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftkm44crj61gtj778vm1j.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftkm44crj61gtj778vm1j.gif" alt="An animated GIF of extruding 3D text letters, in a three striped palette pattern of pastel colors" width="722" height="407"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Screenshot
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ki9m0owmyilg8r1y99n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ki9m0owmyilg8r1y99n.png" alt="A 3D text designer showing extruded letters with shading that shows them in 3D, in a three striped palette pattern of pastel colors: Yellow, mint, and lavendar." width="540" height="323"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try it out now, in less than 30 seconds:&lt;/strong&gt; 🚀🚀🚀 Wanna skip ahead? Scroll to the end and copy the ~30 lines of HTML code into any local HTML file, and then open it in your browser. Modulo has no dependencies and even runs embedded in local HTML files, so it's really that easy!&lt;/p&gt;




&lt;h2&gt;
  
  
  Starting with H1 and a text input
&lt;/h2&gt;

&lt;p&gt;As with previous tutorials, we'll start with &lt;code&gt;&amp;lt;Template&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;State&amp;gt;&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;label&amp;gt;&lt;/span&gt;Text: &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="err"&gt;[&lt;/span&gt;&lt;span class="na"&gt;state.bind&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h1&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"text-shadow: 0 0 3px #fff
      ,1px 1px 0    red
      ,1px 1px 10px #00000033;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.text&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Template&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;State&lt;/span&gt;
  &lt;span class="na"&gt;text=&lt;/span&gt;&lt;span class="s"&gt;"Modulo 3D Text Generator!"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&amp;lt;/State&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this snippet, we have a &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt; element that's bound to &lt;em&gt;State&lt;/em&gt; using &lt;code&gt;[state.bind]&lt;/code&gt;, followed by an &lt;code&gt;H1&lt;/code&gt; element with a hard-coded (red) &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/text-shadow" rel="noopener noreferrer"&gt;text-shadow&lt;/a&gt; effect: The &lt;code&gt;0 0 3px #fff&lt;/code&gt; creates a 3PX white glow around the top, the &lt;code&gt;1px 1px 0 #B90183&lt;/code&gt; creates the "solid"-looking 3D extrusion effect, and finally the &lt;code&gt;1px 1px 10px #00000033&lt;/code&gt; creates a 10px blurred shadow at about ~20% opacity. If the &lt;em&gt;State&lt;/em&gt; concept is giving you conceptual trouble,  &lt;a href="https://dev.to/michaelpb/making-a-font-picker-and-text-designer-tool-in-only-40-lines-of-pure-html-web-component-code-1-extra-file-no-node-or-js-3l1d"&gt;try this tutorial on a font-picker&lt;/a&gt;, or the play around with the interactive examples in &lt;a href="https://modulojs.org/tutorial/ramping-up/part2.html" rel="noopener noreferrer"&gt;Part 2 of the Modulo.js tutorial&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generating a shadow from &lt;em&gt;State&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;Our next step is to make the shadow get auto-generated from state. Let's start by hard-coding 6 shadows (3 red, 3 green):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;State&lt;/span&gt;
    &lt;span class="na"&gt;text=&lt;/span&gt;&lt;span class="s"&gt;"Modulo 3D Text Generator!"&lt;/span&gt;
    &lt;span class="na"&gt;shadows:=&lt;/span&gt;&lt;span class="s"&gt;'[ "red",  "red", "red", "green", "green", "green" ]'&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&amp;lt;/State&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we'll use a &lt;code&gt;{% for %}&lt;/code&gt; for loop that uses the index as the shadow distance. This creates the "3D" effect. This replaces the hard-coded "red" values with for-loop generated shadows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;h1&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"
  text-shadow: 0 0 3px #fff
  &lt;/span&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nv"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;shadow&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;state.shadows&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;&lt;span class="s"&gt;
    ,&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;index&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;px &lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;index&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;px 0 &lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;shadow&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;
    ,&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;index&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;px &lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;index&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;px 10px #00000033
  &lt;/span&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endfor&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;&lt;span class="s"&gt;;
"&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;This generates a total of 13 shadows (1 extra "white glow" shadow, plus each item in the "shadows" array gets 2 shadows each, so 2 * 6 + 1 = 13). The &lt;code&gt;:='[&lt;/code&gt; and &lt;code&gt;]'&lt;/code&gt; syntax is the syntax for creating &lt;em&gt;Arrays&lt;/em&gt;, and the &lt;code&gt;{% for %}&lt;/code&gt; template-tag is the syntax to duplicate a bit of HTML for every item in the array (not to mention each &lt;em&gt;index&lt;/em&gt;, e.g. a number counting up from 0). For further practice, both of these concepts have lots of interactive examples in &lt;a href="https://modulojs.org/tutorial/ramping-up/part4.html" rel="noopener noreferrer"&gt;part 4 of the Modulo.js tutorial&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding a palette and shadow add button
&lt;/h2&gt;

&lt;p&gt;Right now, our 3D text generator is sort of working, but it can't be adjusted. Let's make it customizable: First we clear hard-coded values from &lt;code&gt;shadows:=&lt;/code&gt; array, and then create a new array for our color palette:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;State&lt;/span&gt;
    &lt;span class="na"&gt;text=&lt;/span&gt;&lt;span class="s"&gt;"Modulo 3D Text Generator!"&lt;/span&gt;
    &lt;span class="na"&gt;shadows:=&lt;/span&gt;&lt;span class="s"&gt;'[ ]'&lt;/span&gt;
    &lt;span class="na"&gt;colors:=&lt;/span&gt;&lt;span class="s"&gt;'[ "#B90183", "#A2E4B8", "#FFE45A" ]'&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&amp;lt;/State&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, &lt;a href="https://dev.to/michaelpb/creating-a-word-art-text-curving-design-picke-in-only-30-lines-of-pure-html-web-component-code-1-extra-file-no-node-or-js-4ei7"&gt;in a similar procedure my last tutorial&lt;/a&gt;, let's write a for loop that generates an input for each color in our palette, using the &lt;code&gt;{{ index }}&lt;/code&gt; variable to "bind" each input to each element in the &lt;code&gt;colors:=&lt;/code&gt; Array:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nv"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;color&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;state.colors&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"background: &lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;color&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;click:=&lt;/span&gt;&lt;span class="s"&gt;state.shadows.push&lt;/span&gt;
         &lt;span class="na"&gt;payload=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;color&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;+&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;label&amp;gt;&lt;/span&gt;Palette #&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;index&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="err"&gt;[&lt;/span&gt;&lt;span class="na"&gt;state.bind&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"colors.&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;index&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
         &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"color"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endfor&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we loop through each color in our color palette, creating "divs" with the background color to preview it, along with buttons that, when clicked, invoke the &lt;code&gt;state.shadows.push&lt;/code&gt; function to push the "payload" (in this case, the &lt;code&gt;{{ color }}&lt;/code&gt; itself) onto the shadow array. Thus, every time you click the button, another shadow gets added! If the &lt;code&gt;@click&lt;/code&gt; event concept is giving you trouble, there are many interactive examples in &lt;a href="https://modulojs.org/tutorial/ramping-up/part5.html" rel="noopener noreferrer"&gt;part 5 of the Modulo.js tutorial&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;&amp;lt;x-WordArt3DTool&amp;gt;&lt;/code&gt; - Embeddable snippet
&lt;/h2&gt;

&lt;p&gt;Combining it all, and adding a few final CSS tweaks to the H1 (&lt;code&gt;font-size&lt;/code&gt;, &lt;code&gt;color&lt;/code&gt;, and &lt;code&gt;transform&lt;/code&gt;), and we get the following results that can be embedded anywhere:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;Modulo&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;Component&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"WordArt3DTool"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Template&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;label&amp;gt;&lt;/span&gt;Text: &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="err"&gt;[&lt;/span&gt;&lt;span class="na"&gt;state.bind&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
      &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nv"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;color&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;state.colors&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"background: &lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;color&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;click:=&lt;/span&gt;&lt;span class="s"&gt;state.shadows.push&lt;/span&gt; &lt;span class="na"&gt;payload=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;color&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;+&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;label&amp;gt;&lt;/span&gt;Palette #&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;index&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="err"&gt;[&lt;/span&gt;&lt;span class="na"&gt;state.bind&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"colors.&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;index&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"color"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
      &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endfor&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;h1&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"
        font-size: 64px;
        transform: skew(-10deg, -3deg);
        color: white;
        text-shadow: 0 0 3px #fff
        &lt;/span&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nv"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;shadow&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;state.shadows&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;&lt;span class="s"&gt;
          ,&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;index&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;px &lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;index&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;px 0 &lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;shadow&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;
          ,&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;index&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;px &lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;index&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;px 10px #00000033
        &lt;/span&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endfor&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;&lt;span class="s"&gt;;
      "&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.text&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/Template&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;State&lt;/span&gt;
      &lt;span class="na"&gt;text=&lt;/span&gt;&lt;span class="s"&gt;"Modulo 3D Text Generator!"&lt;/span&gt;
      &lt;span class="na"&gt;colors:=&lt;/span&gt;&lt;span class="s"&gt;'[ "#B90183", "#A2E4B8", "#FFE45A" ]'&lt;/span&gt;
      &lt;span class="na"&gt;shadows:=&lt;/span&gt;&lt;span class="s"&gt;[]&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;gt;&amp;lt;/State&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/Component&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/mdu.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;x-WordArt3DTool&amp;gt;&amp;lt;/x-WordArt3DTool&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I hope you enjoyed this tutorial, if so, follow for more like this!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>programming</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Creating a Word Art text-curving design picker in only 30 lines of pure HTML web component code + 1 extra file (no node or JS!)</title>
      <dc:creator>michaelb</dc:creator>
      <pubDate>Mon, 22 Jan 2024 19:58:41 +0000</pubDate>
      <link>https://forem.com/michaelpb/creating-a-word-art-text-curving-design-picke-in-only-30-lines-of-pure-html-web-component-code-1-extra-file-no-node-or-js-4ei7</link>
      <guid>https://forem.com/michaelpb/creating-a-word-art-text-curving-design-picke-in-only-30-lines-of-pure-html-web-component-code-1-extra-file-no-node-or-js-4ei7</guid>
      <description>&lt;p&gt;Hey all -- as I'm back to Modulo.js tutorial writing, I am always looking for more content ideas. &lt;strong&gt;Have an idea? Be sure to let me know in the comments!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Previously, I showed &lt;a href="https://dev.to/michaelpb/the-2000-line-framework-challenge-how-to-build-web-components-with-two-way-state-binding-with-only-1-file-and-no-nodemodules-2jmf"&gt;how to use the &lt;code&gt;-store=&lt;/code&gt; processor to make a reactive shared &lt;em&gt;State&lt;/em&gt; store between components&lt;/a&gt;, &lt;a href="https://dev.to/michaelpb/how-i-made-a-markdown-html-dual-file-format-modulojs-development-k48"&gt;a deep dive into Modulo's Markdown-HTML file format&lt;/a&gt;, or, last week, &lt;a href="https://dev.to/michaelpb/making-a-text-art-and-svg-circle-picker-design-tool-in-34-lines-of-pure-html-web-component-code-1-extra-file-no-node-or-js-hm7"&gt;how to make a circular text-art tool&lt;/a&gt;. Today, let's make another SVG text design tool, except using &lt;code&gt;&amp;lt;path&amp;gt;&lt;/code&gt; instead of &lt;code&gt;&amp;lt;circle&amp;gt;&lt;/code&gt;. While slightly more complex, using &lt;code&gt;&amp;lt;path&amp;gt;&lt;/code&gt; elements for Text allows for fun and arbitrary text arrangements -- and, most importantly, is supported by Chrome!&lt;/p&gt;

&lt;h2&gt;
  
  
  The final result
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk70vwkg5b61ql55kvul7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk70vwkg5b61ql55kvul7.png" alt="Screenshot showing range sliders allowing to adjust the alignment of Modulo Text FX letters, currently aligned to cause them to spill into a wave-like pattern" width="360" height="424"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try it out now, in less than 30 seconds:&lt;/strong&gt; 🚀🚀🚀 Want to skip ahead? Scroll to the end and copy the ~30 lines of HTML code into any local HTML file, and then open it in your browser. Modulo has no dependencies and even runs embedded in local HTML files, so it's really that easy!&lt;/p&gt;




&lt;h2&gt;
  
  
  Starting with SVG and text input
&lt;/h2&gt;

&lt;p&gt;Let's add an &lt;code&gt;SVG&lt;/code&gt; along with a text input, bound to the text. Let's use a &lt;code&gt;&amp;lt;Template&amp;gt;&lt;/code&gt; and a &lt;code&gt;&amp;lt;State&amp;gt;&lt;/code&gt;  component parts, as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;section&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&amp;lt;input&lt;/span&gt; &lt;span class="err"&gt;[&lt;/span&gt;&lt;span class="na"&gt;state.bind&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;title=&lt;/span&gt;&lt;span class="s"&gt;"Text"&lt;/span&gt; &lt;span class="na"&gt;maxlength=&lt;/span&gt;&lt;span class="s"&gt;"15"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/section&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;svg&lt;/span&gt; &lt;span class="na"&gt;viewBox=&lt;/span&gt;&lt;span class="s"&gt;"0 0 200 100"&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"width: 55%; margin-top: 100px"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;path&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"curve"&lt;/span&gt; &lt;span class="na"&gt;fill=&lt;/span&gt;&lt;span class="s"&gt;"transparent"&lt;/span&gt; &lt;span class="na"&gt;d=&lt;/span&gt;&lt;span class="s"&gt;"M 10,50 C 20,40 40,10 60,40 80,70 100,65 120,90"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;text&amp;gt;&amp;lt;textPath&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#curve"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.text&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/textPath&amp;gt;&amp;lt;/text&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/svg&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Template&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;State&lt;/span&gt;
    &lt;span class="na"&gt;text=&lt;/span&gt;&lt;span class="s"&gt;"Modulo Text FX!"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&amp;lt;/State&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this snippet, we have a &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt; element that's bound to &lt;em&gt;State&lt;/em&gt; using &lt;code&gt;[state.bind]&lt;/code&gt;. If the &lt;em&gt;State&lt;/em&gt; concept is giving you conceptual trouble,  &lt;a href="https://dev.to/michaelpb/making-a-font-picker-and-text-designer-tool-in-only-40-lines-of-pure-html-web-component-code-1-extra-file-no-node-or-js-3l1d"&gt;consider warming up with this tutorial on creating a font design tool&lt;/a&gt;, or the &lt;a href="https://modulojs.org/tutorial/ramping-up/part2.html" rel="noopener noreferrer"&gt;the corresponding section in the interactive Modulo tutorial&lt;/a&gt;. If SVG &lt;code&gt;&amp;lt;textPath&amp;gt;&lt;/code&gt; elements are confusing you, check out &lt;a href="https://developer.mozilla.org/en-US/docs/Web/SVG/Element/textPath" rel="noopener noreferrer"&gt;MDN's documentation&lt;/a&gt;. After that, we have an &lt;code&gt;&amp;lt;svg&amp;gt;&lt;/code&gt; element, containing &lt;code&gt;&amp;lt;path&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;textPath&amp;gt;&lt;/code&gt; elements. These are linked together with &lt;code&gt;id="curve"&lt;/code&gt;, and &lt;code&gt;href="#curve"&lt;/code&gt; respectively. The &lt;code&gt;{{ state.text }}&lt;/code&gt; links the state to the &lt;code&gt;&amp;lt;textPath&amp;gt;&lt;/code&gt; -- &lt;a href="https://dev.to/michaelpb/making-a-text-art-and-svg-circle-picker-design-tool-in-34-lines-of-pure-html-web-component-code-1-extra-file-no-node-or-js-hm7"&gt;also in previous tutorial&lt;/a&gt;. But unlike the previous tutorial, we'll use a &lt;code&gt;&amp;lt;path&amp;gt;&lt;/code&gt; element that takes a &lt;code&gt;d=&lt;/code&gt; attribute, which consist of a series of &lt;code&gt;x,y&lt;/code&gt; coordinate points for each point (dot) on the curve itself (&lt;a href="It's%20not%20100%%20needed%20to%20fully%20understand%20the%20syntax%20here,%20but%20if%20you%20are%20curious,%20[check%20out%20MDN's%20tutorial](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/path)."&gt;documented here&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Okay, I realize that's dense code, but bare with me -- it's only a few more steps to get the tool working!&lt;/p&gt;

&lt;h2&gt;
  
  
  Moving the points to &lt;em&gt;State&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;We currently only have &lt;code&gt;state.text&lt;/code&gt;. We need to also store the points themselves, so we can adjust them with sliders. Let's move to state the Array of points:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;State&lt;/span&gt;
    &lt;span class="na"&gt;text=&lt;/span&gt;&lt;span class="s"&gt;"Modulo Text FX!"&lt;/span&gt;
    &lt;span class="na"&gt;points:=&lt;/span&gt;&lt;span class="s"&gt;'[ [ 20,40 ], [40,10], [60,40], [80,70], [100,65], [120,90] ]'&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&amp;lt;/State&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;:='[&lt;/code&gt; and &lt;code&gt;]'&lt;/code&gt; syntax is the syntax for creating &lt;em&gt;Arrays&lt;/em&gt; in Modulo: If this concept is new to you, consider reading the section on &lt;em&gt;Container types&lt;/em&gt; in &lt;a href="https://modulojs.org/tutorial/ramping-up/part4.html#datatypes" rel="noopener noreferrer"&gt;part 4 of the Modulo.js interactive tutorial&lt;/a&gt;. Next, we need to put the points back into our SVG. We can use the &lt;code&gt;|join:' '&lt;/code&gt; filter to combine the points with spaces:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;path&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"curve"&lt;/span&gt; &lt;span class="na"&gt;fill=&lt;/span&gt;&lt;span class="s"&gt;"transparent"&lt;/span&gt; &lt;span class="na"&gt;d=&lt;/span&gt;&lt;span class="s"&gt;"M 10,50 C &lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.points&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="s1"&gt;' '&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;text&amp;gt;&amp;lt;textPath&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#curve"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.text&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/textPath&amp;gt;&amp;lt;/text&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Creating a hard-coded, rotated range input
&lt;/h2&gt;

&lt;p&gt;At this point, we have moved the points into the &lt;em&gt;State&lt;/em&gt; variable, but we still don't have range sliders for them! Let's do that next. We'll use a "for-loop" for this, so we can repeat the same range-slider code for every point in our point Array. But before we do that, let's start with a "hardcoded" range-slider, which will only control "Point #2", just to make sure we can at least control one of them successfully:&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;label&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"display: inline-block; width: 5%"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;strong&amp;gt;&lt;/span&gt;2&lt;span class="nt"&gt;&amp;lt;/strong&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="err"&gt;[&lt;/span&gt;&lt;span class="na"&gt;state.bind&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"points.2.1"&lt;/span&gt;
      &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"position: relative; transform: rotate(90deg); left: -60px; top: 60px"&lt;/span&gt;
      &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"range"&lt;/span&gt; &lt;span class="na"&gt;max=&lt;/span&gt;&lt;span class="s"&gt;"100"&lt;/span&gt; &lt;span class="na"&gt;min=&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's decipher this: The label and input have &lt;code&gt;style=&lt;/code&gt; attributes to space it by 5% width of the page, rotate the input 90 degrees, and move it 60x60 pixels. The &lt;code&gt;name="points.2.1"&lt;/code&gt; (equivalent to &lt;code&gt;points[2][1]&lt;/code&gt; in other languages) causes the input to control one specific value in the &lt;em&gt;State&lt;/em&gt; variable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Duplicating the input with a for-loop
&lt;/h2&gt;

&lt;p&gt;We've successfully gotten an input to work with a single point (&lt;code&gt;points.2&lt;/code&gt;). We could copy and paste this &lt;code&gt;name="points.2.1"&lt;/code&gt; code 6 times (once for each point), altering each copy to &lt;code&gt;name="points.3.1"&lt;/code&gt;, &lt;code&gt;name="points.4.1"&lt;/code&gt; etc. This would allow us to control every point. Or, we could save ourselves time, and use the Modulo &lt;em&gt;Template&lt;/em&gt; &lt;code&gt;for loop&lt;/code&gt;. Let's see how that looks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nv"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;point&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;state.points&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
    &lt;span class="c"&gt;{# ... #}&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;strong&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;index&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/strong&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="err"&gt;[&lt;/span&gt;&lt;span class="na"&gt;state.bind&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"points.&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;index&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;.1"&lt;/span&gt; &lt;span class="c"&gt;{# ... #}&lt;/span&gt;
&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endfor&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note the only difference here is the &lt;code&gt;2&lt;/code&gt; is replaced with &lt;code&gt;{{ index }}&lt;/code&gt; -- the "index" of the current point we are looping through.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;&amp;lt;x-CurvedTextArtTool&amp;gt;&lt;/code&gt; - Embeddable results
&lt;/h2&gt;

&lt;p&gt;Add the range smooth-rendering &lt;code&gt;="input"&lt;/code&gt; tweak, &lt;a href="https://dev.to/michaelpb/making-a-90s-aesthetic-text-shadow-design-tool-in-only-30-lines-of-pure-html-web-component-code-1-extra-file-no-node-or-js-29p6#tweak-smooth-rerendering-with-sliders"&gt;explained in this tutorial&lt;/a&gt;, and we get the following results. Hope you enjoy this tutorial -- follow for more like this!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;Modulo&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;Component&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"CurvedTextArtTool"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Template&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;section&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&amp;lt;input&lt;/span&gt; &lt;span class="err"&gt;[&lt;/span&gt;&lt;span class="na"&gt;state.bind&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;title=&lt;/span&gt;&lt;span class="s"&gt;"Text"&lt;/span&gt; &lt;span class="na"&gt;maxlength=&lt;/span&gt;&lt;span class="s"&gt;"15"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
        &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nv"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;point&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;state.points&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"display: inline-block; width: 5%"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;strong&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;index&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/strong&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;[state.bind]=&lt;/span&gt;&lt;span class="s"&gt;"input"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"points.&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;index&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;.1"&lt;/span&gt;
                &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"position: relative; transform: rotate(90deg); left: -60px; top: 60px"&lt;/span&gt;
                &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"range"&lt;/span&gt; &lt;span class="na"&gt;max=&lt;/span&gt;&lt;span class="s"&gt;"100"&lt;/span&gt; &lt;span class="na"&gt;min=&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
        &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endfor&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/section&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;svg&lt;/span&gt; &lt;span class="na"&gt;viewBox=&lt;/span&gt;&lt;span class="s"&gt;"0 0 200 100"&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"width: 55%; margin-top: 100px"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;path&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"curve"&lt;/span&gt; &lt;span class="na"&gt;fill=&lt;/span&gt;&lt;span class="s"&gt;"transparent"&lt;/span&gt; &lt;span class="na"&gt;d=&lt;/span&gt;&lt;span class="s"&gt;"M 10,50 C &lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.points&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="s1"&gt;' '&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;text&amp;gt;&amp;lt;textPath&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#curve"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.text&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/textPath&amp;gt;&amp;lt;/text&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/svg&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/Template&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;State&lt;/span&gt;
        &lt;span class="na"&gt;text=&lt;/span&gt;&lt;span class="s"&gt;"Modulo Text FX!"&lt;/span&gt;
        &lt;span class="na"&gt;points:=&lt;/span&gt;&lt;span class="s"&gt;'[ [ 20,40 ], [40,10], [60,40], [80,70], [100,65], [120,90] ]'&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;gt;&amp;lt;/State&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/Component&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/mdu.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;x-CurvedTextArtTool&amp;gt;&amp;lt;/x-CurvedTextArtTool&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Making a text art and SVG circle picker design tool in 34 lines of pure HTML web component code + 1 extra file (no node or JS!)</title>
      <dc:creator>michaelb</dc:creator>
      <pubDate>Sat, 20 Jan 2024 17:50:01 +0000</pubDate>
      <link>https://forem.com/michaelpb/making-a-text-art-and-svg-circle-picker-design-tool-in-34-lines-of-pure-html-web-component-code-1-extra-file-no-node-or-js-hm7</link>
      <guid>https://forem.com/michaelpb/making-a-text-art-and-svg-circle-picker-design-tool-in-34-lines-of-pure-html-web-component-code-1-extra-file-no-node-or-js-hm7</guid>
      <description>&lt;p&gt;Hey all, I'm back to writing my Modulo.js tutorial series, and am always looking for more content ideas. &lt;strong&gt;If you want to see a certain type of tutorial in the future, be sure let me know in the comments -- and follow, if you haven't already!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In my previous tutorials, I showed how to use the single-file, 2000-line, small-but-mighty Modulo.js framework to &lt;a href="https://dev.to/michaelpb/the-2000-line-framework-challenge-making-a-gradient-picker-tool-in-13-lines-of-pure-html-code-1-extra-file-no-node-or-js-2jb1"&gt;make a gradient picker component in 13 lines&lt;/a&gt;, &lt;a href="https://dev.to/michaelpb/the-2000-line-framework-challenge-how-to-template-json-or-apis-in-3-lines-of-component-code-1-extra-file-no-npm-needed-3771"&gt;quickly embed APIs&lt;/a&gt;, or even &lt;a href="https://dev.to/michaelpb/making-a-text-shadow-wave-animation-design-tool-in-only-30-lines-of-pure-html-web-component-code-1-extra-file-no-node-or-js-532p"&gt;how to build an animated text-shadow "wave" effect text picker&lt;/a&gt;. This time, we'll be making something like the last one, except instead of using pure HTML and CSS, we'll be employing the full power of SVG. This lets us really get wild with our text art designer tool! Ready for some creative and exciting shapes in SVG Text Art?&lt;/p&gt;

&lt;h2&gt;
  
  
  The final result
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F42y0gu7jzg4tq8pvyrky.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F42y0gu7jzg4tq8pvyrky.png" alt="Screenshot showing design tool with several inputs (offset, border, radius, fill color, and border color) and the words Modulo.js Text FX in a circle around with lavendar and mint colors"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try it out now, in less than 30 seconds:&lt;/strong&gt; 🚀🚀🚀 Want to skip ahead? Scroll to the end and copy the ~40 lines of HTML code into any local HTML file, and then open it in *&lt;em&gt;Firefox&lt;/em&gt;. Modulo has no dependencies and even runs embedded in local HTML files, so it's really that easy!&lt;/p&gt;




&lt;h2&gt;
  
  
  Template and SVG
&lt;/h2&gt;

&lt;p&gt;Including SVG in Modulo is as simple as adding it to a &lt;em&gt;Template&lt;/em&gt;: &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;

&lt;span class="nt"&gt;&amp;lt;Template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;svg&lt;/span&gt; &lt;span class="na"&gt;viewBox=&lt;/span&gt;&lt;span class="s"&gt;"0 0 600 600"&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"width: 600px; float: right"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;circle&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"circle"&lt;/span&gt; &lt;span class="na"&gt;cx=&lt;/span&gt;&lt;span class="s"&gt;"60"&lt;/span&gt; &lt;span class="na"&gt;cy=&lt;/span&gt;&lt;span class="s"&gt;"100"&lt;/span&gt; &lt;span class="na"&gt;r=&lt;/span&gt;&lt;span class="s"&gt;"40"&lt;/span&gt;
      &lt;span class="na"&gt;stroke=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.stroke&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt; &lt;span class="na"&gt;fill=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.color&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
      &lt;span class="na"&gt;stroke-width=&lt;/span&gt;&lt;span class="s"&gt;"10"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;text&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"2000"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;textPath&lt;/span&gt;
            &lt;span class="na"&gt;xlink:href=&lt;/span&gt;&lt;span class="s"&gt;"#circle"&lt;/span&gt;
            &lt;span class="na"&gt;startOffset=&lt;/span&gt;&lt;span class="s"&gt;"10"&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Modulo.js: Text FX!&lt;span class="nt"&gt;&amp;lt;/textPath&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/text&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/svg&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Template&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;State&lt;/span&gt;
    &lt;span class="na"&gt;color=&lt;/span&gt;&lt;span class="s"&gt;"#B90183"&lt;/span&gt;
    &lt;span class="na"&gt;stroke=&lt;/span&gt;&lt;span class="s"&gt;"#A2E4B8"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&amp;lt;/State&amp;gt;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;In this snippet, we build a 600x600 SVG image (&lt;code&gt;&amp;lt;svg viewBox="0 0 600 600" ...&amp;gt;&lt;/code&gt;), put a 4-radius circle in it at 60x100, and use &lt;code&gt;state.stroke&lt;/code&gt; and &lt;code&gt;state.color&lt;/code&gt; state variables to assign it's color scheme. We then add a text element that "follows" the shape of the circle referring to it by it's ID: &lt;code&gt;&amp;lt;textPath xlink:href="#circle"&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Binding color inputs
&lt;/h2&gt;

&lt;p&gt;We have our colors in our state, but the user has no way of adjusting them. Let's add to our &lt;em&gt;Template&lt;/em&gt; two bound color inputs:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;

&lt;span class="nt"&gt;&amp;lt;label&amp;gt;&amp;lt;input&lt;/span&gt; &lt;span class="err"&gt;[&lt;/span&gt;&lt;span class="na"&gt;state.bind&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"color"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"color"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; Fill Color&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&amp;lt;br/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;label&amp;gt;&amp;lt;input&lt;/span&gt; &lt;span class="err"&gt;[&lt;/span&gt;&lt;span class="na"&gt;state.bind&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"stroke"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"color"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; Border Color&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&amp;lt;br/&amp;gt;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;[state.bind] name="..."&lt;/code&gt; binds each of these to those state variables, so the component will rerender with the new state when a new color is picked. If you are new to Modulo.js, and state and binding is confusing you, &lt;a href="https://dev.to/michaelpb/making-a-font-picker-and-text-designer-tool-in-only-40-lines-of-pure-html-web-component-code-1-extra-file-no-node-or-js-3l1d"&gt;consider warming up with this tutorial on creating a font design tool&lt;/a&gt;, or the &lt;a href="https://modulojs.org/tutorial/ramping-up/part2.html" rel="noopener noreferrer"&gt;Modulo JS - Ramping Up Part 2: State&lt;/a&gt;. If SVG &lt;code&gt;&amp;lt;textPath&amp;gt;&lt;/code&gt; elements are confusing you, check out &lt;a href="https://developer.mozilla.org/en-US/docs/Web/SVG/Element/textPath" rel="noopener noreferrer"&gt;MDN's documentation&lt;/a&gt;.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Finishing up the other inputs: Offset, Border, Radius, and Text
&lt;/h2&gt;

&lt;p&gt;Start with three new state variables, like the initial &lt;code&gt;color&lt;/code&gt; and &lt;code&gt;stroke&lt;/code&gt; ones, except using the data-prop &lt;code&gt;:=&lt;/code&gt; syntax for the numbers:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;

&lt;span class="nt"&gt;&amp;lt;State&lt;/span&gt;
    &lt;span class="na"&gt;text=&lt;/span&gt;&lt;span class="s"&gt;"Modulo.js: Text FX!"&lt;/span&gt;
    &lt;span class="na"&gt;radius:=&lt;/span&gt;&lt;span class="s"&gt;40&lt;/span&gt;
    &lt;span class="na"&gt;width:=&lt;/span&gt;&lt;span class="s"&gt;20&lt;/span&gt;
    &lt;span class="na"&gt;offset:=&lt;/span&gt;&lt;span class="s"&gt;20&lt;/span&gt;
    &lt;span class="na"&gt;color=&lt;/span&gt;&lt;span class="s"&gt;"#B90183"&lt;/span&gt;
    &lt;span class="na"&gt;stroke=&lt;/span&gt;&lt;span class="s"&gt;"#A2E4B8"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&amp;lt;/State&amp;gt;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;And, just like before, add in inputs:&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;input&lt;/span&gt; &lt;span class="err"&gt;[&lt;/span&gt;&lt;span class="na"&gt;state.bind&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;[state.bind]=&lt;/span&gt;&lt;span class="s"&gt;"input"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"offset"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"range"&lt;/span&gt; &lt;span class="na"&gt;min=&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt; &lt;span class="na"&gt;max=&lt;/span&gt;&lt;span class="s"&gt;"300"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;[state.bind]=&lt;/span&gt;&lt;span class="s"&gt;"input"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"width"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"range"&lt;/span&gt; &lt;span class="na"&gt;min=&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt; &lt;span class="na"&gt;max=&lt;/span&gt;&lt;span class="s"&gt;"40"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;[state.bind]=&lt;/span&gt;&lt;span class="s"&gt;"input"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"radius"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"range"&lt;/span&gt; &lt;span class="na"&gt;min=&lt;/span&gt;&lt;span class="s"&gt;"10"&lt;/span&gt; &lt;span class="na"&gt;max=&lt;/span&gt;&lt;span class="s"&gt;"80"&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;The first input controls the text (default type), and the other three &lt;code&gt;input&lt;/code&gt; tags with &lt;code&gt;[state.bind]="input"&lt;/code&gt; control numbers using &lt;code&gt;type="range"&lt;/code&gt; (the &lt;code&gt;="input"&lt;/code&gt; tweak explained in &lt;a href="https://dev.to/michaelpb/making-a-90s-aesthetic-text-shadow-design-tool-in-only-30-lines-of-pure-html-web-component-code-1-extra-file-no-node-or-js-29p6#tweak-smooth-rerendering-with-sliders"&gt;this tutorial&lt;/a&gt;). &lt;/p&gt;

&lt;h2&gt;
  
  
  Adding in the new state variables back to the SVG
&lt;/h2&gt;

&lt;p&gt;Let's go back to the SVG to assign the new state variables to &lt;code&gt;cx=&lt;/code&gt;, &lt;code&gt;cy=&lt;/code&gt;, &lt;code&gt;r=&lt;/code&gt;, and &lt;code&gt;stroke-width=&lt;/code&gt; attributes on the &lt;code&gt;&amp;lt;circle&amp;gt;&lt;/code&gt;, and the &lt;code&gt;startOffset&lt;/code&gt; and content of the &lt;code&gt;&amp;lt;textPath&amp;gt;&lt;/code&gt; itself:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;

&lt;span class="nt"&gt;&amp;lt;circle&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"circle"&lt;/span&gt;
    &lt;span class="na"&gt;cx=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.radius&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;20&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt; &lt;span class="na"&gt;cy=&lt;/span&gt;&lt;span class="s"&gt;"100"&lt;/span&gt;
    &lt;span class="na"&gt;r=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.radius&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
    &lt;span class="na"&gt;stroke=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.stroke&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt; &lt;span class="na"&gt;fill=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.color&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
    &lt;span class="na"&gt;stroke-width=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.width&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;text&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"2000"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;textPath&lt;/span&gt; &lt;span class="na"&gt;xlink:href=&lt;/span&gt;&lt;span class="s"&gt;"#circle"&lt;/span&gt; &lt;span class="na"&gt;startOffset=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.offset&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
       &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.text&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/textPath&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/text&amp;gt;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Note the &lt;code&gt;|add:20&lt;/code&gt; for the &lt;code&gt;cx=&lt;/code&gt;: This &lt;a href="https://modulojs.org/docs/templating/filters.html#add" rel="noopener noreferrer"&gt;|add filter&lt;/a&gt; gives an offset of 20 to the circle so it doesn't overflow on the left.&lt;/p&gt;

&lt;h2&gt;
  
  
  Firefox Footnotes
&lt;/h2&gt;

&lt;p&gt;This tutorial requires &lt;a href="https://caniuse.com/?search=textPath" rel="noopener noreferrer"&gt;the SVG feature of circular text&lt;/a&gt;, which Chrome hasn't yet implemented. My next tutorial will talk about SVG paths, which &lt;em&gt;is&lt;/em&gt; supported by Chrome. The images generated can still be used cross-platform, however.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;&amp;lt;x-TextArtCircleTool&amp;gt;&lt;/code&gt; - Embeddable results
&lt;/h2&gt;

&lt;p&gt;Combine everything, and we get the following results. Hope you enjoy this tutorial -- follow for more like this!&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;

&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;Modulo&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;Component&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"TextArtCircleTool"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Template&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;svg&lt;/span&gt; &lt;span class="na"&gt;viewBox=&lt;/span&gt;&lt;span class="s"&gt;"0 0 600 600"&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"width: 600px; float: right"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;circle&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"circle"&lt;/span&gt;
            &lt;span class="na"&gt;cx=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.radius&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;20&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt; &lt;span class="na"&gt;cy=&lt;/span&gt;&lt;span class="s"&gt;"100"&lt;/span&gt;
            &lt;span class="na"&gt;r=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.radius&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
            &lt;span class="na"&gt;stroke=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.stroke&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt; &lt;span class="na"&gt;fill=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.color&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
            &lt;span class="na"&gt;stroke-width=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.width&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;text&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"2000"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;textPath&lt;/span&gt;
                  &lt;span class="na"&gt;xlink:href=&lt;/span&gt;&lt;span class="s"&gt;"#circle"&lt;/span&gt;
                  &lt;span class="na"&gt;startOffset=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.offset&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;state.text&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/textPath&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/text&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/svg&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;label&amp;gt;&amp;lt;input&lt;/span&gt; &lt;span class="err"&gt;[&lt;/span&gt;&lt;span class="na"&gt;state.bind&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&amp;lt;/label&amp;gt;&amp;lt;br/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;label&amp;gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;[state.bind]=&lt;/span&gt;&lt;span class="s"&gt;"input"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"offset"&lt;/span&gt;
        &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"range"&lt;/span&gt; &lt;span class="na"&gt;min=&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt; &lt;span class="na"&gt;max=&lt;/span&gt;&lt;span class="s"&gt;"300"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt; Offset&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&amp;lt;br/&amp;gt;&lt;/span&gt;   
      &lt;span class="nt"&gt;&amp;lt;label&amp;gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;[state.bind]=&lt;/span&gt;&lt;span class="s"&gt;"input"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"width"&lt;/span&gt;
        &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"range"&lt;/span&gt; &lt;span class="na"&gt;min=&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt; &lt;span class="na"&gt;max=&lt;/span&gt;&lt;span class="s"&gt;"40"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt; Border&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&amp;lt;br/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;label&amp;gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;[state.bind]=&lt;/span&gt;&lt;span class="s"&gt;"input"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"radius"&lt;/span&gt;
        &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"range"&lt;/span&gt; &lt;span class="na"&gt;min=&lt;/span&gt;&lt;span class="s"&gt;"10"&lt;/span&gt; &lt;span class="na"&gt;max=&lt;/span&gt;&lt;span class="s"&gt;"80"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt; Radius&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&amp;lt;br/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;label&amp;gt;&amp;lt;input&lt;/span&gt; &lt;span class="err"&gt;[&lt;/span&gt;&lt;span class="na"&gt;state.bind&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"color"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"color"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; Fill Color&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&amp;lt;br/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;label&amp;gt;&amp;lt;input&lt;/span&gt; &lt;span class="err"&gt;[&lt;/span&gt;&lt;span class="na"&gt;state.bind&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"stroke"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"color"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; Border Color&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&amp;lt;br/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/Template&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;State&lt;/span&gt;
        &lt;span class="na"&gt;text=&lt;/span&gt;&lt;span class="s"&gt;"Modulo.js: Text FX!"&lt;/span&gt;
        &lt;span class="na"&gt;radius:=&lt;/span&gt;&lt;span class="s"&gt;40&lt;/span&gt;
        &lt;span class="na"&gt;width:=&lt;/span&gt;&lt;span class="s"&gt;20&lt;/span&gt;
        &lt;span class="na"&gt;offset:=&lt;/span&gt;&lt;span class="s"&gt;20&lt;/span&gt;
        &lt;span class="na"&gt;color=&lt;/span&gt;&lt;span class="s"&gt;"#B90183"&lt;/span&gt;
        &lt;span class="na"&gt;stroke=&lt;/span&gt;&lt;span class="s"&gt;"#A2E4B8"&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;gt;&amp;lt;/State&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/Component&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/mdu.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;x-TextArtCircleTool&amp;gt;&amp;lt;/x-TextArtCircleTool&amp;gt;&lt;/span&gt;


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

&lt;/div&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>tutorial</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
