<output>

<output> marks the result of a calculation or user action: a total price, a slider's current value, a "Saved" confirmation. Its own attributes are for, the ids of the controls that feed the result; form, to join a form elsewhere in the page; and name, for form.elements. It holds plain text and is not submitted.

What makes it better than a <span> is its implicit ARIA role status, a polite live region: when its text changes, screen readers announce the new value without moving focus away from the slider being dragged.

A tip calculator with output elementsHTMLLive
<style>
  body { font: 15px/1.6 system-ui, sans-serif; margin: 12px; }
  output { font-weight: 700; color: #1565c0; }
  input[type=number] { width: 7em; font: inherit; }
</style>
<form id="tip">
  <label>Bill <input type="number" id="bill" name="bill" value="84.50" step="0.01"></label><br>
  <label>Tip <input type="range" id="pct" name="pct" min="0" max="30" value="18"></label>
  <output name="pctOut" for="pct">18%</output><br>
  Tip <output name="tipOut" for="bill pct">$15.21</output>,
  total <output name="total" for="bill pct">$99.71</output>
</form>
<script>
  const form = document.getElementById('tip');
  const money = new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' });
  function update() {
    const { bill, pct, pctOut, tipOut, total } = form.elements;
    const tip = bill.valueAsNumber * pct.valueAsNumber / 100 || 0;
    pctOut.value = `${pct.value}%`;
    tipOut.value = money.format(tip);
    total.value = money.format(bill.valueAsNumber + tip || 0);
  }
  form.addEventListener('input', update);   // one listener catches every control
  form.elements.pct.value = 25;             // simulate the user dragging the slider
  update();
</script>
Browser output of Listing 2.29
Browser output of 29

One input listener on the form serves every control, because input events bubble. valueAsNumber avoids the bug where "84.50" + tip concatenates strings, and || 0 hides the NaN of an empty field. The text initially inside each <output> (the 18% values) is what users see before the script loads.

If the server needs the computed value, copy it into an <input type="hidden"> and recalculate it on the server anyway: client-side results can be tampered with. For a gauge or task progress, use <meter> or <progress> (Progress and Meter).