# HTMX con partes centrales de ASP.NET: El renacimiento del lado del servidor

<datetime class="hidden">2025-11-28T12:00</datetime>

<!--category-- HTMX, ASP.NET Core, Web Development, HTMX.NET -->
## Introducción

Si usted ha construido aplicaciones tradicionales ASP.NET Core MVC, usted sabe el problema: que temió "clic flash" cuando los usuarios navegan entre las páginas. Recargas de página completa, el navegador cromado parpadea, el contenido salta alrededor como la nueva página renderiza. Funciona, pero no lo hace *sentir* moderno.

La técnica de devolver fragmentos HTML parciales del servidor y cambiarlos en el DOM resuelve esto - y no es nuevo. He estado usando este patrón desde los días de jQuery, e incluso antes de eso con vainilla JavaScript y `XMLHttpRequest`. Lo que ha cambiado es cómo *elegante* se ha convertido en HTMX.

HTMX nos da una manera declarativa de hacer lo que siempre hemos hecho: devolver HTML renderizado por el servidor y cambiarlo a la página. No más JavaScript personalizado de escritura para cada interacción. No más elegir entre desarrollo del lado del servidor "adecuado" y experiencia de usuario suave. Con HTMX, obtenemos ambos.

> **Artículo del compañero:** Este artículo se centra en el lado de integración ASP.NET Core. Para una inmersión profunda en eventos HTMX, ciclo de vida y extensiones personalizadas, vea mi artículo de acompañamiento: [Una gira de silbido de extensiones HTMX y el uso de HTMX con ASP.NET Core](/blog/htmxandaspnetcore).

