Skip to content

Quantity Spin Button Example

Quantity Spin Button Example

Read This First

The code in this example is not intended for production environments. Before using it for any purpose, read this to understand why.

This is an illustrative example of one way of using ARIA that conforms with the ARIA specification.

About This Example

The following example uses the Spin Button Pattern to implement three quantity inputs.

Similar examples include:

  • Toolbar Example: A toolbar that contains a spin button for setting font size.

Example

Guests
Must be between 1 and 8 1 to 8
Must be between 0 and 8 0 to 8
Must be between 0 and 12 0 to 12

Accessibility Features

  • The element with role spinbutton allows text input, for users who prefer to enter a value directly.
  • The spin button input and its adjacent buttons are visually presented as a single form field containing an editable value, an increment button, and a decrement button.
  • When either the spin button input or its adjacent buttons have received focus, a single visual focus indicator encompasses all three, reinforcing the relationship between them.
  • For users who have not set a preference for reduced motion, the focus indicator appears with subtle animation to draw attention.
  • The increment and decrement buttons:
    • Are generously sized for ease of use.
    • Are adjacent to the spin button input so they can be accessed by users of touch-based and voice-based assistive technologies.
    • Are labeled with the title attribute, providing a human-friendly representation of the plus and minus characters for users of touch-based and voice-based assistive technologies. The title attribute also presents a tooltip on hover, clarifying the meaning of each button’s icon.
    • Use an invisible live region to announce the updated value when pressed. The live region empties its contents after 3 seconds to avoid leaving stale content in the document.
    • Are excluded from the page Tab sequence with tabindex="-1" because they are redundant with the arrow key support provided to keyboard users.
    • Can be activated with voice control by speaking a command such as Click add adult.
  • When forced colors are enabled, system color keywords are used to ensure visibility and sufficient contrast for the spin button’s content and interactive states.
  • Each spin button’s minimum and maximum values are programmatically defined with aria-valuemin and aria-valuemax, enabling assistive technologies to convey that information to users in a predictable manner.
  • The minimum and maximum values are also visually expressed with adjacent help text, but is purposefully not associated using aria-describedby since the same information is already programmatically defined.
  • When a user inputs an invalid value:
    • The spin button is visually styled to indicate an error state.
    • aria-invalid="true" is added to the input to inform assistive technologies of the invalid state.
    • An error message is displayed and associated with the input using aria-errormessage.

Keyboard Support

The spin buttons provide the following keyboard support described in the Spin Button Pattern.

Key Function
Down Arrow Decreases value by 1.
Up Arrow Increases value by 1.
Home Decreases to minimum value.
End Increases to maximum value.
Standard single line text editing keys
  • Keys used for cursor movement and text manipulation, such as Delete and Shift + Right Arrow.
  • An HTML input with type="text" is used for the spin button so the browser will provide platform-specific editing keys.

Role, Property, State, and Tabindex Attributes

Role Attribute Element Usage
spinbutton input[type="text"] Identifies the input[type="text"] element as a spin button.
aria-valuenow="NUMBER" input[type="text"]
  • Indicates the current numeric value of the spin button.
  • Updated by JavaScript as users change the value of the spin button.
aria-valuemin="NUMBER" input[type="text"] Indicates the minimum allowed value for the spin button.
aria-valuemax="NUMBER" input[type="text"] Indicates the maximum allowed value for the spin button.
aria-invalid="true" input[type="text"] Indicates that the current value is invalid.
aria-errormessage="ID_REF" input[type="text"] Identifies the element that provides an error message for the spin button.
title="NAME_STRING" button Defines the accessible name for each increment and decrement button (Remove adult, Add adult, Remove kid, Add kid, Remove animal, and Add animal).
aria-controls="ID_REF" button Identifies the element whose value will be modified when the button is activated.
tabindex="-1" button Removes the increment and decrement buttons from the page Tab sequence while keeping them focusable so they can be accessed with touch-based and voice-based assistive technologies.
aria-disabled="true" button Set when the minimum or maximum value has been reached to inform assistive technologies that the button has been disabled.
aria-hidden="true" span For assistive technology users, hides the visible minus and plus characters in the increment and decrement buttons since they are symbolic of the superior button labels provided by the title attribute.
output
  • An element with an implicit role of status and an implicit aria-live value of polite.
  • Triggers a screen reader announcement of the output element’s updated content at the next graceful opportunity.
  • When either the increment or decrement button is pressed, the current value of the spin button is injected into the output element.
  • Its contents are emptied 2000 milliseconds after injection.

