Let's be friends

Introduction

There are so many ways you could organize a program to render things to the DOM. But here’s a little work-through considering your choices and different patterns you could use.

There’s a reason hundreds of devs work for years to build out UI libraries and JS frameworks. And a lot of things to consider. But for now, keep it simple and fun!

Inserting HTML

See the Pen HTML cheatsheet 1 / display types by perpetual.education (@perpetual-education) on CodePen.

Look at the HTML document… find the body element… and replace it’s inner HTML. Fancy!

While this works perfectly fine for controlled content like a static <h1> tag in this case, it introduces risks if the content being injected comes from an untrusted source, such as user-generated content or data from an external API.

Is it safe?

See the Pen HTML cheatsheet 1 / display types by perpetual.education (@perpetual-education) on CodePen.

Imagine the content is not hardcoded as above but comes from a user or an external source.

In this case, the malicious content (an image with an onerror handler) would execute the script when the image fails to load, causing the alert to pop up. In a real attack, this could be used to steal sensitive information or manipulate the DOM in unintended ways.

 

Adding text safely

See the Pen HTML cheatsheet 1 / display types by perpetual.education (@perpetual-education) on CodePen.

To prevent this kind of attack, it’s better to use safer alternatives, such as element.textContent, which ensures that no HTML is interpreted or executed as code. If you’re inserting just text, you should always prefer this.

Creating elements

See the Pen HTML cheatsheet 1 / display types by perpetual.education (@perpetual-education) on CodePen.

The element.textContent property is only for text, though. So, it’s not going to work to add DOM nodes.

Any HTML tags or scripts you try to include will be treated as plain text and won’t be executed or rendered as actual HTML.

If you’re following DFTW, you did a bunch of this in your first few days of exploring JavaScript.

Iterating over a dataset

See the Pen HTML cheatsheet 1 / display types by perpetual.education (@perpetual-education) on CodePen.

Take your time and make sure you 100% know what is happening here.

 

Getting a bit more complicated

See the Pen HTML cheatsheet 1 / display types by perpetual.education (@perpetual-education) on CodePen.

If you’re comfortable with how HTML elements are key:value (or attribute:value) collections, then this should be clear enough. But it’s not exactly as elegant as it could be. For most people, this is a bit tough on the eyes.

 

There isn't a single "right" way

These examples are made to help you explore – not demonstrate a step-by-step way to memorize patterns.

So, the keywords, methods, and syntax will be varied and with reason (to make you think).

Using Array.forEach to keep things tidy

See the Pen HTML cheatsheet 1 / display types by perpetual.education (@perpetual-education) on CodePen.

Using the Array.forEach method helps keep it a little more readable. If you’re going through DFTW, you know that keeping things readable and conceptual is the most important thing. We can talk about “the best” way to do things as we go and run into real-world situations. The for loop is faster. The createElement is safer.

The bigger issue is that currently, the program just goes – and you have no way to control it or reuse it.

element.innerHTML is great for quick prototypes, but you’ll need to consider more secure methods for larger projects and projects with user-generated content.

Reusing it

See the Pen HTML cheatsheet 1 / display types by perpetual.education (@perpetual-education) on CodePen.

Wrapping that in a function gives you control (and encapsulation)

Keeping templates readable

See the Pen HTML cheatsheet 1 / display types by perpetual.education (@perpetual-education) on CodePen.

The template might get a little more complex. You can format it to make it a bit more readable. But what if you have a nested list or something? It could get weird and you don’t have syntax highlighting and you could make more mistakes.

When is it too hard to read?

See the Pen HTML cheatsheet 1 / display types by perpetual.education (@perpetual-education) on CodePen.

OK, so – maybe the template strings aren’t the most beautiful thing in the world – but take a look at this other way you could write it. It’s not a quick read. It doesn’t look like HTML.

For the sake of the prototypes we’re building, we want everything to be as readable as possible.

