Introduction

Prerequisites: Knowledge of building websites with HTML & CSS is all that's required. For example, the set of lessons at FreeCodingLessons.com: Foundations of Web Design cover all the basics of HTML and CSS for coding newbies. However, if you are already comfortable with HTML & CSS, then continue Ramping Up! Familiarity with JavaScript or other programming languages, or Vue / React or other frontend tools is helpful due to overlap in concepts, but not required for Ramping Up.

Welcome to the Ramping Up with Modulo tutorial! By following this 5 part tutorial, you will learn how to build interactive Web Components in Modulo.

Ramping up?

Modulo was designed to overcome a sort of "skill cliff" in web development. Beginners dabbling in HTML and CSS can have a hard time getting into more complex JavaScript frontend frameworks. For much of the same reasons, experienced developers can also encounter a "skill cliff" when integrating a frontend JavaScript framework with a static site or backend MVC app, with some popular options sometimes feeling like overkill in terms of complexity and dependencies.

This tutorial is called "ramping up" since it's goal is allowing you to use Modulo as a "ramp" up that "skill cliff"! By taking this tutorial, you'll learn how to "ramp up" from repetitive, difficult-to-maintain HTML and CSS, to re-usable Web Component development. It also lets you "ramp up" your skills in modern frontend web development: You'll learn concepts like Props, State, Template, Tags, Filters, Slots and more! These are concepts that are transferable to use other popular frameworks, and Modulo's lightweight approach could be a more inviting way to learn the core concepts without getting bogged down in complex setup.

What is Modulo?

Modulo is useful when using plain HTML and CSS is no longer sufficient. It has no dependencies, does not require a "build process" to get started, and does not require experience with JavaScript, terminal applications, or NPM. This means it can be equally easily incorporated into a plain HTML "static site" (e.g. when you assemble HTML, CSS, and other static assets in a directory), or into a "multi-page" web app built with a backend language or MVC framework.

Modulo Definition

JS file hosting alternatives: 1) Directly link to a CDN hosting Modulo.js (shown in this tutorial) or 2) Download the single Modulo.js file and host locally.

Modulo.js is a file containing 2000-lines of JavaScript. Including the file in an HTML page will "enable" all the abilities of the Modulo framework on that page. It will allow us to start writing Modulo definitions and use the framework in general.

Including Modulo

The first step to using Modulo is to include a Modulo script tag in your HTML file. In general, you could 1) start with an empty file (see aside on HTML boilerplate), or 2) open up an existing HTML file:

<script src="https://unpkg.com/mdu.js"></script>

This will only include the JS file, but not activate Modulo. To activate Modulo, we need to create a Modulo definition using a template tag, and leave some space to indicate that this will (soon) contain Modulo code:

<template Modulo> <!-- our stuff will go here eventually... --> </template> <script src="https://unpkg.com/mdu.js"></script>

No HTML boilerplate? You might think that you absolutely need to include "boilerplate" code like <html> or <body> when coding HTML files. These are nice for well-formatted documents, but not strictly necessary: The browser will fill in as needed. Only a <!DOCTYPE HTML> is needed to prevent "quirksmode".

Note that the <template Modulo> tag has a capital M in the attribute Modulo. The capital letter indicates that it's a definition, or that Modulo code is going to be contained within. In other words, you can say that this is the page's "Modulo definition". Also note that technically, either modulo or Modulo will work because HTML is case-insensitive; however, the capitalized Modulo spelling is recommended for easier reading.

Defining and using a component

Once you have included Modulo and activated it, you can fill it up with Component definitions, which are special tags in HTML format. These work like keywords or configuration settings in order to set-up the component and define it's apearance and behavior.

Definition

Let's examine our first Modulo definition:

<Component name="HelloWorld"> <Template> Hello <strong>Modulo</strong> World! </Template> </Component>

Component definitions start with a "Component" opening tag in the format of <Component name="HelloWorld">. Modulo will look for these tags, defining components for each one it encounters. Every component definition must specify a name, conventionally in UpperCamelCase. This is just a convention when writing code: Technically HTML tag names are all case insensitive, and so while inspecting the DOM, browsers typically display them in all-lowercase, removing any capitalization.

Usage

Once defined, you can use a component by referring to it's name as though it were a plain HTML tag. 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 <div>, <a>, etc.

