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:
- It's lightweight (~12kB min.gz)
- Server-side rendering is better for SEO
- Gradual learning curve
- No JavaScript knowledge is required
- Any HTML element can issue an HTTP request
- Any DOM event can trigger a request
- Besides the
GET
andPOST
(supported by default), you can also usePUT
,PATCH
, orDELETE
- Any HTML element (not just the entire window) can be the target for an update by a request
Disadvantages:
- Relatively new, so its community is small
- 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:
- It's highly customizable
- It uses a mobile-first approach
- It's very simple to style a dark version of your design
- The change (generally) applies to a single element, meaning you won't break something somewhere else
- There are official extensions for VSCode and JetBrains IDEs
Disadvantages:
- CSS is tightly coupled with HTML
- Since each class takes care of only one thing, a single element can use umpteen classes, thus hurting readability
- It doesn't provide components out-of-the-box, although there are free and payable solutions available -- e.g., Tailwind Elements or Flowbite
- 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:
- It's lightweight
- Syntax is similar to Vue and Angular, so Alpine.js will feel familiar if you have used any of them before
- You don't necessarily need to adapt your code to the framework -- you can just sprinkle Alpine.js where needed
- It's written in an HTML file, making it ideal to combine with HTMX and Tailwind
Disadvantages:
- 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.
- 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).
- 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:
x-data
creates the component and provides the data for it (count
).- The
span
and thebutton
are both connected to thecount
data. x-text="count"
sets the text content of the element (tocount
) andx-on:click="count++"
increments thecount
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:
- Setting up the FastAPI project, combining it with Jinja, SQLModel, and Alembic
- What is HTMX, and how to integrate it with FastAPI
- What is Tailwind, and how to integrate it with FastAPI
- 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.
- We'll go through the common use cases of using HTMX with FastAPI:
- Click-to-edit-pattern
- Inline validation
- Editing a row in a table
- Removing a row from a table
- Adding a row to a table
- Bulk update
- Search and filtering
- Infinite scroll
- In the templates, we'll use Tailwind's classes
- Finally, we'll add Alpine.js into the mix to improve the use case where HTMX can't:
- Tooltip
- "Select all" checkbox
- Showing additional data upon demand
Part 3
In Part 3, we'll productionize our app using the following tools:
- Cypress (to test some of the functionality we added with HTMX and Alpine.js)
- Postgres
- 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:
- Creating a new party
- Listing the parties
- Editing a single party
- Listing gifts in a table format
- Adding a new gift as a record on a table
- Editing and removing a gift row in a table
- Listing party guests with their attending status
- Updating the attending status for multiple guests
- Searching and filtering through the guest list
- Infinite scroll through the parties list
✓ Mark as Completed