The Pragmatic Studio

Button Clicks

Notes & Exercises

Final Code

You'll find the completed example in the 1-button-clicks-end branch of the code bundle.

Version 0.16 Update

In the video we created a LiveView LEEx template using the special ~L sigil. LiveView 0.16 introduced a new HEEx template which is created using the ~H sigil.

Don't worry: Both types of templates are fully supported in LiveView 0.16. However, HEEx templates have several advantages including compile-time validation of the markup in the template. So it's worth using HEEx templates on your own projects. And the good news is that it's relatively easy to migrate from an LEEx template to an HEEx template.

Most of the time, you just need to make two trivial changes:

  1. Replace the ~L sigil with the ~H sigil. So change this


    to this

  2. Use {} to interpolate code inside HTML tags.

    Since HEEx templates must parse and validate the HTML, code interpolation using <%= ... %> and <% ... %> are restricted to the body (inner content) of HTML elements and it cannot be used inside HTML tags.

    For example, the LEEx template for LightLive includes this section:

    <span style="width: <%= @brightness %>%">
      <%= @brightness %>%

    That syntax is valid in an LEEx template, but invalid in an HEEx template because it uses <%= ... %> to interpolate code inside the span tag. HEEx templates require Elixir expressions inside tags to appear within {}. We can make it a valid HEEx template like so:

    <span style={"width: #{@brightness}%"}>
      <%= @brightness %>%

    Notice that within the {} we now have an Elixir expression that evaluates to a string. It uses standard Elixir string interpolation (#{}) to interpolate the value of the @brightness value.

    Also notice that the <%= @brightness %> expression on the second line remains valid (no changes necessary) because it's in the body of the span element and not inside the span tag itself.

In subsequent notes we'll highlight any special cases when it comes to HEEx migration. And in the final_app_v0.16 directory of the code bundle you'll find a version of all the course code updated for LiveView 0.16. But we recommend sticking with LEEx templates as you go through the course so you can focus on the core concepts.

The Generated App

You might be wondering how we created the Phoenix app we started with in the 1-button-clicks-begin branch. We generated it using:

mix live_view_studio --live

Then we tossed in some images and added TailwindCSS with some custom CSS to give the examples a more polished feel. Other than that cosmetic stuff, the code in the 1-button-clicks-begin branch is a standard Phoenix app.

Creating Your Own App

If you'd like to create your own app that has the same CSS styles and images as the live_view_studio app, here's how you'd go about it:

  1. First, assuming you don't already have an application directory, generate one:

    mix my_app --live
  2. Then copy the assets/package.json file from the live_view_studio application to the assets directory of your app, and then install the dependencies:

    cd assets
    npm install
  3. Then to mimic how we have Tailwind configured, copy the following configuration files from the live_view_studio application to the assets directory in your app:

  4. In terms of CSS and image files, copy all of them from the live_view_studio application to the respective subdirectories of your assets directory:

  5. Finally, at the top of your assets/js/app.js file, change this line which expects that you're using Sass

    import "../css/app.scss"

    to this which expects a regular CSS file:

    import "../css/app.css"

And that should give you a baseline application with all the images and styles in place matching what you'll see in the course!

How's Your Elixir Game?

As you saw in the video, you write LiveViews using the Elixir programming language. If you're new to the language, learning LiveView might feel like someone tied your shoe laces together and asked you play some hoops. 🏀 🤕

Imagine knowing Elixir so well you can drive to the basket and dunk! That's what you'll be able to do after our Elixir & OTP course. So before getting too far into LiveView, we highly recommend joining us in the Elixir course to gain clarity and confidence with the language.


We start with the Elixir fundamentals and leave no stone unturned as we build an app step-by-step from scratch. And the second half is all about OTP, so it's like getting two courses in one. 🙌

We think you're gonna love it!

Exercises and Modifying the Code

Throughout the course we'll suggest exercises to apply what you learned in the videos. You might also decide to make your own modifications to our code. By all means, tinker away!

You have a couple choices as to where you make those modifications.

One option is to change the code in the Git branch of the local repository that's included in the code bundle. For example, you could make changes in the 1-button-clicks-end branch. However, when you switch to the 2-dynamic-form-begin branch (coming up next), any changes you made in the 1-button-clicks-end branch won't come along for the ride. To integrate your changes, you would need to merge them into the 2-dynamic-form-begin branch. And every time you switched to the next branch, you would need to merge your changes from the previous branch.

Another option is create your own separate repository that includes your exercise solutions and modifications, and copy over files from the code bundle repo as necessary. In this scenario there's no need to merge branches as you'll likely just keep everything in the main branch.

Both options have their pros and cons. Which one you choose is a matter of personal preference. But it's good to have a game plan because here comes the first exercise...

Exercise: Light Me Up!

Add a "Light Me Up!" button that when clicked sets the brightness to a random number between 0 and 100. Try doing it from memory before peeking at the answer for guidance. 😉

  1. Add a button that emits an event when clicked.

  2. Handle the event by assigning a random number as the brightness.

  3. Throw a disco party! 🕺

Min and Max Brightness

Now you may have noticed (as @jaimeiniesta did) that you can continue to turn the light up even after it's reached full brightness. Same with turning it down even when it's already off.

Here's his neat solution using min and max:

def handle_event("up", _, socket) do
  socket = update(socket, :brightness, &min(&1 + 10, 100))
  {:noreply, socket}

def handle_event("down", _, socket) do
  socket = update(socket, :brightness, &max(&1 - 10, 0))
  {:noreply, socket}

All course material, including videos and source code, is copyrighted and licensed for individual use only. You may make copies for your own personal use (e.g. on your laptop, on your iPad, on your backup drive). However, you may not transfer ownership or share the material with other people. We make no guarantees that the source code is fit for any purpose. Course material may not be used to create training material, courses, books, and the like. Please support us by encouraging others to purchase their own copies. Thank you!

Copyright © 2005–2024, The Pragmatic Studio. All Rights Reserved.