Quantity

The quantity component enables users to select an amount (number) of something.

Structure and configuration

All of the elements required to build the quantity component must be wrapped by a flix-quantity div. The label element must have a flix-legend class name and be connected to the input's id via for attribute then wrap the buttons and input with the flix-quantity__picker div.

The quantity component is by definition a spinbutton so make sure to add all of the required keyboard interactions described by the W3C. You must add role="spinbutton" to the input, this will announce that the input can be controlled by the plus and minus buttons. The input can be either a text or number type.

Connect the buttons to the input by adding the input's id to the aria-controls attribute on each button. Finally, add aria-live="assertive" to the input will ensure that every time the user interacts with one of the buttons, the current state of the input will be announced.

The plus and minus buttons may be hidden from assistive technologies (using aria-hidden="true") if you allow the input to be edited directly using the keyboard, as they become irrelevant to keyboard users. But if you leave the input as readonly then the plus and minus buttons MUST HAVE either a relevant text using flix-sr-only or a text using aria-label so AT users know what each button does.

If constraints are needed you must set them using the min and max attributes.

<div class="flix-quantity">
  <label class="flix-quantity__label" for="quantity-readonly">Readonly input</label>
  <div class="flix-quantity__picker">
    <button class="flix-btn flix-btn--square flix-quantity__button" type="button" aria-controls="quantity-readonly">
      <span class="flix-sr-only">Remove</span>
    </button>
    <input id="quantity-readonly" type="number" class="flix-quantity__input" readonly="" name="quantity" min="1" max="10" role="spinbutton" aria-live="assertive" value="1"/>
    <button class="flix-btn flix-btn--square flix-quantity__button" type="button" aria-controls="quantity-readonly">
      <span class="flix-sr-only">Add</span>
    </button>
  </div>
</div>
<div class="flix-quantity">
  <label class="flix-quantity__label" for="quantity-simple">Number of vouchers</label>
  <div class="flix-quantity__picker">
    <button class="flix-btn flix-btn--square flix-quantity__button" type="button" aria-controls="quantity-simple">
      <span class="flix-sr-only">Remove</span>
    </button>
    <input id="quantity-simple" type="number" class="flix-quantity__input" name="quantity" min="1" max="10" role="spinbutton" aria-live="assertive" value="1"/>
    <button class="flix-btn flix-btn--square flix-quantity__button" type="button" aria-controls="quantity-simple">
      <span class="flix-sr-only">Add</span>
    </button>
  </div>
</div>

Active state

The flix-quantity--active modifier class added to the wrapper element enables the active state:

<div class="flix-quantity flix-quantity--active">
  <label class="flix-quantity__label" for="quantity-active">Active</label>
  <div class="flix-quantity__picker">
    <button class="flix-btn flix-btn--square flix-quantity__button" type="button" aria-controls="quantity-active">
      <span class="flix-sr-only">Remove</span>
    </button>
    <input id="quantity-active" type="number" class="flix-quantity__input" name="quantity" min="1" max="10" role="spinbutton" aria-live="assertive" value="1"/>
    <button class="flix-btn flix-btn--square flix-quantity__button" type="button" aria-controls="quantity-active">
      <span class="flix-sr-only">Add</span>
    </button>
  </div>
</div>

Error state

To enable the error state and effectively communicate that you must follow these steps:

  • If the field is required, make sure the requried attribute is set to the input element
  • Add aria-invalid="true" to the input field to inform assistive technologies that there is something wrong
  • The error message must be added to the flix-quantity__info element
    • Add an id to the error message element and connect it to the input by using aria-errormessage attribute on the input
    • The error message must also have aria-live="assertive" so they are announced as soon as they change
  • Finally, add the flix-quantity--error class modifier to the wrapper element to enable the error visual state
