Quantity input web component.
npm install @magic-spells/quantity-inputA professional, highly-customizable Web Component for creating intuitive quantity input controls in e-commerce applications. Features increment/decrement buttons with an input field, perfect for shopping carts, product quantities, and any numeric input scenarios.
- Full markup control - You provide the HTML structure and icons
- Optional default styles - Import ready-made CSS or write your own
- Configurable constraints - Set min/max values and default quantities
- Event-driven architecture - Clean separation between UI and logic
- Zero dependencies - Pure Web Components
- Lightweight and performant - Minimal footprint, maximum performance
- Framework agnostic - Pure Web Components work with any framework
- Shopify-ready - Designed for real-world e-commerce applications
- Accessible - Proper ARIA labels and keyboard navigation
``bash`
npm install @magic-spells/quantity-input
`javascript
// Import the component
import '@magic-spells/quantity-input';
// Optional: import default styles
import '@magic-spells/quantity-input/styles';
`
Or include directly in your HTML:
`html
`
You provide your own markup inside the component. The component looks for:
- A button with data-action-decrement for the minus buttondata-action-increment
- A button with for the plus buttoninput
- An element for the quantity value
`html
`
Note: The value attribute on the inner is optional and will be overwritten by the component. Set the value on the element instead.
The quantity input component provides three ways to modify quantities:
- Decrement button: Reduces quantity by 1 (respects min value)
- Increment button: Increases quantity by 1 (respects max value)
- Direct input: Users can type quantities directly (automatically clamped to min/max)
The component emits quantity-input:change events when the value changes, allowing parent components to react to quantity updates.
| Attribute | Description | Default | Required |
| --------- | ------------------------------ | ------- | -------- |
| min | Minimum allowed quantity | 1 | No |max
| | Maximum allowed quantity | none | No |value
| | Initial/current quantity value | 1 | No |
| Event Name | Description | Detail Properties |
| --------------------- | ------------------------------- | ----------------- |
| quantity-input:change | Triggered when quantity changes | { value } |
Your markup inside the component must include:
| Element | Selector | Description |
| ------- | -------- | ----------- |
| Decrement button | [data-action-decrement] | Button to decrease value |[data-action-increment]
| Increment button | | Button to increase value |input
| Input field | | Number input for the quantity |
The component provides complete styling control. Style the content elements however you like:
`css
/ Basic styling (uses rems for scalability) /
quantity-input {
display: inline-flex;
border: 1px solid #ccc;
border-radius: 0.25rem;
overflow: hidden;
width: 7rem;
height: 2.5rem;
}
quantity-input button {
flex-shrink: 0;
width: 2rem;
height: 100%;
background: #f8f9fa;
border: none;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
font-size: 1rem;
}
quantity-input button:hover {
background: #e9ecef;
}
quantity-input input {
flex: 1;
min-width: 0;
height: 100%;
border: none;
text-align: center;
font-size: 1rem;
padding: 0 0.25rem;
}
`
#### Properties
- min: Get/set the minimum allowed valuemax
- : Get/set the maximum allowed valuevalue
- : Get/set the current quantity value
#### Events
The component emits custom events that bubble up for parent components to handle:
quantity-input:change
- Triggered when quantity value changes via buttons or direct input
- event.detail: { value }
#### Programmatic Control
`javascript
const quantityInput = document.querySelector('quantity-input');
// Set values programmatically
quantityInput.value = 5;
quantityInput.min = 1;
quantityInput.max = 20;
// Get current values
console.log(quantityInput.value); // 5
console.log(quantityInput.min); // 1
console.log(quantityInput.max); // 20
// Listen for changes
document.addEventListener('quantity-input:change', (e) => {
console.log('Quantity changed to:', e.detail.value);
});
`
`javascript
// Example cart quantity management
class CartManager {
constructor() {
document.addEventListener('quantity-input:change', this.handleQuantityChange.bind(this));
}
async handleQuantityChange(e) {
const newQuantity = e.detail.value;
const cartItem = e.target.closest('[data-line-item-key]');
const lineItemKey = cartItem.dataset.lineItemKey;
try {
// Update Shopify cart
const response = await fetch('/cart/change.js', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
id: lineItemKey,
quantity: newQuantity,
}),
});
const cart = await response.json();
this.updateCartDisplay(cart);
} catch (error) {
console.error('Failed to update cart:', error);
}
}
updateCartDisplay(cart) {
// Update cart totals, item counts, etc.
}
}
new CartManager();
`
` html`
Awesome T-Shirt
$29.99
$59.98
`jsx
import '@magic-spells/quantity-input';
function ProductQuantity({ min = 1, max = 99, value = 1, onChange }) {
const handleQuantityChange = (e) => {
onChange(e.detail.value);
};
return (
max={max}
value={value}
onQuantity-inputChange={handleQuantityChange}
>
);
}
`
`vue
:max="max"
:value="quantity"
@quantity-input:change="handleQuantityChange"
>
``
- Chrome 54+
- Firefox 63+
- Safari 10.1+
- Edge 79+
All modern browsers with Web Components support.
MIT