Files
Htmx/docs/Components/Badge.md
T
2026-05-04 19:57:48 +05:00

4.7 KiB

Badge

A small inline label pill. Used to indicate status, category, or count. Four variants cover most use-cases.


HTML structure

span.{base classes + variant classes}
  {text}

CSS mechanics

Class Effect
inline-flex items-center rounded-full Pill shape that sits inline with text
px-2.5 py-0.5 text-xs font-semibold Compact size and bold label
transition-colors Smooth color changes on hover
focus:ring-2 focus:ring-ring focus:ring-offset-2 Keyboard focus outline

Variants:

Variant Classes
default bg-primary text-primary-foreground hover:bg-primary/80
secondary bg-secondary text-secondary-foreground hover:bg-secondary/80
destructive bg-destructive text-destructive-foreground hover:bg-destructive/80
outline text-foreground border border-input hover:bg-accent

Constructor signature

public Badge(string text, string variant = "default")
Parameter Description
text Label displayed inside the badge
variant "default" / "secondary" / "destructive" / "outline"

Usage examples

Basic badges

new Badge("New")
new Badge("Beta",    variant: "secondary")
new Badge("Error",   variant: "destructive")
new Badge("Pending", variant: "outline")

Status indicator in a table cell

// Render to bytes and embed in table cell HTML
var writer = new System.Buffers.ArrayBufferWriter<byte>();
new Badge("Active", variant: "default").Render(new HtmxRenderContext(writer));
var badgeHtml = System.Text.Encoding.UTF8.GetString(writer.WrittenSpan);

new Table(
    headers: new[] { "Name", "Status" },
    rows: users.Select(u => new[] { u.DisplayName ?? "", badgeHtml }))

Embedding in a page slot

<!-- MyPage.htmx -->
<div class="flex items-center gap-2">
  <span class="text-sm">Status:</span>
  $$StatusBadge$$
</div>
// MyPage.htmx.cs
public IHtmxComponent StatusBadge { get; }

public MyPage(string status)
{
    StatusBadge = status == "active"
        ? new Badge("Active")
        : new Badge("Inactive", variant: "secondary");
}

protected override void RenderStatusBadge(HtmxRenderContext ctx)
    => StatusBadge.Render(ctx.Next());

Tips and tricks

  • Badge does not have a click handler — wrap it in an <a> or a Button if you need interactivity.
  • All four variants respond to focus, so a Badge embedded inside a focusable element will show a ring.
  • For a count badge (e.g. "3 new") just include the count in the text string.
  • To render a Badge inside raw HTML strings (e.g. inside a Table cell or Card content), render it eagerly to a string in the constructor rather than relying on slot rendering.

Complete page example

Templates/OrdersPage.htmx

<div class="max-w-4xl mx-auto py-10">
  <h1 class="text-2xl font-bold mb-6">Orders</h1>
  $$OrdersTable$$
</div>

Templates/OrdersPage.htmx.cs

namespace Htmx.ApiDemo.Templates;

public sealed class OrdersPage : OrdersPageBase
{
    private readonly IHtmxComponent _table;

    public OrdersPage(IEnumerable<Order> orders)
    {
        _table = new Components.Table(
            headers: new[] { "Order", "Customer", "Amount", "Status" },
            rows: orders.Select(o => new[]
            {
                System.Net.WebUtility.HtmlEncode(o.Id),
                System.Net.WebUtility.HtmlEncode(o.CustomerName),
                $"${o.Total:F2}",
                BadgeHtml(o.Status),
            }));
    }

    private static string BadgeHtml(string status)
    {
        var variant = status switch
        {
            "paid"      => "default",
            "pending"   => "secondary",
            "cancelled" => "destructive",
            _           => "outline",
        };
        var buf = new System.Buffers.ArrayBufferWriter<byte>();
        new Components.Badge(status, variant).Render(new HtmxRenderContext(buf));
        return System.Text.Encoding.UTF8.GetString(buf.WrittenSpan);
    }

    protected override void RenderOrdersTable(HtmxRenderContext ctx)
        => _table.Render(ctx.Next());
}

GET handler

[Handler]
[MapGet("/orders")]
public static partial class GetOrdersHandler
{
    public record Query();

    private static Task<IResult> HandleAsync(
        Query _,
        HttpContext ctx,
        CancellationToken ct)
    {
        // Replace with real data source
        var orders = new[]
        {
            new Order("ORD-001", "Alice Smith",  42.00m, "paid"),
            new Order("ORD-002", "Bob Jones",    18.50m, "pending"),
            new Order("ORD-003", "Carol White",  99.99m, "cancelled"),
        };
        return ctx.WriteHtmxPage(new OrdersPage(orders), title: "Orders");
    }
}