Introduction

Part 1, Chapter 1


Over the last decade, the most popular way to create web applications was to completely separate the frontend from the backend and use RESTFul APIs coupled with a heavy frontend JavaScript framework to create a Single-page Application (SPA).

This can work great when you have separate teams for the frontend and backend. However, this is not ideal for indie hackers who must develop both of them.

Fortunately, there's been an increase in interest and creation of lighter frameworks that support the one-man-band idea. Among the more popular are HTMX and Alpine.js on the JavaScript side and Tailwind CSS for the CSS. With each of those, the code can be written directly within the HTML, thus speeding up the development process.

HTMX

HTMX is a library that allows you to access modern browser features directly from HTML, without having to use JavaScript. Plus, you can still create a a SPA-like feeling since attributes like hx-post and hx-swap update only portions of the DOM.

Advantages:

  1. It's lightweight (~12kB min.gz)
  2. Server-side rendering is better for SEO
  3. Gradual learning curve
  4. No JavaScript knowledge is required
  5. Any HTML element can issue an HTTP request
  6. Any DOM event can trigger a request
  7. Besides the GET and POST (supported by default), you can also use PUT, PATCH, or DELETE
  8. Any HTML element (not just the entire window) can be the target for an update by a request

Disadvantages:

  1. Relatively new, so its community is small
  2. It's lightweight -- although you can do a lot with such a small library if you need a full-scale client-side heavy app, HTMX won't be able to replace React or such

An example of what HTMX looks like:

<div id="parent-div">
   <button hx-post="/clicked"
       hx-trigger="click"
       hx-target="#parent-div"
       hx-swap="outerHTML"
   >
       Click Me!
   </button>
</div>

All HTMX attributes are prefixed with hx-. hx-trigger decides which event (click in the example) triggers the POST request to the /clicked URL (hx-post="/clicked"). The element set with hx-target (element with ID parent-div) is then entirely swapped (hx-swap="outerHTML") with the content of the response.

Tailwind CSS

Tailwind CSS is a utility-first CSS framework.

Instead of the opinionated classes you're used to from frameworks like Bootstrap, which combine multiple different CSS properties -- e.g., .card sets position, width, display, border, and background color -- Tailwind provides primitive utility classes where one class does one thing -- e.g., .bg-white sets the background color to white.

Advantages:

  1. It's highly customizable
  2. It uses a mobile-first approach
  3. It's very simple to style a dark version of your design
  4. The change (generally) applies to a single element, meaning you won't break something somewhere else
  5. There are official extensions for VSCode and JetBrains IDEs

Disadvantages:

  1. CSS is tightly coupled with HTML
  2. Since each class takes care of only one thing, a single element can use umpteen classes, thus hurting readability
  3. It doesn't provide components out-of-the-box, although there are free and payable solutions available -- e.g., Tailwind Elements or Flowbite
  4. Lack of components and abundance of classes makes for a relatively steep learning curve

An example of what Tailwind looks like:

<div class="my-4 mx-auto text-sm lg:text-2xl text-slate-700">
  Tailwind CSS is a utility-first CSS framework.
</div>

In this example, we determine the size of margin (my for top and bottom, mx for left and right), font-size, and line-height (text-sm, text-2xl) as well as the color and shade of the text (text-slate-700, text-slate-300).

Alpine.js

Alpine.js is a lightweight JavaScript framework with, as of writing, only 15 attributes, 6 properties, and 2 methods. Its creator calls it the "jQuery for the modern web".

Advantages:

  1. It's lightweight
  2. Syntax is similar to Vue and Angular, so Alpine.js will feel familiar if you have used any of them before
  3. You don't necessarily need to adapt your code to the framework -- you can just sprinkle Alpine.js where needed
  4. It's written in an HTML file, making it ideal to combine with HTMX and Tailwind

Disadvantages:

  1. Unlike HTMX, which doesn't look much like JavaScript, Alpine.js still feels like one of the modern JavaScript frameworks -- e.g., it uses components. Some solutions also require writing plain JavaScript.
  2. Using Alpine.js in all its powers requires the data to be in an Alpine component. This means that you need to transfer your data from FastAPI to Alpine (we won't be covering this approach in this course).
  3. You have to (mostly) pay for Alpine.js components (e.g., an accordion).

An example of what Alpine.js looks like:

<div x-data="{ count: 0 }">
  <span x-text="count"></span>
  <button x-on:click="count++">Increment</button>
</div>

This code creates a very simple counter:

  1. x-data creates the component and provides the data for it (count).
  2. The span and the button are both connected to the count data.
  3. x-text="count" sets the text content of the element (to count) and x-on:click="count++" increments the count value each time the button is clicked.

FastAPI with TailwindCSS, HTMX, and AlpineJS

FastAPI's modern and lightweight design works beautifully with the other frameworks mentioned. While it's mainly used for building APIs, you can also create full-stack web applications by pairing it with a template engine.

In this setup, FastAPI manages the backend, HTMX handles server interactions, Alpine.js takes care of client-side tasks, and Tailwind CSS makes everything look great.

Even though HTMX provides usage examples, combining all these tools into a working application can be tricky. That's where this course comes in — it shows you how to blend these modern, lightweight frameworks into a seamless application.

What Does This Course Cover?

This course has three parts.

Part 1

In Part 1, you'll learn the basics about each tech stack that we'll be using:

  1. Setting up the FastAPI project, combining it with Jinja, SQLModel, and Alembic
  2. What is HTMX, and how to integrate it with FastAPI
  3. What is Tailwind, and how to integrate it with FastAPI
  4. What is Alpine.js, and how to integrate it with FastAPI

Part 2

In Part 2, we'll add HTMX, Tailwind CSS, and Alpine.js to our FastAPI project.

  1. We'll go through the common use cases of using HTMX with FastAPI:
    1. Click-to-edit-pattern
    2. Inline validation
    3. Editing a row in a table
    4. Removing a row from a table
    5. Adding a row to a table
    6. Bulk update
    7. Search and filtering
    8. Infinite scroll
  2. In the templates, we'll use Tailwind's classes
  3. Finally, we'll add Alpine.js into the mix to improve the use case where HTMX can't:
    1. Tooltip
    2. "Select all" checkbox
    3. Showing additional data upon demand

Part 3

In Part 3, we'll productionize our app using the following tools:

  1. Cypress (to test some of the functionality we added with HTMX and Alpine.js)
  2. Postgres
  3. Docker and Docker Compose

Finally, we'll deploy the application to Heroku.

What You'll Be Building

HTMX combined with FastAPI is great for apps that manage data -- adding, changing, and removing some data. We'll create a party organizer app that covers the following use cases:

  1. Creating a new party
  2. Listing the parties
  3. Editing a single party
  4. Listing gifts in a table format
  5. Adding a new gift as a record on a table
  6. Editing and removing a gift row in a table
  7. Listing party guests with their attending status
  8. Updating the attending status for multiple guests
  9. Searching and filtering through the guest list
  10. Infinite scroll through the parties list



Mark as Completed