En este artículo, te mostraré cómo HTMX se integra maravillosamente con ASP.NET Core parcials, cómo el excelente **HTMX.NET** biblioteca lo hace aún mejor, y cómo mi [principalmentelucid.pagingtaghelper](https://github.com/scottgal/mostlylucid.pagingtaghelper) El paquete NuGet utiliza HTMX que proporciona una potente paginación con una configuración mínima.

El enfoque es framework-agnóstico también - Django añadió fragmentos de plantilla en la versión 6.0, Rails tiene Turbo Frames, y el ecosistema web más amplio está adoptando patrones HTML-over-the-wire. Es un buen momento para construir aplicaciones de servidor.

[TOC]

## ¿Qué es HTMX?

HTMX es una biblioteca que le permite acceder a las funciones modernas del navegador directamente desde HTML, en lugar de escribir JavaScript. Se extiende HTML con atributos que le permiten hacer peticiones AJAX, intercambiar contenido y crear interacciones ricas - todo sin dejar su marcado.

Los atributos clave que usará con más frecuencia:

- `hx-get`, `hx-post`, `hx-put`, `hx-delete` - Hacer peticiones HTTP
- `hx-target` - Especifique dónde poner la respuesta
- `hx-swap` - Controlar cómo se intercambia el contenido (innerHTML, outerHTML, etc.)
- `hx-trigger` - Definir qué desencadena la petición (clic, cambio, carga, etc.)
- `hx-push-url` - Actualizar la URL del navegador sin una recarga completa de la página

Esta es la belleza de esto: sigues escribiendo código del lado del servidor, devolviendo HTML renderizado por el servidor. Sin API JSON, sin plantillas del lado del cliente, sin tuberías de compilación.

## Un patrón tan antiguo como AJAX itself

Antes de HTMX, logramos el mismo efecto con mucho más ceremonia. Así es como se veían las actualizaciones parciales en la era de jQuery:

```javascript
// jQuery circa 2010
$('#load-more').click(function() {
    $.ajax({
        url: '/posts/page/' + currentPage,
        success: function(html) {
            $('#posts-container').append(html);
            currentPage++;
        }
    });
});
```

E incluso antes, con el JavaScript de vainilla:

```javascript
// Vanilla JS circa 2005
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
    if (xhr.readyState === 4 && xhr.status === 200) {
        document.getElementById('content').innerHTML = xhr.responseText;
    }
};
xhr.open('GET', '/partial-content', true);
xhr.send();
```

El patrón del lado del servidor era idéntico: devolver fragmentos HTML, intercambiarlos en el DOM. HTMX simplemente mueve esta lógica de JavaScript a atributos HTML, haciéndolo declarativo, reconocible y mucho menos propenso a errores. La innovación no es la técnica; es la interfaz.

Los desarrolladores de ASP.NET han estado haciendo esto durante años. UpdatePanels en WebForms (2005), `PartialView()` en MVC desde el primer día, `Html.RenderAction()` para fragmentos componibles - la capacidad siempre ha estado allí. Lo que nos faltaba era una manera elegante y estandarizada de conectarlo en el lado del cliente. HTMX llena ese hueco perfectamente.

La industria en general también ha estado redescubriendo estos patrones. Términos como "SSR" (Server-Side Rendering), "hybrid rendering", y "islands architecture" están esencialmente describiendo lo que los marcos del lado del servidor siempre han hecho, pero con ojos frescos. Es la validación que la escala de enfoque de servidor-renderizado, realiza, y - con las herramientas adecuadas - proporciona una experiencia de usuario excelente.

## Configuración de HTMX en el núcleo de ASP.NET

En primer lugar, incluya HTMX en su diseño. Puede utilizar un CDN o servirlo localmente:

```html
<script src="https://unpkg.com/htmx.org@2.0.0"></script>
```

No hay paso de construcción, no hay instalación de npm, no hay configuración webpack. Sólo deja una etiqueta de guión y te vas a las carreras.

## Alpine.js: El componente cliente-lado

Para la reactividad del lado del cliente (mostrando/ocultando elementos, alternando estados, estado de interfaz de usuario local), [Alpine.js](https://alpinejs.dev/) A sólo 15KB gzipped, proporciona reactividad declarativa Vue/React-como sin la hinchazón.

```html
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
```

Así es como trabajan juntos:

```razor
<div x-data="{ open: false }">
    <button x-on:click="open = !open">Toggle</button>
    <div x-show="open" x-transition>
        <button hx-get="/api/data" hx-target="#results">Load Data</button>
    </div>
</div>
```

Alpine maneja la interfaz de usuario local (la palanca), HTMX maneja las llamadas del servidor (la búsqueda de datos). A lo largo de este artículo, verá este patrón - Alpine para la reactividad del cliente, HTMX para las interacciones del servidor.

## Biblioteca HTMX.NET

[Khalid Abuhakmeh](https://khalidabuhakmeh.com/about)'s [HTMX.NET](https://github.com/khalidabuhakmeh/Htmx.Net) biblioteca proporciona la integración de ASP.NET Core de primera clase. Disponible como `Htmx` y `Htmx.TagHelpers` NuGet paquetes, se siente nativo de .NET y hace que trabajar con HTMX sea un placer absoluto. Encontrarás más de Khalid excelente trabajo de código abierto en su [GitHub](https://github.com/khalidabuhakmeh).

### Instalación

```bash
dotnet add package Htmx
dotnet add package Htmx.TagHelpers
```

En tu `_ViewImports.cshtml`:

```razor
@addTagHelper *, Htmx.TagHelpers
```

### El método de extensión IsHtmx()

La característica más útil es la `Request.IsHtmx()` método de extensión, que le indica si la solicitud vino de HTMX. Esto le permite devolver una vista completa o sólo una parcial:

```csharp
[HttpGet]
public async Task<IActionResult> Index(int page = 1, int pageSize = 20)
{
    var posts = await blogViewService.GetPagedPosts(page, pageSize);

    if (Request.IsHtmx())
        return PartialView("_BlogSummaryList", posts);

    return View("Index", posts);
}
```

Este patrón es absolutamente brillante. Una sola acción controladora sirve a ambos:

- Cargas de página completa (cuando los usuarios navegan directamente o actualizan)
- Actualizaciones parciales (cuando HTMX hace la solicitud)

No hay endpoints API separados, no hay lógica duplicada, no hay serialización de JSON.

> **Un concepto erróneo común:** Muchos desarrolladores de ASP.NET piensan que usted necesita el `_` prefijo (como `_BlogSummaryList.cshtml`) para obtener una representación parcial. ¡Tú no! `PartialView()` método en sí mismo le dice a ASP.NET Core para saltarse el diseño - está diciendo "olvidar el diseño, sólo renderizar este bit". `return PartialView("SearchResults", model)` con un archivo de vista regular y funciona perfectamente. La convención de subrayado se originó en ASP.NET Web Pages (WebMatrix) donde se impidió que los archivos se sirvan directamente a través de URL - pero MVC siempre ha protegido todas las vistas de acceso directo de todos modos. Es puramente una convención de nombres para ayudar a identificar vistas *Propósito* como parciales.

### Ayudantes de etiquetas HTMX.NET

HTMX.NET proporciona ayudantes de etiquetas que hacen que trabajar con controladores sea más limpio. En lugar de escribir cadenas de ruta, puede utilizar referencias fuertemente mecanografiadas:

```razor
<button
    hx-controller="Comment"
    hx-action="GetCommentForm"
    hx-post
    hx-target="#commentform">
    Reply
</button>
```

Esto genera la ruta correcta usando el sistema de enrutamiento de ASP.NET Core. Si cambia el nombre de su controlador o acción, su IDE lo captará. ¡Mucho mejor que las cadenas mágicas!

He aquí un ejemplo real del sistema de comentarios de este blog:

```razor
<button
    class="btn btn-outline btn-sm mb-4"
    hx-action="Comment"
    hx-controller="Comment"
    hx-post
    hx-vals
    x-on:click.prevent="window.mostlylucid.comments.setValues($event)"
    hx-on="htmx:afterSwap: window.scrollTo({top: 0, behavior: 'smooth'})"
    hx-swap="outerHTML"
    hx-target="#commentform">
    Comment
</button>
```

Observe cómo HTMX juega bien con Alpine.js (`x-on:click.prevent`) para aquellos trozos ocasionales de interactividad del lado del cliente.

### Otros ayudantes de HTMX.NET

La biblioteca también proporciona:

- `Request.IsHtmxNonBoosted()` - Compruebe si es una solicitud HTMX pero no aumentada
- `Request.IsHtmxRefresh()` - Compruebe si es una petición de restauración de historial
- Ayudantes de respuesta para encabezados HTMX (desencadenadores, redireccionamientos, etc.)

## Ejemplo del mundo real: Búsqueda con parciales

Aquí está el controlador de búsqueda de este blog, mostrando el patrón de retorno de tres niveles:

```csharp
[HttpGet]
[OutputCache(Duration = 3600, VaryByHeaderNames = new[] { "hx-request", "pagerequest" })]
public async Task<IActionResult> Search(
    string? query,
    int page = 1,
    int pageSize = 10,
    [FromHeader] bool pagerequest = false)
{
    var searchModel = await BuildSearchModel(query, page, pageSize);

    if (pagerequest && Request.IsHtmx())
        return PartialView("_SearchResultsPartial", searchModel.SearchResults);

    if (Request.IsHtmx())
        return PartialView("SearchResults", searchModel);

    return View("SearchResults", searchModel);
}
```

Tres vías de retorno para tres escenarios:

1. Solicitudes de paginación - mínimo parcial (sólo la lista de resultados)
2. Cambios de filtro - sección parcial (resultados con filtros)
3. Navegación directa - página completa (distribución + todo)

El punto de vista parcial (`_SearchResultsPartial.cshtml`) utiliza el ayudante de la etiqueta de paginación:

```razor
@model Mostlylucid.Models.Blog.PostListViewModel
<div class="pt-2" id="content">
    @if (Model.Data?.Any() is true)
    {
        <div class="inline-flex w-full items-center justify-center pb-4">
            @if (Model.TotalItems > Model.PageSize)
            {
                <pager
                    x-ref="pager"
                    link-url="@Model.LinkUrl"
                    hx-boost="true"
                    hx-target="#content"
                    hx-swap="show:none"
                    page="@Model.Page"
                    page-size="@Model.PageSize"
                    total-items="@Model.TotalItems"
                    hx-headers='{"pagerequest": "true"}'>
                </pager>
            }
        </div>
        @foreach (var post in Model.Data)
        {
            <partial name="_ListPost" model="post"/>
        }
    }
</div>
```

Romper el ayudante de la etiqueta del buscapersonas:

- `hx-boost="true"` - Intercepta enlaces, convierte a AJAX
- `hx-target="#content"` - Dónde inyectar la respuesta
- `hx-headers='{"pagerequest": "true"}'` - Encabezado personalizado le dice al controlador que es paginación
- El controlador comprueba `Request.IsHtmx() && pagerequest` para devolver sólo el mínimo parcial

## El paquete sobre todolucid.pagingtaghelper

Escribí [principalmentelucid.pagingtaghelper](https://github.com/scottgal/mostlylucid.pagingtaghelper) para evitar el código de paginación repetitivo. Es HTMX-primero pero funciona sin JavaScript también.

### Instalación

```bash
dotnet add package mostlylucid.pagingtaghelper
```

Añadir a `_ViewImports.cshtml`:

```razor
@addTagHelper *, mostlylucid.pagingtaghelper
```

### Características principales

Aplicación `IPagingModel<T>` y has terminado:

```csharp
public class BasePagingModel<T> : IPagingModel<T> where T : class
{
    public int Page { get; set; }
    public int TotalItems { get; set; }
    public int PageSize { get; set; }
    public string LinkUrl { get; set; }
    public List<T> Data { get; set; }
}
```

**Lo que obtienes:**

- Se requiere configuración cero
- Múltiples marcos de interfaz de usuario (TailwindCSS + DaisyUI, Bootstrap 5, vistas personalizadas)
- Soporte de modo oscuro
- 8 idiomas incorporados
- Cabeceras clasificables, selectores de tamaño de página
- Mejora progresiva (funciona sin JavaScript)
- Soporte token de continuación para bases de datos NoSQL

El ayudante de etiquetas genera enlaces que preservan las cadenas de consulta, soportan cabeceras personalizadas e integran perfectamente con HTMX (vea el ejemplo anterior).

## Diagrama de flujo HTMX

Así es como todo el sistema encaja:

```mermaid
graph TB
    A[Browser] -->|"Initial page load"| B[Controller Action]
    B -->|"Request.IsHtmx() = false"| C[Return Full View]
    C --> D[Render Layout + Partial]

    A -->|"User clicks pagination/filter"| E[HTMX Request]
    E -->|"hx-get with headers"| F[Same Controller Action]
    F -->|"Request.IsHtmx() = true"| G{Check Headers}
    G -->|"pagerequest header"| H[Return Minimal Partial]
    G -->|"No special header"| I[Return Section Partial]

    H --> J[Swap Content in Target]
    I --> J

    J -->|"User clicks another link"| E

    style B stroke:#333,stroke-width:2px
    style F stroke:#333,stroke-width:2px
    style C stroke:#0066cc,stroke-width:2px
    style H stroke:#00cc66,stroke-width:2px
    style I stroke:#00cc66,stroke-width:2px
```

## Comparando con otros marcos

### Fragmentos de plantilla de Django

Django añadió la representación de plantilla parcial adecuada en la versión 6.0 (diciembre 2024) con fragmentos de plantilla. Antes de eso, los desarrolladores de Django normalmente usaban etiquetas de inclusión o paquetes de terceros como django-render-block. `PartialView()` desde la versión 1.0 en 2016 - diferentes marcos, diferentes líneas de tiempo, pero el mismo destino: fragmentos HTML para HTMX.

### Turboframes de carriles

Ruby on Rails tiene Turbo Frames (parte de Hotwire), que es similar en espíritu:

```erb
<%= turbo_frame_tag "posts" do %>
  <%= render @posts %>
<% end %>
```

La diferencia es que Turbo requiere marcadores de marco específicos tanto en la solicitud como en la respuesta. HTMX es más flexible - cualquier punto final puede devolver cualquier HTML, y usted decide dónde va con `hx-target`.

### Phoenix LiveView

Phoenix LiveView de Elixir adopta un enfoque diferente con conexiones persistentes de WebSocket y estado del lado del servidor:

```elixir
def handle_event("load_more", _params, socket) do
  {:noreply, assign(socket, posts: load_more_posts())}
end
```

LiveView es brillante para aplicaciones en tiempo real, pero requiere infraestructura WebSocket y memoria del servidor para las conexiones. HTMX utiliza HTTP antiguo - apátrida, caché, escalable. Para un blog, eso es perfecto.

## Consideraciones sobre el desempeño

**Caché de salida**: El `OutputCache` atributo varía según `hx-request` encabezado, en caché páginas completas y parciales por separado:

```csharp
[OutputCache(Duration = 3600, VaryByHeaderNames = new[] { "hx-request", "pagerequest" })]
```

**Eficiencia de la red**: HTML renderizado por servidor es a menudo más pequeño que JSON + plantillas del lado del cliente, requiere menos viajes de ida y vuelta, y cachés correctamente.

**Tamaño del paquete**: HTMX (14KB) + opcional Alpine.js (15KB) + ayudante de etiqueta de paginación (0KB, lado servidor) = inferior a 30KB total. Compare eso con una aplicación típica de React (200KB+).

## Patrones avanzados

**Actualizaciones optimistas de la interfaz de usuario** - Combine HTMX y Alpine para una retroalimentación instantánea:

```razor
<div x-data="{ count: @Model.CommentCount }">
    <button hx-post="/comment/like" x-on:click="count++" hx-on::after-request="count = $event.detail.xhr.response">
        Likes: <span x-text="count"></span>
    </button>
</div>
```

El conteo se actualiza inmediatamente (optimista), luego se sincroniza con la respuesta del servidor.

**Swaps fuera de banda** - Actualizar varias secciones de página de una respuesta:

```razor
<div id="main-content"><!-- Main response --></div>
<div id="notification-count" hx-swap-oob="true"><span>5 new</span></div>
```

Perfecto para tarjetas de notificación, recuentos de carros, etc. Cubro este patrón en profundidad en [Mostrar tostada y intercambio con HTMX](/blog/showingtoastandswappingwithhtmx).

**Plantillas del lado del cliente con WebAPI** - A veces quieres una experiencia intermedia: HTML renderizado por servidor para la mayoría de las cosas, pero JSON de un WebAPI para contenido dinámico específico. [extensión cliente-side-templates](https://htmx.org/extensions/client-side-templates/) le permite hacer exactamente esto:

```html
<script src="https://unpkg.com/htmx-ext-client-side-templates@2.0.0/client-side-templates.js"></script>
<script src="https://unpkg.com/mustache@latest"></script>

<div hx-ext="client-side-templates">
    <template id="post-template" type="text/mustache">
        {{#posts}}
        <div class="post">
            <h3>{{title}}</h3>
            <p>{{excerpt}}</p>
        </div>
        {{/posts}}
    </template>

    <button hx-get="/api/posts"
            hx-target="#post-list"
            mustache-template="post-template">
        Load Posts
    </button>
    <div id="post-list"></div>
</div>
```

Este enfoque funciona con plantillas Mustache, Handlebars o Nunjucks. Su WebAPI devuelve JSON, pero HTMX maneja el lado del cliente de renderizado. Es particularmente útil cuando tiene una API existente o necesita compartir datos con aplicaciones móviles. Para obtener más detalles sobre extensiones HTMX incluyendo plantillas del lado del cliente, consulte [el artículo de acompañamiento](/blog/htmxandaspnetcore).

## Gotchas & Tips

**Herramienta de depuración:** Instalar la [Extensión del depurador HTMX](https://chromewebstore.google.com/detail/htmx-debugger/) - muestra cada petición, respuesta e intercambio en tiempo real.

### Tokens CSRF

Los tokens antifalsificación de ASP.NET Core necesitan un manejo especial con AJAX. HTMX.NET proporciona varias opciones limpias. `HtmxAntiforgeryScriptEndpoint`:

```csharp
// In Program.cs
app.MapHtmxAntiforgeryScript();
```

```html
<!-- In your layout head -->
<script src="@HtmxAntiforgeryScriptEndpoints.Path" defer></script>
```

O use el ayudante de etiqueta: `<meta name="htmx-config" includeAspNetAntiforgeryToken="true" />`. Véase [Artículo de Khalid sobre Tokens Anti-Forgery HTMX](https://khalidabuhakmeh.com/htmx-requests-with-aspnet-core-anti-forgery-tokens) para más detalles.

### Alpine.js @ Taquigrafía en Razor

Alpines `@click` conflictos de taquigrafía con Razor's `@` Sintaxis. Utilice el formulario explícito en su lugar:

```razor
<button x-on:click="doSomething()">Click me</button>  <!-- Instead of @click -->
<div x-bind:class="isOpen ? 'block' : 'hidden'"></div>  <!-- Instead of :class -->
```

O escapar con `@@click`, pero la sintaxis explícita es más clara.

### Gestión del historial

**Controlar las entradas del historial:** Por defecto, HTMX empuja cada solicitud al historial. Para paginación/filtros donde no desea contaminación del historial:

```razor
<paging model="@Model" hx-push-url="false">  <!-- Don't add history entries -->
```

O usar `hx-replace-url="true"` actualizar la URL sin añadir entradas.

**El problema Phantom Parcial:** Navegador hacia atrás / hacia adelante muestra sólo un fragmento parcial sin diseño. `hx-history-elt` en su contenedor de contenido:

```html
<div class="container mx-auto" id="contentcontainer" hx-history-elt>
    @RenderBody()
</div>
```

Esto le dice a HTMX qué elemento fotografiar, preservando el diseño circundante al restaurar la historia.

### Caché CDN (Cloudflare, etc.)

**Síntoma:** HTMX funciona localmente, pero se rompe detrás de un CDN - el contenido incorrecto se cachea.

**Causa raíz:** Los CDN ignoran el `HX-Request` encabezado. Su servidor devuelve contenido diferente basado en este encabezado, pero la CDN los guarda en caché de forma idéntica.

**ASP.NET Core fix:** Uso `VaryByHeaderNames`:

```csharp
[OutputCache(Duration = 3600, VaryByHeaderNames = new[] { "hx-request" })]
```

**CDN fix:** Configurar reglas de caché para incluir `HX-Request` para Cloudflare: Dashboard → Caching → Reglas de caché → Clave de caché personalizada → Encabezados → Incluir `HX-Request`.

### El debate de hx-boost

[`hx-boost`](https://htmx.org/attributes/hx-boost/) convierte enlaces normales en peticiones AJAX. [Página de peculiaridades de HTMX](https://htmx.org/quirks/) algunos miembros del equipo principal recomiendan evitarlo (descartes `<head>` contenido, afecta la localidad de comportamiento), mientras que otros lo encuentran bien para victorias rápidas.

```razor
<div hx-boost="true" hx-target="#contentcontainer">
    <a asp-action="Show" asp-route-slug="@post.Slug">Read More</a>
</div>
```

Este blog lo utiliza ampliamente. Al dirigirse a contenedores específicos, explícito `hx-get` es más claro, pero `hx-boost` funciona si eres consistente. Inhabilitar selectivamente con `hx-boost="false"` sobre los elementos infantiles.

## Conclusión

HTMX con ASP.NET Los parciales del núcleo representan un retorno a la simplicidad del lado del servidor sin sacrificar la UX moderna.

- Interacciones dinámicas, similares a las del SPA
- Renderización del lado del servidor (genial para SEO)
- Caché HTTP adecuado
- Mínimo JavaScript
- Mejora progresiva
- Enrutamiento seguro con HTMX.NET
- Paginación de configuración cero con principalmentelucid.pagingtaghelper

El enfoque renderizado por el servidor ha resistido la prueba del tiempo, y con HTMX, finalmente tiene la elegante herramienta del lado del cliente que se merece. Puede construir aplicaciones web robustas y performantes utilizando patrones que han funcionado durante décadas - que sólo han estado esperando la herramienta adecuada para hacerlos brillar de nuevo.

## Artículos relacionados en este blog

### Artículo del compañero

Este artículo es parte de una serie de dos partes sobre HTMX con ASP.NET Core:

1. **Este artículo** - Se centra en la integración de ASP.NET Core, vistas parciales, HTMX.NET y paginación
2. **[Un recorrido por silbidos de extensiones HTMX](/blog/htmxandaspnetcore)** - Inmersión profunda en eventos HTMX, ciclo de vida, arquitectura de extensión y extensiones personalizadas

### Más artículos de HTMX

- [Añadiendo llamadas con HTMX](/blog/addpagingwithhtmx) - El artículo original sobre la implementación de la paginación con el viejo PaginationTagHelper
- [Caché de núcleo ASP.NET con HTMX](/blog/aspnetcachingwithhtmx) - Inmersión profunda en estrategias de almacenamiento en caché para solicitudes HTMX
- [Auto-refrescar con Alpine y HTMX](/blog/autorefreshwithalpineandhtmx) - Combinación Alpine.js con HTMX para componentes reactivos
- [Hacer que su sitio sea más similar al SPA con HTMX](/blog/htmxtomakeyoursitemorespalike) - Navegación tipo SPA sin marcos JavaScript
- [Uso de SweetAlert para indicadores HX](/blog/usingsweetalertforhxindicators) - Hermosos indicadores de carga con HTMX
- [Mostrar tostada y intercambio con HTMX](/blog/showingtoastandswappingwithhtmx) - Notificaciones de tostadas activadas por el servidor

## Lectura adicional

**Documentación oficial:**

- [Documentación HTMX](https://htmx.org/docs/) - La documentación oficial HTMX
- [Ejemplos HTMX](https://htmx.org/examples/) - Ejemplos prácticos de patrones HTMX
- [Extensiones HTMX](https://htmx.org/extensions/) - Extensiones HTMX oficiales
- [Alpine.js Documentación](https://alpinejs.dev/) - Oficial Alpine.js docs
- [Alpine.js Ejemplos](https://alpinejs.dev/examples) - Patrones prácticos Alpine.js
- [ASP.NET Puntos de vista parciales básicos](https://learn.microsoft.com/en-us/aspnet/core/mvc/views/partial) - Guía de Microsoft para vistas parciales
- [Caché de salida básico ASP.NET](https://learn.microsoft.com/en-us/aspnet/core/performance/caching/output) - Documentación oficial de almacenamiento en caché

**Bibliotecas y herramientas:**

- [HTMX.NET GitHub](https://github.com/khalidabuhakmeh/Htmx.Net) - El código fuente de la biblioteca HTMX.NET
- [HTMX.NET NuGet](https://www.nuget.org/packages/Htmx/) - HTMX.NET en NuGet
- [Htmx.TagHelpers NuGet](https://www.nuget.org/packages/Htmx.TagHelpers/) - Ayudantes de etiquetas HTMX en NuGet
- [Sitio web de Khalid Abuhakmeh](https://khalidabuhakmeh.com/) - Creador de HTMX.NET, con excelentes posts de blog
- [GitHub de Khalid Abuhakmeh](https://github.com/khalidabuhakmeh) - Proyectos .NET de código abierto más brillantes
- [mayormente lucid.pagingtaghelper GitHub](https://github.com/scottgal/mostlylucid.pagingtaghelper) - Mi código fuente del ayudante de la etiqueta de paginación
- [principalmentelucid.pagingtaghelper NuGet](https://www.nuget.org/packages/mostlylucid.pagingtaghelper/) - El paquete de NuGet

**Recursos comunitarios:**

- [Discord HTMX](https://htmx.org/discord) - Apoyo comunitario activo
- [Ensayos HTMX](https://htmx.org/essays/) - Artículos reflexivos sobre filosofía HTMX
- [Libro de sistemas Hypermedia](https://hypermedia.systems/) - Libro en línea gratuito sobre la construcción de aplicaciones de hipermedios