Why use "components"? Have you ever repeated the same HTML, CSS, and/or JavaScript while writing a website or or web app? Components let you store repeated code in one place. Once defined, components can be re-used everywhere, saving developer time and reducing mistakes. Furthermore, within teams, components libraries improve collaboration between developers.

Unlike plain HTML tags, you must use a dash (-) when referring to a component. This is a rule of the HTML5 Custom Components standard, which Modulo is based upon. Modulo's default behavior is to prefix custom components with an x-. So, if a component is defined like <Component name="HelloWorld">, then it can be referenced elsewhere like <x-HelloWorld></x-HelloWorld>.

To quickly summarize: Components are reusable bits of HTML, JS, and CSS code, and must be defined within a tag like <Component name="HelloWorld">, and then this definition can be embedded in an HTML page within a script tag like: <script Modulo src="https://unpkg.com/mdu.js">

Okay, enough talk, let's actually try this out!

What are local files?

These learning tips are on practicing the techniques taught in this tutorial on both a local file ("local file challenge"), as well as the miniature "demonstration" editors embedded in this website for convenience.

What does it mean to develop locally? This means editing a HTML file separately in a text editor (open source options include Geany, Notepad++, or Visual Studio Code), saved to your computer, also opened in a modern web browser (such as Firefox or Chrome). It's recommended to use a local file editor on a laptop or desktop computer to practice concepts. However, if all you have is Android or iOS, don't worry: While this tutorial is not optimized for mobile, it's still possible to complete most everything without local files.

Learning Tips
  • Tip 1: The Try It Now instructions tell you to apply the concepts you learn. Most will have sample code to edit and see. Some will say "Local file challenge:", and encourage you to apply the lesson you learned on a component you develop locally on your computer.

  • Tip 2: Since Modulo is new, most editors and IDEs are not aware of it's syntax. However, the work around is easy: Configure your editor for Django or Django template mode when working on Modulo files.

  • Tip 3: To maximize learning and retention, consider applying these local file challenge activities in creative way, such as on a website or project you care about! If you feel "out of ideas", consider getting inspiration from one of these ultra-simple, beginner HTML designs.

  • Tip 4: For maximum productivity, consider tiling the web browser and editor side-by-side, or in separate monitors, and cruising along with key combos like Alt+Tab (switch windows, e.g. between editor and browser) and Ctrl+Shift+R (force-refresh browser)

Try it now
  1. Local file challenge: Open up an HTML file in your preferred text editor.

  2. Copy & paste in the following code:

    <!-- Define a custom component in a "Modulo" definition tag --> <template Modulo> <Component name="RampingUpWithModulo"> <Template> Hello <strong>Modulo</strong> World! </Template> </Component> </template> <script src="https://unpkg.com/mdu.js"> </script> <!-- Reuse it anywhere, just like a "real" HTML tag --> <div> <x-RampingUpWithModulo></x-RampingUpWithModulo> <p>In a P tag: <x-RampingUpWithModulo></x-RampingUpWithModulo></p> </div>
  3. Ensure that the HTML file is opened in your preferred web browser as well.

  4. Refresh your web browser to view the results.

    • Hint: The browser should now show "Hello Modulo World", followed by "In a P tag: Hello Modulo World".
  5. Edit the component: Change "World!" to "Universe!"

  6. Refresh your web browser and observe the change.

    • Hint: Sometimes browsers can "cache" results and just show you the old version, even after you save a change. If you don't see a change right away, see learning tips on force-refreshing.
Comprehension Questions
  • What's different between the first Component definition example we saw in this tutorial, and the second? What's the same? How do we use them?

    • Answer #1: The name of the components are different, as the first example given was HelloWorld, while the second example was RampingUpWithModulo
    • Answer #2: The content of the components is the same: Both had a "Template" of: Hello <strong>Modulo</strong> world!
    • Answer #3: <x-HelloWorld></x-HelloWorld> and <x-RampingUpWithModulo></x-RampingUpWithModulo> respectively
  • When in use, do you see how the tag gets replaced with the content of the template? How might this save time when writing HTML?

    • Answer #1: Repetive code can be "refactored" (rewritten) to be more DRY ("don't repeat yourself") by identifying the "repeating units" and then putting those inside of Components, so their template can be repeated with less code required.
    • Answer #2: When repetitive code is refactored this way, it lets us edit it in one spot, and see the results everywhere.
