Building a text-shadow design tool

In my previous tutorials, I showed how to use the single-file Modulo.js to make a gradient picker component in 13 lines, quickly embed APIs, or even how to build a full CMS-powered site with Modulo. The greatest interest, however, has been in Modulo's ease at making design tools and similar useful components. Let's revisit the "Word Art" design tool topic today!

The final result

Today, we'll learn how to create a "duo-tone" text-shadow word art aesthetic generator, with customizable symmetric colorful shadows. Look below for an example of what we'll be building:

Screenshot showing sliders controlling shadow distance and spread and color adjustment inputs

Try it out now, in less than 30 seconds: 🚀🚀🚀 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!


Starting with an H1 tag and some State variables

Let's start with an H1 tag with lots of CSS text styling:

<Template> <h1 style=" text-shadow: 0 0 2px black, -3px -3px 1px {{ state.shadow1 }}, 3px 3px 1px {{ state.shadow2 }}; color: white; text-stroke: 2px black; -webkit-text-stroke: 2px black; font-size: 50px; transform: skew(-30deg, -10deg); text-align: center; ">90s Text Art FX in Modulo.js!</h1> </Template> <State shadow1="#B90183" shadow2="#A2E4B8" ></State>

Note how most of the rules are hard-coded (color, font-size, transform, etc), except for the colors of the two text-shadow drop shadows, which are replaced with the two State variables (shadow1 and shadow2 respectively). This lets us "move" our colors into our State so we can control them using bound inputs. If you want to make the other hard-coded aspects customizable follow the previous tutorial in the series.

Controlling shadow color state variables with inputs

Next we will learn how to let users modify these variables, so they can preview different color schemes:

<label>Shadow 1 <input [state.bind] name="shadow1" type="color"></label> <label>Shadow 2 <input [state.bind] name="shadow2" type="color"></label>

Tricky? Learn more on color pickers here or get more State practice in Part two of the interactive Modulo tutorial.

Adding a "shadow throw distance" and "shadow blur amount" sliders

Next, let's make both the "shadow distance" and "blur amount" adjustable with two new state variables:

<State distance:=3 spread:=2 shadow1="#B90183" shadow2="#A2E4B8" ></State>

Note the := syntax: We use this since we are dealing with numbers instead of strings. We then add these new variables into the style= attribute in the Template:

text-shadow: 0 0 2px black, -{{ state.distance }}px -{{ state.distance }}px {{ state.spread }}px {{ state.shadow1 }}, {{ state.distance }}px {{ state.distance }}px {{ state.spread }}px {{ state.shadow2 }};

Finally, we add an input with name="size" and [state.bind], so that it binds to the state variable just like the name="text" textarea was bound:

<label>Shadow throw distance <input [state.bind] name="distance" type="range" min="1" max="20" /></label> <label>Shadow blur amount <input [state.bind] name="spread" type="range" min="1" max="10" /></label>

Important to note: The type="range", along with min="..." and max="..." lets you create a slider-type input such that the user can "drag" a knob between those two values.

Tweak: Smooth rerendering with sliders

Examine the following GIF:

Image description

A slight tweak was applied: [state.bind]="input". This tells State to rerender during drag (input event), not just during release (change event, the default).

<x-TextArt> - Embeddable results

Adding in that last tweak and combining everything gives this result. Hope you enjoy this tutorial -- follow for more!

<!DOCTYPE html> <template Modulo> <Component name="TextArt"> <Template> <label>Shadow 1 <input [state.bind] name="shadow1" type="color"></label><br/> <label>Shadow 2 <input [state.bind] name="shadow2" type="color"></label><br/> <label>Shadow throw distance<input [state.bind]="input" name="distance" type="range" min="1" max="50" /></label><br/> <label>Shadow blur amount <input [state.bind]="input" name="spread" type="range" min="1" max="30" /></label><br/> <h1 style=" text-shadow: 0 0 2px black, -{{ state.distance }}px -{{ state.distance }}px {{ state.spread }}px {{ state.shadow1 }}, {{ state.distance }}px {{ state.distance }}px {{ state.spread }}px {{ state.shadow2 }}; color: white; text-stroke: 2px black; -webkit-text-stroke: 2px black; font-size: 50px; transform: skew(-30deg, -10deg); text-align: center; ">90s Text Art FX in Modulo.js!</h1> </Template> <State distance:=3 spread:=2 shadow1="#B90183" shadow2="#A2E4B8" ></State> </Component> </template> <script src="https://unpkg.com/mdu.js"></script> <x-TextArt></x-TextArt>