shshadcn-htmx

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.json

2. Use it

components/ui/output.tsx
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
components/ui/output.tsx
/** @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

templates/components/output.html
{% 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
templates/components/output.html
{# 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

components/output.tmpl
{{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
components/output.tmpl
{{/*
  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

lib/my_app_web/components/output.ex
<.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
lib/my_app_web/components/output.ex
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

snippets/output.html
<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
snippets/output.html
<!--
  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.

+ tax =$45.36
<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 [&amp;.htmx-request]:opacity-60 border-transparent bg-primary text-primary-foreground">$45.36</output>
</div>

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".

128128$1,280.00Cannot 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>
{% 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 [&amp;.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 [&amp;.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 [&amp;.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 [&amp;.htmx-request]:opacity-60 border-destructive/30 bg-destructive/5 text-destructive dark:bg-destructive/10">Cannot divide by zero</output>
</div>

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.

Total$39.98
<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 [&amp;.htmx-request]:opacity-60 border-transparent bg-primary text-primary-foreground">$39.98</output>
  </div>
</form>

API Reference

<Output>

PropTypeDefaultDescription
htmlForstring
Space-separated list of the ids of the inputs that contributed to the result. Sets the native for attribute.MDN<output for>
formstring
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>
namestring
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.
childrenChild
The result value / content. With an htmx innerHTML swap, this is the initial content replaced in place.
ariaAtomicboolean
Override the implicit aria-atomic="true". Leave unset to announce the whole result on every change (the usual choice).MDNstatus role (aria-atomic)
ariaLabelstring
Accessible name when no visible <label>.MDNaria-label
ariaLabelledbystring
Id of a visible element providing the accessible name.MDNaria-labelledby
ariaDescribedbystring
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
classstring
Extra Tailwind classes appended to the root element.