Breaking it up

See the Pen HTML cheatsheet 1 / display types by perpetual.education (@perpetual-education) on CodePen.

You can break the single item out into it’s own function. This will keep things more readable and give the function a smaller scope to handle. Depending on your situation, this might be more or less readable. So, it’s up to you to figure that out.

Using Array.map and Array.join

See the Pen HTML cheatsheet 1 / display types by perpetual.education (@perpetual-education) on CodePen.

People tend to get sick of writing out the template (or whatever you call it) (the variable for the base string) – and they’ll see this trick using Array.map() and adopt it. But if it’s too tricky, just use the Array.forEach() style until you change your mind.

The array method map is creating an array based on what you give it, so something like ["<li>a</li>","<li>b</li>","<li>c</li>"] and the Array.join('') is putting the array back together as a string – and instead of a comma, using a nothing to connect them into their final output `"<li>a</li><li>b</li><li>c</li>" .

Kinda weird at first! And not as readable for new people. (but faster to write in some situations)

Templating vs rendering

See the Pen HTML cheatsheet 1 / display types by perpetual.education (@perpetual-education) on CodePen.

Some of these functions aren’t really rendering anything. They’re just returning a value (a string representing some HTML markup);

Maybe naming them differently will be helpful to differentiate them.

Composition

See the Pen HTML cheatsheet 1 / display types by perpetual.education (@perpetual-education) on CodePen.

This render() function to handle all DOM updates, making the code more composable and reusable. Maybe?

Nefarious attacks

See the Pen HTML cheatsheet 1 / display types by perpetual.education (@perpetual-education) on CodePen.

Click results to run the program and see the attack!

Balancing the Convenience of Template Strings with Security Best Practices

Template strings are great for writing and reading dynamic HTML quickly and clearly, especially in controlled environments where the content is trusted. The security concern arises when dealing with untrusted content, like user input or external data, which can expose your app to XSS attacks if not handled properly.

Most modern frameworks or libraries handle sanitization for you, making template strings safe in many cases. The key is knowing when to rely on your tech stack and when to use safer methods, like textContent, for user-generated content.

During DFTW, choose what is most readable until further notice.

The template tag

See the Pen HTML cheatsheet 1 / display types by perpetual.education (@perpetual-education) on CodePen.

The <template> element keeps your HTML structure readable by allowing you to define it directly in the document. However, since the content isn’t rendered immediately, there’s no visible placeholder, and managing multiple querySelector calls to inject data can become verbose and cumbersome.

While textContent helps avoid XSS vulnerabilities, the overall process can feel repetitive and awkward, especially for simpler cases.

That said, the <template> element has its purposes, particularly for reusable, isolated components, performance optimizations, and web components. We’ll dive deeper into its true strengths later.

Using insertAdjacentHTML() (Adding to specific places)

See the Pen HTML cheatsheet 1 / display types by perpetual.education (@perpetual-education) on CodePen.

Sometimes, you only need to add or insert something in a specific part of the page without affecting the rest of the content. Using insertAdjacentHTML() allows you to insert new content directly into the DOM without re-rendering or replacing existing elements. This is especially useful when dealing with real-time updates or when you need to add items incrementally to a specific place, like appending to a list or inserting into a particular section.

Why?

Efficient Incremental Updates: If you’re working with large lists or content that frequently updates (like notifications, chat messages, or real-time data feeds), insertAdjacentHTML() is perfect for adding new content without touching existing elements.

Inserting into a Specific Location: You can use it to append, prepend, or even insert content before or after an element, giving you precise control over where the new content appears.

Re-rendering the whole section (Reactive approach)

See the Pen HTML cheatsheet 1 / display types by perpetual.education (@perpetual-education) on CodePen.

Other times, it’s better to rebuild a section of the DOM entirely, especially when you need to ensure the UI is in sync with your application’s data. Re-rendering a specific part of the DOM from scratch ensures the entire section is fully updated based on the latest state. This is useful when dealing with reactive updates, where the UI needs to stay consistent with changes in the underlying data model.

Why?

Ensuring Consistency: If the list or section you’re working with isn’t too large and needs to be fully updated whenever the data changes, re-rendering the whole section ensures that the UI always reflects the current state. This is particularly useful when changes affect multiple parts of the list, like sorting or filtering items.

Simple Data Binding: In cases where you’re updating based on user interactions (e.g., adding an item), re-rendering the section ensures that everything is properly updated without needing to manually manage each part of the DOM.

A note about DOM-diffing

As you’d expect, swapping out big chunks of the DOM is way more work (and more taxing) than just updating a small section. But beyond performance, there are practical problems, too. What if the user is in the middle of typing in a text input, and the form or list rerenders? Boom—focus lost. Same goes for other active states that suddenly reset.

Now, imagine you’re looking at some super complex page, and someone out in the ether gives a “like” on something—should that little thumbs-up icon turning blue trigger a full rebuild of the page, module, component, or just the CSS class?

The next step in this evolution is smarter: take a snapshot of the current DOM, build a new one with updated data, compare the two, and only update what’s different. That’s totally doable—you should give it a shot! But, fair warning, things can get gnarly as you dive deeper. The more nested your structure, the more recursion you’ll need to walk through all the little attributes and details. Honestly, you might be better off using a tool that handles the heavy lifting for you.

Vue

See the Pen HTML cheatsheet 1 / display types by perpetual.education (@perpetual-education) on CodePen.

There are UI frameworks that abstract much of this away. What do you think about this?

Frameworks like Vue and React handle most of this DOM-diffing for you, abstracting away the complicated bits. They keep your UI responsive and in sync with the underlying data without you having to think too much about how many elements need updating or when. And they help avoid problems like focus loss or redundant re-renders.

But at the end of the day, it’s not just about saving time—it’s about balancing convenience with control. Sure, you could write everything from scratch and optimize the DOM manually, but frameworks have already solved a lot of those headaches.

work in progress...

Additional considerations & challenges

Dom-diffing and performance

  • Consideration: Updating large parts of the DOM is taxing. Be mindful of performance.
  • Challenge: Try swapping only small parts of the DOM and see how it affects performance. Use console.time() to compare full vs. partial renders.

Handling user input and state loss

  • Consideration: Rerenders can disrupt focus and reset active states (e.g., input fields).
  • Challenge: Build a form that rerenders dynamically—now ensure it preserves focus between updates.

Real-time updates with minimal impact

  • Consideration: Avoid unnecessary updates. Does a “like” button change need to rebuild the entire component?
  • Challenge: Use CSS class updates or targeted DOM changes (querySelector) to handle real-time feedback.

Inserting adjacent HTML for incremental updates

  • Consideration: Insert content at precise locations without touching existing DOM elements.
  • Challenge: Append new chat messages or notifications using insertAdjacentHTML() and ensure nothing else rerenders.

Full re-renders vs. targeted changes

  • Consideration: Sometimes, rebuilding a section is simpler and more consistent than selective updates.
  • Challenge: Create a list that rerenders completely when sorted or filtered—then compare it to incremental updates.

Balancing security with convenience (template strings)

  • Consideration: Template strings are convenient but risky with untrusted input.
  • Challenge: Use template strings to build dynamic HTML. Now switch to textContent for user-generated content and observe the difference.

Leveraging modern CSS

  • Consideration: Use CSS optimizations to avoid rendering off-screen content.
  • Challenge: Build a long list or infinite scroll feature—apply content-visibility to off-screen elements and measure the performance boost.

Using frameworks for DOM management

  • Consideration: Frameworks like Vue or React handle DOM diffing efficiently.
  • Challenge: Recreate a small interactive component manually, then rebuild it with a framework and compare the experience.
Let's be friends