Try it now (Alternative)

There's a time-saving alternative way to start a local file. The fastest way is by clicking the SAVE button (hidden below "RUN") on any of the interactive examples on this website. This will download an HTML file with all of the above code already filled in, ready for you to start! This allows you to pick the example that has the most code in common with the project you are about to build, which speeds up initial development.

Alternative local file starting instructions: Start this tutorial by clicking SAVE below:

<Template> Hello <strong>Modulo</strong> world! </Template>

In a P tag:

  • Hint: Can't find the SAVE button? - It might only appear when you hover your mouse over the "RUN" button in the middle of the interactive demo above.

Component Parts

The central concept to Modulo is that of Component Parts. Because it is so central, saying Component Parts over and over gets tiresome, so in this documentation and the source code it's typically shortened to CParts.

CParts: The Musical Think of CParts like the cast and crew of a musical. Each are assigned to a different task—some are more flashy and visible, others being stage-hands working behind the scenes—but they all work together to put on the same show!

All component definitions consist of some number of CParts. Thus, a component definition is really just a collection of CPart definitions. "Under the hood" of your component, each CPart will have a different role to contribute to the functionality of your component.

Template and Style

Let's start with the two most basic CParts:

  1. Template - <Template>

    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. Later, we'll learn how to use "templating language" to control what HTML is produced in what circumstance.

  2. Style - <Style>

    Just like the <style> tag in HTML, the Style CPart allows us to write CSS for our component. CSS written here will be automatically prefixed so that it will only apply to your component and any HTML generated by the Template CPart. This is quite useful: It allows us to write isolatable components. Keeping our CSS separate means fewer unexpected interactions.

Where to put CSS Instead of a Style CPart, you can always link a global CSS file the regular way to style your components. However, many developers prefer the simplicity of keeping everything in one place, e.g. the CSS with the component definition that it styles.

Syntax notes

Like Component naming, most CParts are technically case-insensitive (e.g. "<style>" will work the same as "<Style>"). However, it's important you follow the convention of making the CPart names start with a capital letter, such that you can easily distinguish them from plain HTML tags.

Throughout Modulo documentation, there are little code editors, like below. These allow you to immediately practice new concepts learned. For simplicity, the top and bottom of the component definition code is omitted. Instead, these sample code editors only focus on the CPart definitions within.

Try it now

Edit the component definition on the left, and click RUN to see the results on the right!

  1. Practice modifying the Template CPart (<Template>) to see how that affects the output preview on the right
  2. Practice modifying the Style CPart (<Style>) to add or modify CSS
  3. Local file challenge: Practice incorporating the <Style> CPart into your local component, and expanding on the <Template> as needed to build out the beginnings of your component or layout.