JavaScript and CSS Source Code

HTML Source Code

To copy the following HTML code, please open it in CodePen.


<div class="spinners">
  <fieldset>
    <legend>
      Guests
    </legend>
    <div class="spinner-fields">
      <div class="spinner-field">
        <label for="adults">
          Adults
        </label>
        <div class="spinner">
          <button type="button"
                  title="Remove adult"
                  aria-controls="adults"
                  data-spinbutton-operation="decrement"
                  tabindex="-1">
            <span aria-hidden="true">
              −
            </span>
          </button>
          <input id="adults"
                 aria-errormessage="error-adults"
                 role="spinbutton"
                 type="text"
                 size="4"
                 inputmode="numeric"
                 autocomplete="off"
                 spellcheck="false"
                 aria-valuemin="1"
                 aria-valuemax="8"
                 aria-valuenow="1"
                 value="1">
          <button type="button"
                  title="Add adult"
                  aria-controls="adults"
                  data-spinbutton-operation="increment"
                  tabindex="-1">
            <span aria-hidden="true">
              +
            </span>
          </button>
        </div>
        <small id="error-adults">
          Must be between 1 and 8
        </small>
        <small id="help-adults">
          1 to 8
        </small>
        <output for="adults"
                data-self-destruct="2000"
                class="visually-hidden"></output>
      </div>
      <div class="spinner-field">
        <label for="kids">
          Kids
        </label>
        <div class="spinner">
          <button type="button"
                  title="Remove kid"
                  aria-controls="kids"
                  data-spinbutton-operation="decrement"
                  tabindex="-1">
            <span aria-hidden="true">
              −
            </span>
          </button>
          <input id="kids"
                 aria-errormessage="error-kids"
                 role="spinbutton"
                 type="text"
                 size="4"
                 inputmode="numeric"
                 autocomplete="off"
                 spellcheck="false"
                 aria-valuemin="0"
                 aria-valuemax="8"
                 aria-valuenow="0"
                 value="0">
          <button type="button"
                  title="Add kid"
                  aria-controls="kids"
                  data-spinbutton-operation="increment"
                  tabindex="-1">
            <span aria-hidden="true">
              +
            </span>
          </button>
        </div>
        <small id="error-kids">
          Must be between 0 and 8
        </small>
        <small id="help-kids">
          0 to 8
        </small>
        <output for="kids"
                data-self-destruct="2000"
                class="visually-hidden"></output>
      </div>
      <div class="spinner-field">
        <label for="animals">
          Animals
        </label>
        <div class="spinner">
          <button type="button"
                  title="Remove animal"
                  aria-controls="animals"
                  data-spinbutton-operation="decrement"
                  tabindex="-1">
            <span aria-hidden="true">
              −
            </span>
          </button>
          <input id="animals"
                 aria-errormessage="error-animals"
                 role="spinbutton"
                 type="text"
                 size="4"
                 inputmode="numeric"
                 autocomplete="off"
                 spellcheck="false"
                 aria-valuemin="0"
                 aria-valuemax="12"
                 aria-valuenow="0"
                 value="0">
          <button type="button"
                  title="Add animal"
                  aria-controls="animals"
                  data-spinbutton-operation="increment"
                  tabindex="-1">
            <span aria-hidden="true">
              +
            </span>
          </button>
        </div>
        <small id="error-animals">
          Must be between 0 and 12
        </small>
        <small id="help-animals">
          0 to 12
        </small>
        <output for="animals"
                data-self-destruct="2000"
                class="visually-hidden"></output>
      </div>
    </div>
  </fieldset>
</div>
Back to Top

This is an unpublished draft preview that might include content that is not yet approved. The published website is at w3.org/WAI/.