"HTML-only, no JS!" ✨🪄
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. Have an idea for a next topic? Be sure to let me know in the comments!
In previous tutorials, I covered topics like adding an API or JSON/CSV file in a few lines of HTML, and more recently, I showed how to make word art skew adjusters or a word art shadow throw and range picker tool. 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 {% for %}
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!
The final result
Animated GIF
Screenshot
Try it out now, in less than 30 seconds: 🚀🚀🚀 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!
Starting with H1 and a text input
As with previous tutorials, we'll start with <Template>
and <State>
:
<Template>
<label>Text: <input [state.bind] name="text" /></label>
<h1 style="text-shadow: 0 0 3px #fff
,1px 1px 0 red
,1px 1px 10px #00000033;">{{ state.text }}</h1>
</Template>
<State
text="Modulo 3D Text Generator!"
></State>
In this snippet, we have a <input>
element that's bound to State using [state.bind]
, followed by an H1
element with a hard-coded (red) text-shadow effect: The 0 0 3px #fff
creates a 3PX white glow around the top, the 1px 1px 0 #B90183
creates the "solid"-looking 3D extrusion effect, and finally the 1px 1px 10px #00000033
creates a 10px blurred shadow at about ~20% opacity. If the State concept is giving you conceptual trouble, try this tutorial on a font-picker, or the play around with the interactive examples in Part 2 of the Modulo.js tutorial.
Generating a shadow from State
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):
<State
text="Modulo 3D Text Generator!"
shadows:='[ "red", "red", "red", "green", "green", "green" ]'
></State>
Next, we'll use a {% for %}
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:
<h1 style="
text-shadow: 0 0 3px #fff
{% for index, shadow in state.shadows %}
,{{ index }}px {{ index }}px 0 {{ shadow }}
,{{ index }}px {{ index }}px 10px #00000033
{% endfor %};
"> ...
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 :='[
and ]'
syntax is the syntax for creating Arrays, and the {% for %}
template-tag is the syntax to duplicate a bit of HTML for every item in the array (not to mention each index, e.g. a number counting up from 0). For further practice, both of these concepts have lots of interactive examples in part 4 of the Modulo.js tutorial.
Adding a palette and shadow add button
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 shadows:=
array, and then create a new array for our color palette:
<State
text="Modulo 3D Text Generator!"
shadows:='[ ]'
colors:='[ "#B90183", "#A2E4B8", "#FFE45A" ]'
></State>
Now, in a similar procedure my last tutorial, let's write a for loop that generates an input for each color in our palette, using the {{ index }}
variable to "bind" each input to each element in the colors:=
Array:
{% for index, color in state.colors %}
<div style="background: {{ color }}">
<button @click:=state.shadows.push
payload="{{ color }}">+</button>
<label>Palette #{{ index }}
<input [state.bind] name="colors.{{ index }}"
type="color" /></label>
</div>
{% endfor %}
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 state.shadows.push
function to push the "payload" (in this case, the {{ color }}
itself) onto the shadow array. Thus, every time you click the button, another shadow gets added! If the @click
event concept is giving you trouble, there are many interactive examples in part 5 of the Modulo.js tutorial.
<x-WordArt3DTool>
- Embeddable snippet
Combining it all, and adding a few final CSS tweaks to the H1 (font-size
, color
, and transform
), and we get the following results that can be embedded anywhere:
<!DOCTYPE html>
<template Modulo>
<Component name="WordArt3DTool">
<Template>
<label>Text: <input [state.bind] name="text" /></label>
{% for index, color in state.colors %}
<div style="background: {{ color }}">
<button @click:=state.shadows.push payload="{{ color }}">+</button>
<label>Palette #{{ index }} <input [state.bind] name="colors.{{ index }}" type="color" /></label>
</div>
{% endfor %}
<h1 style="
font-size: 64px;
transform: skew(-10deg, -3deg);
color: white;
text-shadow: 0 0 3px #fff
{% for index, shadow in state.shadows %}
,{{ index }}px {{ index }}px 0 {{ shadow }}
,{{ index }}px {{ index }}px 10px #00000033
{% endfor %};
">{{ state.text }}</h1>
</Template>
<State
text="Modulo 3D Text Generator!"
colors:='[ "#B90183", "#A2E4B8", "#FFE45A" ]'
shadows:=[]
></State>
</Component>
</template>
<script src="https://unpkg.com/mdu.js"></script>
<x-WordArt3DTool></x-WordArt3DTool>
I hope you enjoyed this tutorial, if so, follow for more like this!
Top comments (0)