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 usingaria-errormessage
attribute on the input - The error message must also have
aria-live="assertive"
so they are announced as soon as they change
- Add an
- Finally, add the
flix-quantity--error
class modifier to the wrapper element to enable the error visual state
<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
- add the
- input:
- add the
disabled
attribute to the input, so people are unable to edit them
- add the
- 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.
<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>