6.6 KiB
Quantity Control
An accessible, feature-rich Angular quantity selector component with dropdown presets and manual input mode.
Features
- ✅ Dropdown with presets - Quick selection from predefined values
- ✅ Edit mode - Manual input for values beyond presets
- ✅ Smart logic - Automatically shows/hides Edit based on constraints
- ✅ Flexible range - Start from any value (0, 1, or custom)
- ✅ Full accessibility - WCAG 2.1 AA compliant with screen reader support
- ✅ Keyboard navigation - Arrow keys, Home, End, Enter, Escape
- ✅ Form integration - Implements
ControlValueAccessor - ✅ Type-safe - Full TypeScript support with proper validation
Installation
import { QuantityControlComponent } from '@isa/shared/quantity-control';
@Component({
// ...
imports: [QuantityControlComponent],
})
Basic Usage
Standalone
<shared-quantity-control [value]="quantity" />
With Reactive Forms
export class MyComponent {
quantityControl = new FormControl(1);
}
<shared-quantity-control [formControl]="quantityControl" />
With Template-Driven Forms
<shared-quantity-control [(ngModel)]="quantity" />
API
Inputs
| Input | Type | Default | Description |
|---|---|---|---|
value |
model<number> |
1 |
Current quantity value (two-way binding) |
disabled |
model<boolean> |
false |
Whether the control is disabled |
min |
number |
1 |
Minimum selectable value (starting point) |
max |
number | undefined |
undefined |
Maximum selectable value (e.g., stock available) |
presetLimit |
number |
10 |
Number of preset options before requiring Edit |
ariaLabel |
string |
undefined |
Custom ARIA label for accessibility |
How It Works
Preset options generated: min to (min + presetLimit - 1)
Edit option shown when:
maxisundefined(unlimited), ORmax > (min + presetLimit - 1)(stock exceeds presets)
Examples
Standard Use Case (1-10 with unlimited)
<shared-quantity-control
[(value)]="quantity"
[min]="1"
[presetLimit]="10"
/>
Dropdown: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, Edit ✅
Start From Zero
<shared-quantity-control
[(value)]="quantity"
[min]="0"
[presetLimit]="10"
/>
Dropdown: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, Edit ✅
Limited Stock (No Edit)
<shared-quantity-control
[(value)]="quantity"
[min]="1"
[max]="5"
[presetLimit]="10"
/>
Dropdown: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 (No Edit - max is 5)
High Stock (With Edit)
<shared-quantity-control
[(value)]="quantity"
[min]="1"
[max]="50"
[presetLimit]="20"
/>
Dropdown: 1, 2, 3, ... 20, Edit ✅ (allows 21-50)
Custom Range (5-15)
<shared-quantity-control
[(value)]="quantity"
[min]="5"
[presetLimit]="11"
[max]="15"
/>
Dropdown: 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 (No Edit)
With Reactive Forms
export class ShoppingCartComponent {
quantityControl = new FormControl(1, [
Validators.min(1),
Validators.max(99)
]);
}
<shared-quantity-control
[formControl]="quantityControl"
[min]="1"
[max]="99"
[presetLimit]="10"
/>
Disabled State
<shared-quantity-control
[(value)]="quantity"
[disabled]="true"
/>
Custom ARIA Label
<shared-quantity-control
[(value)]="quantity"
[ariaLabel]="'Select number of items to purchase'"
/>
Accessibility
The component implements the ARIA combobox pattern and is fully accessible:
-
✅ Keyboard Navigation:
Space/Enter- Open dropdownArrow Up/Down- Navigate optionsHome/End- Jump to first/last optionEnter/Space- Select optionEscape- Close dropdown or cancel edit
-
✅ ARIA Attributes:
role="combobox"on hostrole="listbox"on dropdownrole="option"on each itemaria-expanded,aria-haspopup,aria-controlsaria-activedescendantfor keyboard focusaria-selectedfor current value
-
✅ Screen Reader Support:
- Value changes announced
- Edit mode transitions announced
- Validation errors announced
-
✅ E2E Testing:
data-what="quantity-control"on buttondata-what="quantity-control-option"on optionsdata-whichattributes with values
Validation
Automatic Validation
The component validates input in Edit mode:
// If min=1, entering 0 shows:
"Invalid quantity. Please enter a number greater than or equal to 1."
// If max=50, entering 100 shows:
"Invalid quantity. Maximum available is 50."
Form Validators
Use standard Angular validators with the form control:
quantityControl = new FormControl(1, [
Validators.required,
Validators.min(0),
Validators.max(999),
]);
Behavior
Dropdown
- Click button or press
Space/Enterto open - Click option to select
- Click outside (backdrop) to close
- Press
Escapeto close
Edit Mode
- Select "Edit" option from dropdown
- Input field opens with current value pre-selected
- Press
Enterto save - Press
Escapeto cancel (reverts to original value) - Click outside (blur) to save
Styling
The component uses scoped CSS with these CSS classes:
.quantity-control-button /* Main button */
.quantity-control-value /* Value display */
.quantity-control-input /* Edit mode input */
.options-list /* Dropdown container */
.quantity-control-option /* Each option */
.quantity-control-option.active /* Keyboard focused */
.quantity-control-option.selected /* Current value */
Host Classes
:host.disabled /* Disabled state */
:host.open /* Dropdown open */
:host.edit-mode /* Edit mode active */
Performance
- ✅ OnPush change detection for optimal performance
- ✅ Signal-based reactivity with computed values
- ✅ Efficient keyboard manager from Angular CDK
- ✅ Automatic cleanup on component destruction
Browser Support
- Chrome/Edge (latest)
- Firefox (latest)
- Safari (latest)
- Mobile browsers (iOS Safari, Chrome Android)
Dependencies
@angular/core^20.1.2@angular/forms^20.1.2@angular/cdk^20.1.2@ng-icons/core(for chevron icons)
Contributing
This component is part of the ISA Frontend monorepo. For changes:
- Update component code
- Update tests (when available)
- Update Storybook stories
- Update this README if API changes
License
Internal use only - ISA Frontend Project