Preact - a JavaScript guide

We're going to look at how you can use a library called Preact to greatly simplify building complex web GUIs. Preact is a lightweight front-end framework that has a similar API to the heavyweight React. Other front-end frameworks include Angular and Vue.

Before reading this guide, try my learn JavaScript tutorial or my guide to events and the event loop. You should know the basics of HTML, CSS and JavaScript before you start learning a framework like Preact.

Hello world

In a new folder, perhaps called preact, put this in an index.html:

This loads code the Preact library, making 2 functions available to you - h() and render(). h() is used to build up some HTML into a variable app, then render(app, document.body) loads that HTML into the body of the page.

We could acheive the same without Preact with this:

... but it can quickly get messy when building up more than just one element.

Ensure you have vite installed then serve it with vite. Access it in a web browser to check it works, and you should see a page that says 'Hello world!' like this:

I won't show the full source within each example, only the bits that are relevant or change. Press on any example to see the full source code for that example, which can be downloaded and run locally.

Using the htm library

The h('h1', null, 'Hello world!') above doesn't look anything like the resulting HTML <h1>Hello world!</h1>. We can fix that with another library called htm. First, we need to import the library and set things up:

You'll need that code in all examples from here on.

Then before you render the app into document.body, change the line to this:

Now we can do html`<h1>Hello world!</h1>`
instead of h('h1', null, 'Hello world!'),
which is basically normal HTML inside a... weird thing. This thing is a 'tagged template' - notice how it strangely doesn't use ( braces ) around the backticks.

Props and components

In the React and Preact world (as well as with other front-end frameworks) we talk about components. A page may consist of various different components, for example a search bar, a menu, the main story on a page, a carousel of images, the footer etc. It's good practice to create functions for each of these components, then compose them together to make larger components or whole pages.

Here we're going to make a very simple component called Hello and include it on our page 3 times:

Remember you still need render(app, document.body) below that too.

Although JavaScript functions usually have camelCase names, by convention components are PascalCase instead. Your function's first parameter should be called props (for 'properties'). props is an object, which can have lots of keys within it. In this case, when the Hello component is added to a page it's given name="something". That makes props.name available to the component.

Without Preact we could do something like this:

... which again for now looks fine, but will get messier as we add more to the page.

Component children

Just like normal HTML, components can have other elements nested within them.

A vanilla JavaScript equivalent would be relatively trivial, but in the next section we'll start to discover the more powerful advantages of a library like Preact over vanilla JavaScript.

Dynamic, stateful components

One of the great things about a library such as Preact is it enables you to create dynamic components that respond to a change in state far easier than using vanilla JavaScript.

First, we have to import the useState() function or 'hook' from Preact:

Which we'll be using in our new stateful component, Counter:

And we'll add 2 instances of the Counter to the page:

Our new component Counter uses one property props.start to customise the starting count.

It also includes a dynamic state variable count - you can change it, and when you do the component instantly re-renders. Importantly though, this isn't a normal variable where you could do count++ and see the change. To change it, you must use its settter method setCount().

When we want a new state variable, you create that variable with useState():

useState() takes a starting value as an argument and returns an array with 2 items. The first is the state variable you've created, and the 2nd is a setter method you must call to change/mutate that state variable. If you accidentally edit the state variable instead of using the setter method, the component won't re-render and you'll be scratching your head wondering why.

Again, let's see how we could achieve the same with vanilla JavaScript instead of Preact.

... this time, it should be more obvious how Preact is going to help us keep our code clean and organised. Without Preact we have to do a lot of document.createElement() and el.querySelector(). To make the displayed count dynamic we had to put a tag around it to give it a class so we could select it to change its value with div.querySelector('.count').innerHTML = count. When you have multiple bits of dynamic content on a page, this gets very tiresome.

Todo list example

This example shows how to build a simple todo list using Preact. We'll assume we're in a component function TodoList which we add to the page with <${TodoList}/>.

We'll store our list of items in an array. Because we'll be adding to that list and rendering based on it, we'll need it to be stateful. We'll initialise the array to be empty with []:

In the HTML we'll be returning from the component, we'll show that list by mapping each list item to a <li> element, all nested within a <ul>:

We must be careful not to list.push('new item') or the new item won't be rendered to the page. As with the counter earlier, we must use the setter method returned by useState([]) instead:

We'll also want a form with an input box and a button to add new items:

Finally, a function which is called when the button is clicked or the 'enter' key is pressed while in the input box:

Putting it all together:

Try it out by putting something into the box below the pressing 'Add'

While this works for one todo list on the page, if we try to add another it no longer works, because there are now 2 <input> boxes on the page, both with the same id.

Instead, we'll use a Preact feature called refs (for 'references'). To use refs we need to import the useRef() function at the top of our JavaScript, by editing the line where we import useState to import useRef as well:

We can then initalise a new reference with:

Which we can attach to our input box (instead of giving it an id):

And then use in our add() function via the ref's .current property:

All together:

... and notice how now you can have multiple TodoList's on a page and they'll all work, independently of each other.

Preact vs vanilla JavaScript

If you chose to use vanilla JavaScript instead of Preact, you could achieve a similar todo list like this:

... so why not do that? Well, you can if you want. However, here are some reasons to prefer Preact:

JSX and other frameworks

I've chosen Preact and htm because they're lightweight and don't require a build step. An alternative to htm is jsx, but JSX needs to be converted to JavaScript with a build step. Most examples on the Preact website use JSX.

Taking our todo list further

It would be nice if when we clicked an item in our todo list it would delete it.

We can add a remove() function:

... which removes an item from the list at index i, being sure to use setList() to mutate the state variable list.

We can then bind the onclick handler of the item in the list to that remove function:

For an extra touch, below the list we can write a suitable message if the list is empty:

Putting it all together:

What next?

You'll learn the most by trying things out. Make your own components and compose them into a page. Make sure you've got lots of interactivity with things you can press and change.