<Template> Hello <strong>Modulo</strong> World! <p class="neat">Any HTML can be here!</p> </Template> <Style> /* ...and any CSS here! */ strong { color: blue; } .neat { font-variant: small-caps; } :host { /* styles the entire component */ display: inline-block; background-color: cornsilk; padding: 5px; box-shadow: 10px 10px 0 0 turquoise; } </Style>
Comprehension Question
  • What is the purpose of <Style>?
    • Answer: Style lets us add isolated CSS styling to our Component
  • What is does it mean that Style "isolates" CSS?
    • Answer: Style by default "isolates" CSS by making it only apply to the content of the Component it is defined in. This keeps our CSS neater, and less confusing. That is, you might like this feature if you ever find yourself getting confused and tangled code with questions like: "Did I already use this class name?", "Did I accidentally just style ALL divs this way?" etc. Details on this so-called "prefix isolation" will be covered later, in Part 4 of this tutorial.
  • What does :host do?
    • Answer: It lets us style the component itself (not only what's inside of it)

Props

Why use Props? Components are "write once, use everywhere". That is to say, you only need to define a component once to use it throughout your pages. The advantages are clear: By writing "DRY" (non-repetitive) code, you can make changes to the single component definition, and see the update at once wherever on the site that the component might be used. However, sometimes you want each instance of a component to have different content or slightly modified behavior. This is where Props come into play: They allow you to customize differences in content or behavior when using a component.

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 CPart defines the properties that can be customized about a component each time it is reused.

Other people's components

Before we learn how to use the Props CPart itself, let's first get acquainted with a concept we haven't done before: Reusing components that were coded by someone else! In a realistic scenario of an organization building a web app, it's likely that most of the components you will be using won't actually be written by you personally, but instead by someone else on some sort of internal "component library" team. Similarly, even if working by yourself, you'll need to learn how to component libraries written by others so you can use components already defined for you to accomplish common tasks. Don't reinvent the wheel!

In this next activity, we'll practice reusing components.

Try it now

Usage: For even more flexibility, the mini-demonstration editors found through can demonstrate usage of components when in "USAGE" mode, such as the <x-ExampleBtn> below. You can toggle "USAGE" mode from the "MENU" button, which is above the "RUN" button.

The button below was defined to accept two so-called "props": label, and shape. We'll cover how it was defined to use a Props CPart later on. For now, we'll practice only with using the x-ExampleBtn.

USAGE
<p>Trying out the button...</p> <x-ExampleBtn label="Button Example" shape="square" ></x-ExampleBtn> <p>Another button...</p> <x-ExampleBtn label="Example 2: Rounded" shape="round" ></x-ExampleBtn>

Trying out the button...

Another button...

`

  1. Examine the code above. Examine the preview on the right. Do you see how the code in turn uses the x-ExampleBtn in two locations, with a different shape and label each? We can call each of these a component instance. Each component instance can receive different or customized props attributes.
  2. Note the label="..." prop attribute that is on each x-ExampleBtn. Test it out by editing the contents of this attribute on one or both of the buttons and click RUN to see the result on the right.
  3. Note the shape="..." prop that is on each button. It's impossible to have known this without reading the CSS of x-ExampleBtn, but it accepts either "square" or "round". Try changing one to the other and see the results.
Comprehension Challenge

Comprehension Challenge 1: Based on the patterns you see here, add a third button to this example that is round and contains the word "Hello".

Comprehension Challenge 2: See if you can think up or imagine what props might be attached to different types of widgets, e.g. a "modal pop-up" widget might specify the title, or an Open Street Map widget might specify latitude and longitude for the map being displayed. What would a text input need? What about a tabbed navigation interface? How about a component that shows a chess board with pieces in a specified setup?


Defining and using the Props CPart

Let's "peel back the layers" and examine out how this ExampleBtn was written. In order for a component to be able to "receive" props when it is reused, we must define a Props CPart, which is conventionally placed as the first thing in a component definition. Props CParts are defined somewhat like previous CParts, except they have no contents and are just an opening tag with attributes, followed by a closing tag. A Props CPart might look like this:

Props and Templating for CSS The Style CPart intentionally does not support templating, props, or any such "live" modification. Instead, this should be done in the template by using an inline style= attribute. If it gets too messy, consider setting CSS to style= attributes used by the Style CPart, using the var() CSS function.

<Props name device frequency></Props>

The recommended style for Modulo code is to add a newline after each prop name for easier reading. HTML syntax doesn't care either way, so the above might be improved for readability if it were written as follows:

<Props name device frequency ></Props>

Once you have defined which props you expect a component to receive by using the Props CPart, you can then reference the values of those props elsewhere within the component: Either in the Template CPart (what we'll cover next), or in the Script CPart (covered later).

Template variables

Remember how CParts are supposed to "work together"? Our discussion of props gives us a chance to explore the Template CPart a little bit deeper, as once we have defined our Props, we have to put them to use! This is where the Template CPart comes into play.

Previously, we have only used a Template CPart to display static, unchanging HTML. That's quite limiting. The typical purpose of "templating" or "a templating language" is to allow customization, substitution, and transformation of HTML content. Templating isn't unique to web development: If you've used template files with word processors such Microsoft Word, or email templates within marketing or sales software, you'll know that with templating you can include placeholders where we want to insert data or values, in order to personalize each instance.

The most relevant concept in Templating is the concept of template variables, or locations in the Template HTML that get substituted for the values. In our case, we'll be receiving those values as Props. Basically, by using Props and template variables, we can add in a "fill in the blank" feature to your HTML.

Using props within a template

Within a Template CPart, we can insert data or values using a special "placeholder" syntax that is as follows: {{ myVariableName }}. We can also use a dot (.) in this syntax to access properties. Thus, you will see this placeholder syntax more often used like this: {{ props.device }}. So, combining this information with the 3 props that we have above, we can create a template that has 3 placeholders that get filled in with specific data when the component gets reused. Examine the below code and try to guess at what it might do:

<Template> <p>Hi {{ props.name }}, your {{ props.device }} is at {{ props.frequency }}hz.</p> </Template>

In this case, if we were to use our component with the attributes name="Tux", device="Radio" and frequency="2600", then the following text would be rendered on the page when the Component is used:

<p>Hi Tux, your Radio is at 2600hz.</p>

The "Modulo templating language" was modeled after Django, Jinja2, or Liquid, and thus is quite powerful, being capable of much than the simple substitutions we're learning here. We'll learn more features in Part 2 of this tutorial series.

Try it now
  1. Examine the Props and Template variable code below, and see if you can answer the comprehension questions.
<Props caption image ></Props> <Template> <figure> <img style="height: 50px; width: 50px" src="{{ props.image }}" /> <label><em>Caption:</em> {{ props.caption }}</label> </figure> </Template> <Style> :host { text-align: center; } figure { display: inline-block; border: 10px inset tomato; padding: 10px; margin: 10px; width: 100px; background: salmon; } </Style>
  1. Challenge: Add code to the Template and Prop CParts to display the the "photographer" and "location" information.

    • Hint 1: Try flipping to "USAGE" editing mode (go to MENU button above RUN, then toggle EDIT USAGE). Do you see how image and caption are specified as attributes? Note there's a "photographer" credit there as well. How would you use that in the component?
    • Hint 2: Remember to first add it to <Props at the top! It's very easy to forget this step, but Modulo will only "gather" the attributes specified there, and ignore the rest.
    • Hint 3: Try copying the same structure as the "Caption" code, but for the other property names.
  2. Local file challenge:

    1. Add a Props CPart to your component -- e.g. <Props messsage>)
    2. Use the Props in your Template CPart by using template variables -- e.g. {{ props.message }}
    3. Practice setting them in using your component -- e.g. <x-Hello message="Hi">
Comprehension questions
  1. What happens when you delete Props that are expected?
    • Answer: Both the "image" and "caption" become blank
    • Answer: This is because you have to actually use the component with correct props to see the effect.
  2. In the example above, do you see how there are two "props" declared to be available? Can you name them both?
    • The "Props" CPart specifies which props should be used. In this case, the two props are "caption" and "image" -- the two attributes of the Props CPart.
  3. If you had to use this component in an HTML document, how would specify these "Props"?
    • You'd specify them like <x-PictureFrame image="./myfile.jpg">
    • It could be re-used with different pictures and captions

Part 1: Summary

In this tutorial, we learned what a Component is, and how to define one, about what CParts are, and three important CParts (Template, for HTML, Style, for CSS, and Props for specifying which HTML attributes you want to use). At this point, you can already start getting useful results from using Modulo, since even without JavaScript usage we are already defining simple components that can help us re-use HTML code between different pages.

Key terms
  • Component - a discrete, re-usable bit of code, typically used to show a graphical UI element (eg a button, or a rich-text area). Components can also use other components (eg a form component might contain both of the above as child components). A component may be used once on a page, or it might be used many times in different "component instances".
  • Component Part, or CPart - each component consists of a "bag" or "bundle" of CParts, each CPart being a "pluggable" module that supplies different functionality for that component. Every component is defined as a collection of CParts (e.g. Props, Template, or Style tag).
  • customElement - the term used for a custom HTML5 Web Component, which is the underlying technology that Modulo functions as a thin wrapper over. They all have dashes (-) in the name.
  • Template - the component part that is used to specify the HTML template that the component renders on the page.
  • Props - a cpart used to specify attributes, that the user of a Component can use to configure the component
  • template variable - Modulo's templating language can include template variables (e.g. {{ props.name }}) mixed in with the HTML)

In the subsequent tutorial we will go deeper: Explore the full capabilities of Templates, and finally create forms and interactive, changing components with the State CPart.

Part 2: Template Tags, Template Filters, and State »