CodewCaro.

React vs. HTMX: A Comparative Look at Modern Web Development

Caroline Cah
Caroline Cah

For a long time it has been taught that in order for us to create rich UI's we need to create React components.


Even though these tools are super powerful, sometimes they feel like way too much, especially if you're more into backend stuff and find the whole frontend scene a bit of a maze.


HTMX, takes traditional concepts back. It's like the perfect middle ground between old-school server-side rendering and all the flashy client-side interactivity we see today. And the best part? You don't have to drown in JavaScript to get your site up; HTMX has your back.


This article dives into my findings of React and HTMX, comparing their philosophies, use cases, and performance implications to help developers make informed decisions. The JavaScript library for building user interfaces, and a newcomer HTMX, a modern toolkit that extends HTML to enrich web applications with minimal JavaScript.


Key Features of HTMX


This Hypertext Markup Extension is all about keeping things simple and light, so you can toss it into your current project without any hassle. And while it's pretty straightforward, HTMX packs a bunch of cool features that really amp up its game in web development.


React: The JavaScript Powerhouse


Developed by Facebook, React has become synonymous with modern web development. React's component-based architecture allows developers to build reusable UI elements, making it an great choice for large-scale, dynamic web applications. With React, you describe your UI declaratively and React takes care of efficiently updating and rendering components when your data changes. Working with components gives developers a sense of making UI rich.


But what is a rich UI?


No full page reload? Native-like UI element? The feeling of "I'm not in a web browser" ?


Strengths


The strengths I found on React were many. React's performance is generally great, especially for single-page applications (SPAs) where dynamic content and interactivity are paramount. However, the need for JavaScript to render content can affect initial load times and SEO if not correctly managed, though solutions like server-side rendering (SSR) and static site generation (SSG) with frameworks like Next.js help mitigate these issues. Also complicating state management in libraries such as Redux. Redux's global state management means that any state change triggers a re-render of all connected components, which can lead to performance issues in large-scale applications. For small to medium-sized projects, the overhead of integrating and maintaining libraries such as Redux might not be justified compared to the benefits it brings.


HTMX: HTML Extended for Interactivity


Developed by Big Sky Software, HTMX has an impressing weight of 2.9 kB compared to React's 6.4 kB. HTMX has features built on AJAX requesting and some other minor features while React has composability (inter-relations between components), one-way data binding, state management and hooks. The ecosystem is extensive for React and quite small but growing for HTMX.


React is great for building structured web applications, but the complexity can lead to great overhead for developers seeking simplicity. Putting large amount of logic handling on the frontend can make applications less performant aswell. This is where HTMX comes in.


HTMX is a relatively new entrant, designed to enhance HTML's capabilities to build modern web applications without relying heavily on JavaScript frameworks. By using custom attributes, HTMX enables you to add dynamic behavior directly to your HTML, making asynchronous calls, updating content, and more, with minimal JavaScript.


React vs. HTMX: Choosing the Right Tool


When to Choose React:


You're building a complex SPA with extensive interactive elements.


You prefer a JavaScript-centric development experience with stateful components.


Your project benefits from a large ecosystem and community support.


When to Choose HTMX:


You're enhancing a traditional server-rendered application with dynamic features.


You prefer writing less JavaScript and leveraging the server for rendering logic.


Your application's interactivity can be achieved with simpler updates and doesn't warrant a full SPA architecture.


AJAX stands for Asynchronous JavaScript And XML. Triggering AJAX Requests with HTMX At the core of HTMX lies the capability to initiate AJAX requests straight from HTML markup. This functionality is enabled through specific attributes, each corresponding to a different type of HTTP request:


With HTMX, you can perform state changes directly in your HTML by using custom attributes.


Below I created an example of code that does the same thing but uses HTMX with Server-Side Flask in Python compared to the traditional Javascript React combination.


HTMX


This HTML is for adding a simple UI for adding a new task. The server part then renders each task item. With HTMX, you can handle interactions with minimal client-side code, relying on the server to manage the state and render the updated list.


<form hx-post="/add-task" hx-target="#task-list" hx-swap="outerHTML">
  <input type="text" name="newTask" placeholder="Add a new task">
  <button type="submit">Add Task</button>
</form>

<ul id="task-list" hx-get="/tasks" hx-swap="outerHTML">
  <!-- Server renders task items here -->
</ul>

<script src="https://unpkg.com/htmx.org"></script>

Server-Side (Python Flask):


Here the Python code uses Flask to handle the rendering of tasks. The server is responsible for maintaining the task list state and rendering the HTML, significantly simplifying client-side logic.


from flask import Flask, request, render_template_string, jsonify

app = Flask(__name__)
tasks = []

@app.route('/add-task', methods=['POST'])
def add_task():
    new_task = request.form['newTask']
    tasks.append({'id': len(tasks) + 1, 'text': new_task, 'completed': False})
    return render_updated_tasks()

@app.route('/toggle-task/<int:task_id>')
def toggle_task(task_id):
    for task in tasks:
        if task['id'] == task_id:
            task['completed'] = not task['completed']
            break
    return render_updated_tasks()

@app.route('/remove-task/<int:task_id>')
def remove_task(task_id):
    global tasks
    tasks = [task for task in tasks if task['id'] != task_id]
    return render_updated_tasks()

@app.route('/tasks')
def render_updated_tasks():
    # Render and return the updated task list
    tasks_html = render_template_string('''<ul id="task-list">{{ tasks|safe }}</ul>''', tasks=jsonify(tasks).data.decode('utf-8'))
    return tasks_html

if __name__ == "__main__":
    app.run(debug=True)

Updating states through Javascript


In React, you creates state updates through JavaScript, managing state within the component. Here tasks can be added, marked as complete, or removed. Each action triggers a state update, potentially leading to frequent re-renders. In this scenario, each interaction (adding, completing, or removing a task) requires updating the component's state and re-rendering the task list.


import React, { useState } from 'react';

function TaskList() {
  const [tasks, setTasks] = useState([]);
  const [newTask, setNewTask] = useState('');

  const addTask = () => {
    if (!newTask.trim()) return;
    setTasks([...tasks, { id: Date.now(), text: newTask, completed: false }]);
    setNewTask('');
  };

  const toggleComplete = (taskId) => {
    setTasks(tasks.map(task => 
      task.id === taskId ? { ...task, completed: !task.completed } : task
    ));
  };

  const removeTask = (taskId) => {
    setTasks(tasks.filter(task => task.id !== taskId));
  };

  return (
    <div>
      <input
        type="text"
        value={newTask}
        onChange={(e) => setNewTask(e.target.value)}
        placeholder="Add a new task"
      />
      <button onClick={addTask}>Add Task</button>
      <ul>
        {tasks.map((task) => (
          <li key={task.id}>
            <input
              type="checkbox"
              checked={task.completed}
              onChange={() => toggleComplete(task.id)}
            />
            {task.text}
            <button onClick={() => removeTask(task.id)}>Remove</button>
          </li>
        ))}
      </ul>
    </div>
  );
}

export default TaskList;

Conclusion


Is HTMX right for you? That has to be evaluated with your team or yourself. Ask yourself what type of architecture your application require. Does it require some already existing library that handles dates or fancy stylings? Then maybe React is for you nevertheless. Is it a one-page application? HTMX could be for you. I found it interesting to see what HTMX is about, simplifying state updating and the core concepts of web development. It can make wonders in making a rapid and simplified application, saving developers the overhead.

More posts