I Created the Exact Same App with Simple Web Standards

Bill Miller
7 min readFeb 6, 2022

I did the thing. I created a To-Do List “app” using vanilla web standards and good old-fashioned procedural code, on a Sunday morning, in my jammies, in 20 minutes. It was quick and simple. Actually, A large portion of that time was spent refilling my coffee cup; I don’t really DO morning.

Why did I do this? In the programming world I’m a dinosaur. When it comes to writing web code, I miss the simplicity. I’ll explain later in the article, but the “app” is the thing right now.

Some Backstory

The To-Do list “app” in question was the focus of a couple of two very good articles. The first of which was authored by Sunnil Sandhu, where the same “app” was created to compare and contrast React and Vue. (An article he’s updated a few times now.) It’s a great article and he does a good job making the comparison.

Adam Presley was inspired to use the same “app” to write an article introducing and utilizing Web Components. He also does a fantastic job, and honestly Web Components look kind of groovy and effective with the right use case. It also is a very good article.

You should read them. I take no issue with these individuals, and I am not attacking them. Their articles were written for different reasons. I was simply inspired the problem of the “app” to write my own, simple version.

What Does the “App” Do?

The app, with an input box, minus button, and a plus button at the bottom.

The “app” is rather simple; It’s a To-Do List. The end user types a task. If they need to add more items to the list, they click the plus button. They click the minus button when they’ve accomplished their task and it goes away.

What Does the “App” Really Do?

From a programming perspective, the “app” provides an input field for the end-user to type their task.

To add another item to the list, they click the plus button. This activates a function which copies and adds another instance of the input and minus button to the DOM.

The end-user clicks the minus button when they’ve completed their task. This removes the element containing the input and minus button from the DOM.

The Markup

The markup should be fairly self-explanatory, but here’s a bit to explain the “why did you choose” questions.

The markup. (Provided in a pen since this description is useless to anyone with assistive tech.)

Remember, markup is supposed to be semantic.

<main> encapsulates everything since it is the main part of the document.

There’s an <h1> element for the heading / title, using an ice cream cone emoji as an icon graphic. There’s only one heading, so I use the first heading element in the hierarchy. The emoji saves the trouble of reaching out to the server to fetch a graphic file making the “app” load even faster.

Next, is an ordered list (<ol>) element, because a to-do list is a bloody list. When someone writes a to-do list, they usually enumerate it. Because of this, it made sense to use an ordered list. The enumeration doesn’t show in the final version of the app, but it is a possibility which can easily be turned on in the CSS. An unordered list could have also been used; I just liked the option of enumeration.

The whole thing is finished off by the ‘+’ button, which will be used to add another to-do list item for the end-user.

I always try to put as much of the markup in the HTML file as possible. There are times where it might have to be templated in the JavaScript, but only if it is absolutely necessary. The markup is the first thing loaded and parsed. We also want to observe the separation of concerns.

Fortunately, a really helpful element has been added to the HTML spec; that’s <template>. The <template> element is never rendered but allows you to pre-template the markup you may need to add to the rendered part of the page later. This saves you the trouble of building or templating it in JavaScript. The markup remains where it belongs…in your HTML document. You copy it as a document fragment and then insert it where you want it to go.

Here, I used <template> for the list items <li> which will go inside the ordered list, with the input box and a minus button to power the “app”.

Minus the typical HTML boilerplate, that’s it.

The CSS

I swiped most of the styles from Sunil’s original CSS. I did condense it down since there were fewer elements in the “app”. (I’ll let you see it in a pen.)

The “app” (<main>) was made to look like a card because that’s what the crazy kids are doing these days. Cards are in, apparently.

Since the first letter of the <h1> is actually an emoji that’s supposed to be the “icon” for the “app”, I used the ::first-letter pseudo-element to make it look like one.

There’s a common set of styles for all the buttons. The buttons held within the <li> elements are minus buttons and are made green. The + button was styled red.

Otherwise, everything which needs a reset has been reset. I let the user/browser choose their sans-serif font and set it to 1em in size.

The JavaScript

The JavaScript. (Provided in the Pen since this description is useless to anyone using assisstive tech.)

I attach an addTodoItem function to the plus button. The button is referenced from the DOM directly using querySelector. On load, it’s the only button rendered.

The list (<ol>) is referenced globally by every other function in the “app”, so I declare it in the global space as list.

For the start of the app, the end-user needs at least one <li> in the list, so I call the addTodoItem function to make it happen.

The addTodoItem Function

The first line of the addTodoItem function is where the magic of the <template> element happens. We retrieve it and clone what we need from <template>’s ‘content’ property using the cloneNode method.

cloneNode’s single parameter is a boolean value which tells the browser if you want it to copy the element’s children as well. Since I want the nested <input> and <button> elements, I set the cloneNode parameter to ‘true’. Leaving it ‘false’ would have copied the <li> element by itself and it would be empty.

We attach the removeTodoItem function to the copied minus button, and then insert the copied <li> at the tail end of the list with the append method.

The removeTodoItem Function

Since the removeTodoItem function is called by clicking the minus button, that button is bound to ‘this’. We use ‘this’ to crawl up one level of the DOM and remove the parent <li> element.

As a convenience for the user, if all of the <li>s have been removed from list (list’s child count is zero) we add a fresh new one for them to fill out.

The “App” In a Pen

Here’s a pen of the “app”.

Why Do You Keep Adding Quotation Marks Around the Word “App”?

When it comes to the web development, my perspective is a little different…Here it goes…

“There are no web apps, there are only web sites.”

Once you change perspective, things become much easier. The page markup is developed first, followed by the styling. The scripting enhances what’s there. It keeps things simple, and simple is easy. It’s the way we used to do it, and the way I miss.

The in-fashion paradigms, frameworks, and methodologies have their use cases, but I find if I approach from the perspective of a web page which needs some scripted enhancement, the coding aspect is really simple. Scripting becomes little more than some minor data processing and some digital slight-of-hand. There are no extra functions, classes, or framework libraries imported, only the necessary code is pushed to the browser. The “app” loads really quickly, and the user experience is greatly improved.

The next time you decide to build a web “app”, try it the simple way. Build the pages with minimal and semantic markup, style only the elements you have on the page, then enhance what’s there with a sprinkling of JavaScript. Observe the separation of concerns and keep everything simple. I think you might find the development fast, easy, and a good user experience.

--

--