There is something wrong with this field
<div class="flix-quantity flix-quantity--error">
  <label class="flix-quantity__label" for="quantity-error">Error</label>
  <div class="flix-quantity__picker">
    <button class="flix-btn flix-btn--square flix-quantity__button" type="button" aria-controls="quantity-error">
      <span class="flix-sr-only">Remove</span>
    </button>
    <input id="quantity-error" class="flix-quantity__input" type="number" name="quantity" min="1" max="10" role="spinbutton" aria-live="assertive" aria-invalid="true" aria-errormessage="quantity-error-message" required="" value="1"/>
    <button class="flix-btn flix-btn--square flix-quantity__button" type="button" aria-controls="quantity-error">
      <span class="flix-sr-only">Add</span>
    </button>
  </div>
  <span class="flix-quantity__info" id="quantity-error-message" aria-live="assertive">There is something wrong with this field</span>
</div>

Disabled State

Control elements (the buttons) reuse square button elements (notice flix-btn classes) so in order to disable a certain control you need to disable the buttons as well. Here are the steps to disable the entire component:

  • buttons:
    • add the disabled attribute to the buttons to effectively disable them
    • add the flix-btn--disabled class modifier to activate the disabled appearance
  • input:
    • add the disabled attribute to the input, so people are unable to edit them
  • add the flix-quantity--disabled modifier class to the wrapper element to activate the disabled appearance of the entire component
<div class="flix-quantity flix-quantity--disabled">
  <label class="flix-quantity__label" for="quantity-disabled">Disabled</label>
  <div class="flix-quantity__picker">
    <button class="flix-btn flix-btn--square flix-btn--disabled flix-quantity__button" type="button" disabled="" aria-controls="quantity-disabled">
      <span class="flix-sr-only">Remove</span>
    </button>
    <input id="quantity-disabled" type="number" disabled="" class="flix-quantity__input" name="quantity" min="1" max="10" role="spinbutton" value="1"/>
    <button class="flix-btn flix-btn--square flix-btn--disabled flix-quantity__button" type="button" disabled="" aria-controls="quantity-disabled">
      <span class="flix-sr-only">Add</span>
    </button>
  </div>
</div>

Complex quantity/pax element

Element consists of two main elements:

  • Label: flix-quantity__label;
  • Standalone quantity: flix-quantity__picker;

Labels can have excerpt text, this text should be placed in a small HTML tag.

This field is required 3 max.
<div class="flix-box">
  <div class="flix-form-row">
    <div class="flix-quantity flix-quantity--inline">
      <label for="quantity-inline" class="flix-quantity__label">Normal</label>
      <div class="flix-quantity__picker">
        <button class="flix-btn flix-btn--square flix-quantity__button" type="button" aria-controls="quantity-inline">
          <span class="flix-sr-only">Remove passenger</span>
        </button>
        <input id="quantity-inline" type="number" class="flix-quantity__input" name="passengers-quantity" min="1" max="10" role="spinbutton" aria-live="assertive" value="1"/>
        <button class="flix-btn flix-btn--square flix-quantity__button" type="button" aria-controls="quantity-inline">
          <span class="flix-sr-only">Add passenger</span>
        </button>
      </div>
    </div>
  </div>
  <div class="flix-form-row">
    <div class="flix-quantity flix-quantity--error flix-quantity--inline">
      <label for="quantity-inline-error" class="flix-quantity__label">
        Error <small>with details</small>
      </label>
      <div class="flix-quantity__picker">
        <button class="flix-btn flix-btn--square flix-quantity__button" type="button" aria-controls="quantity-inline-error">
          <span class="flix-sr-only">Remove passenger</span>
        </button>
        <input id="quantity-inline-error" type="number" class="flix-quantity__input" name="passengers-quantity" min="1" max="10" role="spinbutton" aria-live="assertive" aria-invalid="true" aria-errormessage="quantity-inline-error-message" aria-describedby="quantity-inline-error-description" value="4"/>
        <button class="flix-btn flix-btn--square flix-quantity__button" type="button" aria-controls="quantity-inline-error">
          <span class="flix-sr-only">Add passenger</span>
        </button>
      </div>
      <span class="flix-quantity__info" id="quantity-inline-error-message" aria-live="assertive">This field is required</span>
      <span class="flix-quantity__info" id="quantity-inline-error-description">3 max.</span>
    </div>
  </div>
</div>