Components
Output
The native <output> element (ARIA role="status") — a live result region for the outcome of a calculation or a server action. Tie it to its inputs with for. Its implicit aria-live means an htmx swap of its content is announced automatically — no JavaScript.
Installation
1. Install via the shadcn CLI
npx shadcn@latest add http://localhost/r/output.json2. Use it
import { Output } from "@/components/ui/output"
// Tie the result to the inputs that produced it via `for`.
<Output id="result" htmlFor="qty price" tone="primary">$0.00</Output>
// Server-computed: target THIS output, swap innerHTML so the
// implicit role="status" live region persists and is announced.
// change/input bubble from the child inputs up to the form.
<form hx-post="/cart/total" hx-trigger="change, input delay:300ms"
hx-target="#result" hx-swap="innerHTML">
<input name="qty" value="1" />
<Output id="result" htmlFor="qty" tone="primary">$0.00</Output>
</form>Or copy the source manually
/** @jsxImportSource hono/jsx */
import type { Child } from "hono/jsx"
import { cn, type ClassValue } from "@/registry/lib/cn"
// Output — shadcn-htmx, htmx v4 + Tailwind v4.
//
// A live result region: the outcome of a calculation or a server action,
// tied to the inputs that produced it via the `for` attribute.
//
// Source of truth — we render the real native <output> element:
// repos/mdn/files/en-us/web/html/reference/elements/output/index.md
// - `for` — space-separated list of the ids of elements that
// contributed input values to the calculation (lines 16-17).
// - `form` — associate the output with a <form> elsewhere in the
// document by its id; overrides an ancestor <form> (lines 18-21).
// - `name` — the element's name in the form.elements API (lines 23-24).
// - "Implicit ARIA role: status" (lines 119-120). shadcn/ui ships no
// Output component — this is a native-platform addition.
//
// Why no JS: <output>'s implicit role="status" IS a live region with an
// implicit aria-live="polite" and aria-atomic="true":
// repos/mdn/files/en-us/web/accessibility/aria/reference/roles/status_role/index.md:18
// repos/mdn/files/en-us/web/accessibility/aria/guides/live_regions/index.md:12
// "Including ... role='status' ... works as long as you add the
// attribute before the changes occur ... Start with an empty live
// region, then change the content inside the region."
// So an htmx swap of the output's CONTENT (hx-swap="innerHTML", with the
// <output> itself as the persistent target) is announced automatically —
// no aria-live wiring, no site.js. Native semantics do the work.
//
// htmx note: target the <output> and swap innerHTML so the live region
// element persists across requests (a fresh outerHTML swap would replace
// the region each time and defeat the announcement contract above).
// repos/htmx/www/reference.md — hx-target, hx-swap (innerHTML).
export type OutputTone = "default" | "muted" | "primary" | "destructive"
const base =
"inline-flex min-h-9 w-fit items-center gap-2 rounded-md border px-3 py-1.5 text-sm font-medium tabular-nums transition-colors " +
// htmx v4 adds .htmx-request to the swap target while a request that
// targets it is in flight — dim the stale value so the update reads as
// a refresh. See repos/htmx/www/reference.md (htmx-request class).
"[&.htmx-request]:opacity-60"
const tones: Record<OutputTone, string> = {
default: "border-border bg-card text-card-foreground",
muted: "border-transparent bg-muted text-muted-foreground",
primary: "border-transparent bg-primary text-primary-foreground",
destructive:
"border-destructive/30 bg-destructive/5 text-destructive dark:bg-destructive/10",
}
export function outputClasses(opts?: {
tone?: OutputTone
class?: ClassValue
}): string {
const tone = opts?.tone ?? "default"
return cn(base, tones[tone], opts?.class)
}
type OutputProps = {
// Space-separated list of the ids of the inputs that feed this result.
// Ties the output to its sources (MDN <output for>). React calls this
// `htmlFor`; on the native element it's the `for` attribute.
htmlFor?: string
// Associate with a <form> elsewhere in the document by its id. Without
// it, the output belongs to its nearest ancestor <form>, if any.
form?: string
// The element's name in the form.elements API.
name?: string
id?: string
tone?: OutputTone
class?: ClassValue
// The result value / content. With an htmx swap, this is the initial
// (often placeholder) content that gets replaced in place.
children?: Child
// Accessible name. <output> already announces via its implicit
// role="status"; a name lets AT preface the value (e.g. "Total: 42").
ariaLabel?: string
ariaLabelledby?: string
ariaDescribedby?: string
// Override the implicit aria-atomic="true" if you only want the changed
// bits announced (rare — leave the implicit value in most cases).
ariaAtomic?: boolean
// htmx — point at this <output> as the persistent target and swap its
// innerHTML so the live region stays put and announcements fire.
"hx-get"?: string
"hx-post"?: string
"hx-put"?: string
"hx-patch"?: string
"hx-delete"?: string
"hx-target"?: string
"hx-swap"?: string
"hx-trigger"?: string
"hx-include"?: string
"hx-vals"?: string
"hx-indicator"?: string
}
export function Output(props: OutputProps) {
const {
htmlFor,
form,
name,
id,
tone,
class: className,
children,
ariaLabel,
ariaLabelledby,
ariaDescribedby,
ariaAtomic,
...rest
} = props
return (
<output
id={id}
for={htmlFor}
form={form}
name={name}
data-slot="output"
data-tone={tone ?? "default"}
aria-label={ariaLabel}
aria-labelledby={ariaLabelledby}
aria-describedby={ariaDescribedby}
aria-atomic={ariaAtomic === undefined ? undefined : ariaAtomic}
class={outputClasses({ tone, class: className })}
{...rest}
>
{children}
</output>
)
}
1. Save the file
Copy output.html into templates/components/.
2. Use it
{% from "components/output.html" import output %}
{% call output(id="result", for="qty price", tone="primary") %}$0.00{% endcall %}
<form hx-post="/cart/total" hx-trigger="change, input delay:300ms"
hx-target="#result" hx-swap="innerHTML">
<input name="qty" value="1" />
{% call output(id="result", for="qty", tone="primary") %}$0.00{% endcall %}
</form>View source
{# Output macro — shadcn-htmx, htmx v4 + Tailwind v4.
Mirrors registry/ui/output.tsx. Renders the native <output> element
(implicit role="status" — an aria-live="polite", aria-atomic="true" live
region), so an htmx innerHTML swap of its content is announced with no JS.
Source: repos/mdn/.../elements/output/index.md (for / form / name; implicit
role="status"). Target THIS <output> with hx-swap="innerHTML" so the live
region persists across requests.
Usage:
{% from "components/output.html" import output %}
<form hx-post="/cart/total" hx-trigger="change, input delay:300ms"
hx-target="#total" hx-swap="innerHTML">
<input name="qty" value="1" />
{% call output(id="total", for="qty price", tone="primary") %}$0.00{% endcall %}
</form>
#}
{% macro output(
for=none,
form=none,
name=none,
id=none,
tone="default",
aria_label=none,
aria_labelledby=none,
aria_describedby=none,
aria_atomic=none,
extra_class="",
**attrs
) %}
{%- set base -%}
inline-flex min-h-9 w-fit items-center gap-2 rounded-md border px-3 py-1.5 text-sm font-medium tabular-nums transition-colors [&.htmx-request]:opacity-60
{%- endset -%}
{%- set tones = {
"default": "border-border bg-card text-card-foreground",
"muted": "border-transparent bg-muted text-muted-foreground",
"primary": "border-transparent bg-primary text-primary-foreground",
"destructive": "border-destructive/30 bg-destructive/5 text-destructive dark:bg-destructive/10"
} -%}
<output class="{{ base }} {{ tones[tone] }} {{ extra_class }}"
{%- if id %} id="{{ id }}"{% endif %}
{%- if for %} for="{{ for }}"{% endif %}
{%- if form %} form="{{ form }}"{% endif %}
{%- if name %} name="{{ name }}"{% endif %}
data-slot="output"
data-tone="{{ tone }}"
{%- if aria_label %} aria-label="{{ aria_label }}"{% endif %}
{%- if aria_labelledby %} aria-labelledby="{{ aria_labelledby }}"{% endif %}
{%- if aria_describedby %} aria-describedby="{{ aria_describedby }}"{% endif %}
{%- if aria_atomic is not none %} aria-atomic="{{ aria_atomic|lower }}"{% endif %}
{%- for k, v in attrs.items() %} {{ k|replace('_', '-') }}="{{ v }}"{% endfor -%}
>{{ caller() }}</output>
{% endmacro %}
1. Save the file
Add output.tmpl alongside your templates.
2. Use it
{{template "output" (dict "ID" "result" "For" "qty price" "Tone" "primary" "Body" "$0.00")}}
<form hx-post="/cart/total" hx-trigger="change, input delay:300ms"
hx-target="#result" hx-swap="innerHTML">
<input name="qty" value="1" />
{{template "output" (dict "ID" "result" "For" "qty" "Tone" "primary" "Body" "$0.00")}}
</form>View source
{{/*
Output template — shadcn-htmx, htmx v4 + Tailwind v4.
Mirrors registry/ui/output.tsx. Renders the native <output> element
(implicit role="status" — an aria-live="polite", aria-atomic="true" live
region), so an htmx innerHTML swap of its content is announced with no JS.
Source: repos/mdn/.../elements/output/index.md (for / form / name; implicit
role="status"). Target THIS <output> with hx-swap="innerHTML" so the live
region persists across requests.
Usage:
{{template "output" (dict
"ID" "total" "For" "qty price" "Tone" "primary"
"Attrs" (dict "hx-post" "/cart/total" "hx-trigger" "change, input delay:300ms"
"hx-target" "#total" "hx-swap" "innerHTML")
"Body" "$0.00")}}
Tone is one of default | muted | primary | destructive.
*/}}
{{define "output"}}
{{- $base := "inline-flex min-h-9 w-fit items-center gap-2 rounded-md border px-3 py-1.5 text-sm font-medium tabular-nums transition-colors [&.htmx-request]:opacity-60" -}}
{{- $tone := or .Tone "default" -}}
{{- $tones := dict
"default" "border-border bg-card text-card-foreground"
"muted" "border-transparent bg-muted text-muted-foreground"
"primary" "border-transparent bg-primary text-primary-foreground"
"destructive" "border-destructive/30 bg-destructive/5 text-destructive dark:bg-destructive/10" -}}
<output class="{{$base}} {{index $tones $tone}}{{if .Class}} {{.Class}}{{end}}"
{{- if .ID}} id="{{.ID}}"{{end}}
{{- if .For}} for="{{.For}}"{{end}}
{{- if .Form}} form="{{.Form}}"{{end}}
{{- if .Name}} name="{{.Name}}"{{end}}
data-slot="output"
data-tone="{{$tone}}"
{{- if .AriaLabel}} aria-label="{{.AriaLabel}}"{{end}}
{{- if .AriaLabelledby}} aria-labelledby="{{.AriaLabelledby}}"{{end}}
{{- if .AriaDescribedby}} aria-describedby="{{.AriaDescribedby}}"{{end}}
{{- if .AriaAtomic}} aria-atomic="{{.AriaAtomic}}"{{end}}
{{- range $k, $v := .Attrs}} {{$k}}="{{$v}}"{{end -}}
>{{htmlSafe .Body}}</output>
{{end}}
1. Save the file
Drop output.ex into lib/my_app_web/components/.
2. Use it
<.output id="result" for="qty price" tone="primary">$0.00</.output>
<form hx-post="/cart/total" hx-trigger="change, input delay:300ms"
hx-target="#result" hx-swap="innerHTML">
<input name="qty" value="1" />
<.output id="result" for="qty" tone="primary">$0.00</.output>
</form>View source
defmodule ShadcnHtmx.Components.Output do
@moduledoc """
Output — shadcn-htmx, htmx v4 + Tailwind v4 for Phoenix.
Renders the native `<output>` element (implicit `role="status"`) — a live
result region for the outcome of a calculation or a server action, tied to
its inputs via the `for` attribute.
Because `role="status"` is an implicit `aria-live="polite"`,
`aria-atomic="true"` live region, an htmx `innerHTML` swap of the output's
content is announced by assistive tech automatically — no JS needed. Target
THIS `<output>` and swap `innerHTML` so the live region persists across
requests.
Source: repos/mdn/.../elements/output/index.md (for / form / name; implicit
role="status").
## Examples
<form hx-post="/cart/total" hx-trigger="change, input delay:300ms"
hx-target="#total" hx-swap="innerHTML">
<input id="qty" name="qty" value="1" />
<.output id="total" for="qty price" tone="primary">$0.00</.output>
</form>
<.output for="a b" name="result">60</.output>
"""
use Phoenix.Component
@base "inline-flex min-h-9 w-fit items-center gap-2 rounded-md border px-3 py-1.5 text-sm font-medium tabular-nums transition-colors [&.htmx-request]:opacity-60"
@tones %{
"default" => "border-border bg-card text-card-foreground",
"muted" => "border-transparent bg-muted text-muted-foreground",
"primary" => "border-transparent bg-primary text-primary-foreground",
"destructive" => "border-destructive/30 bg-destructive/5 text-destructive dark:bg-destructive/10"
}
attr :for, :string, default: nil
attr :form, :string, default: nil
attr :name, :string, default: nil
attr :tone, :string, default: "default", values: ~w(default muted primary destructive)
attr :class, :string, default: nil
attr :rest, :global,
include:
~w(hx-get hx-post hx-put hx-patch hx-delete hx-target hx-swap hx-trigger
hx-include hx-vals hx-indicator id aria-label aria-labelledby
aria-describedby aria-atomic)
slot :inner_block, required: false
def output(assigns) do
assigns =
assigns
|> assign(:base, @base)
|> assign(:tone_class, Map.fetch!(@tones, assigns.tone))
~H"""
<output
class={[@base, @tone_class, @class]}
for={@for}
form={@form}
name={@name}
data-slot="output"
data-tone={@tone}
{@rest}
>{render_slot(@inner_block)}</output>
"""
end
end
1. Save the file
Paste the markup; relies only on theme tokens.
2. Use it
<output id="result" for="qty price" data-slot="output" data-tone="primary"
class="inline-flex min-h-9 w-fit items-center gap-2 rounded-md border border-transparent bg-primary px-3 py-1.5 text-sm font-medium tabular-nums text-primary-foreground transition-colors [&.htmx-request]:opacity-60">$0.00</output>View source
<!--
shadcn-htmx — raw HTML output snippets.
Mirrors registry/ui/output.tsx. The native <output> element carries the
implicit role="status" — an aria-live="polite", aria-atomic="true" live
region. Do NOT add role/aria-live: the browser supplies them. Start with
initial content, then let htmx swap the output's innerHTML in place and the
update is announced automatically. No JS.
Target THIS <output> with hx-swap="innerHTML" so the live region element
persists across requests (an outerHTML swap would replace the region and
break the announcement contract).
Source: repos/mdn/.../elements/output/index.md (for / form / name; implicit
role="status").
BASE: inline-flex min-h-9 w-fit items-center gap-2 rounded-md border px-3 py-1.5
text-sm font-medium tabular-nums transition-colors [&.htmx-request]:opacity-60
TONES:
default border-border bg-card text-card-foreground
muted border-transparent bg-muted text-muted-foreground
primary border-transparent bg-primary text-primary-foreground
destructive border-destructive/30 bg-destructive/5 text-destructive dark:bg-destructive/10
-->
<!-- Native — output tied to its inputs via for, updated by the browser -->
<form>
<input type="range" id="o-b" name="b" value="50" /> +
<input type="number" id="o-a" name="a" value="10" /> =
<output for="o-a o-b" name="result" data-slot="output" data-tone="default"
class="inline-flex min-h-9 w-fit items-center gap-2 rounded-md border border-border bg-card px-3 py-1.5 text-sm font-medium tabular-nums text-card-foreground transition-colors [&.htmx-request]:opacity-60">60</output>
</form>
<!-- htmx — server-computed result swapped into the same live region -->
<form hx-post="/cart/total" hx-trigger="change, input delay:300ms"
hx-target="#cart-total" hx-swap="innerHTML">
<label for="o-qty" class="text-sm font-medium">Quantity</label>
<input type="number" id="o-qty" name="qty" value="1" min="1"
class="h-9 w-20 rounded-md border bg-transparent px-3 text-sm" />
<output id="cart-total" for="o-qty" data-slot="output" data-tone="primary"
class="inline-flex min-h-9 w-fit items-center gap-2 rounded-md border border-transparent bg-primary px-3 py-1.5 text-sm font-medium tabular-nums text-primary-foreground transition-colors [&.htmx-request]:opacity-60">$0.00</output>
</form>
Examples
Basic — tied to its inputs
The for attribute is a space-separated list of the ids of the inputs that contributed to the result. The output's content IS the result.
Native <output> carries role="status" implicitly, so it is already an aria-live="polite" region — no extra ARIA needed. Set htmlFor (the native for attribute) to the ids of the controls it depends on.
<label for="o-a">Subtotal</label>
<input id="o-a" name="a" value="42.00" />
<Output id="o-total" htmlFor="o-a" tone="primary">$45.36</Output><label for="o-a">Subtotal</label>
<input id="o-a" name="a" value="42.00" />
{% call output(id="o-total", for="o-a", tone="primary") %}$45.36{% endcall %}<label for="o-a">Subtotal</label>
<input id="o-a" name="a" value="42.00" />
{{template "output" (dict "ID" "o-total" "For" "o-a" "Tone" "primary" "Body" "$45.36")}}<label for="o-a">Subtotal</label>
<input id="o-a" name="a" value="42.00" />
<.output id="o-total" for="o-a" tone="primary">$45.36</.output><div class="flex flex-wrap items-center gap-2">
<label for="o-a" class="text-sm font-medium">Subtotal</label>
<input id="o-a" name="a" value="42.00" readonly="" class="h-9 w-24 rounded-md border bg-transparent px-3 text-sm tabular-nums"/>
<span class="text-muted-foreground">+ tax =</span>
<output id="o-total" for="o-a" data-slot="output" data-tone="primary" class="inline-flex min-h-9 w-fit items-center gap-2 rounded-md border px-3 py-1.5 text-sm font-medium tabular-nums transition-colors [&.htmx-request]:opacity-60 border-transparent bg-primary text-primary-foreground">$45.36</output>
</div>Further reading
Tones
Four theme-token tones for the result chip: default (card), muted, primary (emphasis), and destructive (an error result).
Tone is purely visual — every tone keeps the same role="status" semantics. Use destructive for a failed calculation, not for a critical interruption — for that, reach for an Alert with role="alert".
<Output>128</Output>
<Output tone="muted">128</Output>
<Output tone="primary">$1,280.00</Output>
<Output tone="destructive">Cannot divide by zero</Output>{% call output() %}128{% endcall %}
{% call output(tone="muted") %}128{% endcall %}
{% call output(tone="primary") %}$1,280.00{% endcall %}
{% call output(tone="destructive") %}Cannot divide by zero{% endcall %}{{template "output" (dict "Body" "128")}}
{{template "output" (dict "Tone" "muted" "Body" "128")}}
{{template "output" (dict "Tone" "primary" "Body" "$1,280.00")}}
{{template "output" (dict "Tone" "destructive" "Body" "Cannot divide by zero")}}<.output>128</.output>
<.output tone="muted">128</.output>
<.output tone="primary">$1,280.00</.output>
<.output tone="destructive">Cannot divide by zero</.output><div class="flex flex-wrap items-center gap-3">
<output data-slot="output" data-tone="default" aria-label="Default result" class="inline-flex min-h-9 w-fit items-center gap-2 rounded-md border px-3 py-1.5 text-sm font-medium tabular-nums transition-colors [&.htmx-request]:opacity-60 border-border bg-card text-card-foreground">128</output>
<output data-slot="output" data-tone="muted" aria-label="Muted result" class="inline-flex min-h-9 w-fit items-center gap-2 rounded-md border px-3 py-1.5 text-sm font-medium tabular-nums transition-colors [&.htmx-request]:opacity-60 border-transparent bg-muted text-muted-foreground">128</output>
<output data-slot="output" data-tone="primary" aria-label="Primary result" class="inline-flex min-h-9 w-fit items-center gap-2 rounded-md border px-3 py-1.5 text-sm font-medium tabular-nums transition-colors [&.htmx-request]:opacity-60 border-transparent bg-primary text-primary-foreground">$1,280.00</output>
<output data-slot="output" data-tone="destructive" aria-label="Error result" class="inline-flex min-h-9 w-fit items-center gap-2 rounded-md border px-3 py-1.5 text-sm font-medium tabular-nums transition-colors [&.htmx-request]:opacity-60 border-destructive/30 bg-destructive/5 text-destructive dark:bg-destructive/10">Cannot divide by zero</output>
</div>Further reading
htmx — server-computed result
The form posts on every input change; the server returns the new total, which htmx swaps into the output's innerHTML. Because the <output> persists as the live region, the new value is announced automatically.
The form triggers on change, input delay:300ms (both bubble from the child inputs up to the form), hx-targets the <output>, and uses hx-swap="innerHTML" so the live-region element stays in place. Per the MDN live regions guide, the region must exist before its content changes — swapping the inner content (not the whole element) is exactly what fires the announcement.
<form hx-post="/cart/total"
hx-trigger="change, input delay:300ms"
hx-target="#o-cart" hx-swap="innerHTML">
<input id="o-qty" name="qty" type="number" value="2" />
<input id="o-price" name="price" type="number" value="19.99" />
<Output id="o-cart" htmlFor="o-qty o-price" tone="primary">$39.98</Output>
</form>
// change/input bubble from the inputs to the form, so the form
// posts qty+price. Server returns just the new value text —
// swapped into the live region: $59.97<form hx-post="/cart/total"
hx-trigger="change, input delay:300ms"
hx-target="#o-cart" hx-swap="innerHTML">
<input id="o-qty" name="qty" type="number" value="2" />
<input id="o-price" name="price" type="number" value="19.99" />
{% call output(id="o-cart", for="o-qty o-price", tone="primary") %}$39.98{% endcall %}
</form><form hx-post="/cart/total"
hx-trigger="change, input delay:300ms"
hx-target="#o-cart" hx-swap="innerHTML">
<input id="o-qty" name="qty" type="number" value="2" />
<input id="o-price" name="price" type="number" value="19.99" />
{{template "output" (dict "ID" "o-cart" "For" "o-qty o-price" "Tone" "primary" "Body" "$39.98")}}
</form><form hx-post="/cart/total"
hx-trigger="change, input delay:300ms"
hx-target="#o-cart" hx-swap="innerHTML">
<input id="o-qty" name="qty" type="number" value="2" />
<input id="o-price" name="price" type="number" value="19.99" />
<.output id="o-cart" for="o-qty o-price" tone="primary">$39.98</.output>
</form><form class="flex flex-wrap items-end gap-3" hx-post="/output/total" hx-trigger="change, input delay:300ms" hx-target="#o-cart" hx-swap="innerHTML">
<div class="grid gap-1.5">
<label for="o-qty" class="text-sm font-medium">Quantity</label>
<input id="o-qty" name="qty" type="number" value="2" min="0" class="h-9 w-24 rounded-md border bg-transparent px-3 text-sm tabular-nums"/>
</div>
<div class="grid gap-1.5">
<label for="o-price" class="text-sm font-medium">Unit price</label>
<input id="o-price" name="price" type="number" value="19.99" min="0" step="0.01" class="h-9 w-28 rounded-md border bg-transparent px-3 text-sm tabular-nums"/>
</div>
<div class="grid gap-1.5">
<span class="text-sm font-medium">Total</span>
<output id="o-cart" for="o-qty o-price" data-slot="output" data-tone="primary" class="inline-flex min-h-9 w-fit items-center gap-2 rounded-md border px-3 py-1.5 text-sm font-medium tabular-nums transition-colors [&.htmx-request]:opacity-60 border-transparent bg-primary text-primary-foreground">$39.98</output>
</div>
</form>API Reference
<Output>
| Prop | Type | Default | Description |
|---|---|---|---|
htmlFor | string | — | Space-separated list of the ids of the inputs that contributed to the result. Sets the native for attribute.MDN<output for> |
form | string | — | Id of a <form> elsewhere in the document to associate with; overrides the nearest ancestor <form>. The output's value is not submitted.MDN<output form> |
name | string | — | The element's name in the form.elements API. |
tone | "default"|"muted"|"primary"|"destructive" | "default" | Visual tone of the result chip. Purely cosmetic — the role="status" semantics are identical across tones. |
children | Child | — | The result value / content. With an htmx innerHTML swap, this is the initial content replaced in place. |
ariaAtomic | boolean | — | Override the implicit aria-atomic="true". Leave unset to announce the whole result on every change (the usual choice).MDNstatus role (aria-atomic) |
ariaLabel | string | — | Accessible name when no visible <label>.MDNaria-label |
ariaLabelledby | string | — | Id of a visible element providing the accessible name.MDNaria-labelledby |
ariaDescribedby | string | — | Id of an element describing this control (announced after the name).MDNaria-describedby |
hx-* | any | — | Any htmx attribute. Forwarded onto the underlying element.htmxAttribute reference |
class | string | — | Extra Tailwind classes appended to the root element. |