htmlaccessibilitysemantic-markup

What HTML semantics should I use to make the output of a custom calculator accessible?


I'm developing a simple calculator tool. Right now, I'm using an <input> element with the readonly attribute to style the result of the calculation. However, while I think that this produces desirable aesthetics, I'm concerned that this is a poor choice for accessibility, given that this is not an input, it's an output. Is a different HTML Element more appropriate here?

Here is a small reproduction of what I'm trying to do:

<h1>Triangle Area Calculator</h1>
<form>
    <ul>
        <li>
            <label for="base">Triangle base:</label>
            <input type="number" step="any" id="base" name="base" required onchange="checkComplete()">
        </li>
        <li>
            <label for="height">Triangle height:</label>
            <input type="number" step="any" id="height" name="height" required onchange="checkComplete()">
        </li>
        <li>
            <label for="area">Triangle area:</label>
            <input type="number" step="any" class="result" id="area" name="result" readonly>
        </li>
    </ul>
</form>
form ul {
  list-style: none;
}
input.result{
  background-color: whitesmoke;
}
function checkComplete() {
    base_input = document.getElementById("base")
  height_input = document.getElementById("height")
  area_result = document.getElementById("area")
  
  if (base_input.checkValidity() && height_input.checkValidity()){
    area_result.value = base_input.value * height_input.value/2
  }
  else{
    area_result.value = ""
  }
}

Here is the above in a JSFiddle project.


Solution

  • <output>: The Output element, which is

    a container element into which a site or app can inject the results of a calculation or the outcome of a user action.

    You can style the output element with an inline box to make it visually match the input element.

    For accessibility with screen readers that don’t recognize <output> semantics yet, use the aria-live attribute to indicate that this field will update dynamically.

    "use strict";
    
    function checkComplete() {
      let base_input = document.getElementById("base");
      let height_input = document.getElementById("height");
      let area_result = document.getElementById("area");
    
      if (base_input.checkValidity() && height_input.checkValidity()) {
        area_result.value = base_input.value * height_input.value / 2;
      } else {
        area_result.value = "";
      }
    }
    form ul {
      list-style: none;
    }
    
    .result {
        box-sizing: border-box;
        display: inline-block;
        vertical-align: bottom;
        width: 100px;
        height: 1.5rem;
        padding-left: 2px;
        border-radius: 4px;
        border: 1px solid black;
        background-color: whitesmoke;
    }
    <h1>Triangle Area Calculator</h1>
    <form>
      <ul>
        <li>
          <label for="base">Triangle base:</label>
          <input type="number" step="any" id="base" name="base" required onchange="checkComplete()">
        </li>
        <li>
          <label for="height">Triangle height:</label>
          <input type="number" step="any" id="height" name="height" required onchange="checkComplete()">
        </li>
        <li>
          <label for="area">Triangle area:</label>
          <output for="base height" aria-live="polite" class="result" id="area" name="result"></output>
        </li>
      </ul>
    </form>