Software Development Process, Community, Elixir

Utilizing Phoenix LiveView's Error HTML Pages

After adopting Phoenix LiveView as part of our regular tech stack at SmartLogic, we began to uncover some lesser-known pieces of LiveView. Recently, I encountered an unexpected challenge while rendering a 404 page. Let's walk through it together:

The Challenge

The goal is to display a 404 error page when a user manually navigates to an incorrect product ID in the URL bar.

For example, if is a valid URL, but is not, the latter will redirect to a 404 page.

The two main requirements for this 404 page:
1. Render when the user enters an invalid ID in the URL
2. The navigation bar must retain the URL that the user types

Limitations in Traditional Approaches

Before LiveView, we could achieve this using the action fallback plug in Phoenix. But, in this scenario, I want to apply the behavior to my LiveView for products, not in a generic product controller file. Also, the mount function in my LiveView requires a valid product ID to render the HTML on the page. With an invalid ID from the params, Phoenix displays a "product not found" error that crashes the app.

Why not handle the error within the 'else' block of the mount function and then redirect it? This approach is the most common pattern when encountering errors in LiveView's mount functions.

In this design, we don't want to redirect the user away from a bad URL page; We want to show them a 404. If the product they enter into the params doesn't exist: "Oops, there was an error." That's the user experience you expect to see when you can't find a thing.

So, we can't redirect the user or use the action fallback plug from Phoenix. Another suggestion: wrap the HEEx code in my render function in an if/else block to show the expected code with a valid product ID and the 404 page in the else. If we do this, every LiveView that requires this functionality will need this logic. And also, we're writing Elixir! My favorite thing about the Elixir programming language is that I rarely need to reach for if/else.

The HTML Module in Phoenix LiveView

Enter... the Error HTML module. Phoenix LiveView (1.7.2) ships with an Error HTML module that lives at MyApp.ErrorHTML. By default, a render function reads the status of the error and shows it on the page. To see this working locally, set debug_errors: false in your config/dev.exs file. Otherwise, navigating to invalid route will look something like this:

no found route for GET /invalid/route (DemoWeb.Router)
no found route for GET /invalid/route (DemoWeb.Router)

How the Error HTML Module Works

Once you've set your configs, you should see something like this:

Generic, times new roman "Not Found" message
Generic, times new roman "Not Found" message

(but don't check this config into your project! 😜)

So far, so good. At this point, we need to raise the error where we want it. To do this, we can create a module called Web.Fallback that contains a basic defexception message and determines the plug_status of 404.

In my LiveView, the mount function looks something like this:

The design meets the two requirements for this feature with these pieces in place: The user won't be redirected if they enter an invalid product ID, and the user will see a 404 page.

Customizing 404 Pages in the Code

But that 404 page is pretty boring and straight out of 1998. I want a branded 404 page that's cohesive with the style of the app so the user knows they're still within the application's ecosystem. The documentation for Error HTML says we can create an error_html folder within the controllers folder and add custom error pages per status code. Then, we can make a custom page at /controllers/error_html/404.html.heex and uncomment the line in the Error HTML module: embed_templates "error_html/*"

To match the application's style on the 404 page, we copy the contents of the root.html.heex and rip out the main body content that renders the rest of the app. Then, fill it in with the appropriate branding and language for the 404 page.

(Side note: The documentation for Error HTML was outdated when I was implementing this and said I needed to reference href="/css/app.css" to access my stylesheet. As of Phoenix 1.7.2, this was incorrect and was, in fact, href={~p"/assets/app.css"} as I found by comparing the code in my root HEEx file.)

A Better User Experience

Now, we have a 404 page that renders with all the application styles our hearts desire and meets all the acceptance criteria.

Before I ran into this challenge, I thought there was little to learn about rendering 404 pages in 2023. But with these new approaches in LiveView, there's never a dull moment! As a consultancy, we continuously learn and adapt, ensuring we provide the best solutions for our clients and the developer community.

I hope this was helpful if you want to use the Error HTML module! As always, if you're looking for a cool team of folks to build you some custom software, please reach out.

Author image

About Sundi Myint

Sundi was an Engineering Manager at SmartLogic working on projects in Elixir & Flutter, as well as a Co-Host on SmartLogic's podcast ✨Elixir Wizards✨.
  • Baltimore, MD
You've successfully subscribed to SmartLogic Blog
Great! Next, complete checkout for full access to SmartLogic Blog
Welcome back! You've successfully signed in.
Unable to sign you in. Please try again.
Success! Your account is fully activated, you now have access to all content.
Error! Stripe checkout failed.
Success! Your billing info is updated.
Error! Billing info update failed.