Quantity <mv-quantity>

Selector de cantidad para e-commerce, una variante ligera de <mv-number-field>: mínimo 1, limitado automáticamente a las existencias, una leyenda “En stock” / “Solo quedan 3 en stock” / “Agotado” vinculada al campo, un mensaje y una sacudida al alcanzar el límite de existencias, un estado agotado deshabilitado que se reactiva al reponerse; variantes píldora y sutil para las líneas del carrito.

CategoríaFormularios
TipoWeb Component (<mv-quantity>)
Estadoestable
También instalanumber-field
Keywordsquantity, quantité, stepper, stock, out-of-stock, cart, e-commerce, form-associated

When to use

  • A product page or cart line needs a quantity picker capped at available stock
  • Shoppers should see In stock, Only 3 left or Out of stock next to the quantity
  • A compact pill or muted variant must fit inside cart rows

Avoid when

  • The number is not a purchase quantity, like a price, percentage or measurement → use Number Field instead
  • The whole purchase block with variants, price and add to cart is needed → use Buy Box instead

Instalación

node scripts/add.mjs quantity --out ./src/marvelous

Agente de IA con el servidor MCP de Marvelous UI: install_components({ slugs: ["quantity"], target_dir: "<absolute path>/src/marvelous", framework: "react" }).

Archivos copiados (dependencias incluidas): tokens/tokens.css, core/base.css, core/dom.js, core/element.js, core/i18n.js, core/motion.js, components/number-field/number-field.js, components/number-field/number-field.css, components/quantity/quantity.js, components/quantity/quantity.css.

Uso

Marcado de referencia: parte de él y personalízalo con atributos, data-* y variables CSS:

<div id="quantity-demo" style="display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,14rem),1fr));gap:1.25rem;width:min(100%,50rem);margin-inline:auto;font-size:.875rem">
  <style>
    #quantity-demo .panel { display:grid; gap:.875rem; align-content:start; padding:1.25rem; border:1px solid var(--mv-border); border-radius:var(--mv-radius-xl); background:var(--mv-surface) }
    #quantity-demo .cap { margin:0; font-size:.75rem; font-weight:500; color:var(--mv-fg-muted) }
  </style>

  <form class="panel" id="quantity-demo-form" onsubmit="event.preventDefault()">
    <p class="cap">In stock</p>
    <mv-quantity label="Quantity" name="quantity" value="1" stock="24"></mv-quantity>
  </form>

  <div class="panel">
    <p class="cap">Low stock · capped</p>
    <mv-quantity label="Quantity" name="quantity-2" value="2" stock="3" data-variant="pill"></mv-quantity>
  </div>

  <div class="panel">
    <p class="cap">Out of stock</p>
    <mv-quantity label="Quantity" name="quantity-3" value="1" stock="0"></mv-quantity>
    <button class="mv-button" data-variant="outline" data-size="sm" id="quantity-demo-restock" style="justify-self:start">Restock (+12)</button>
  </div>

  <div class="panel">
    <p class="cap">Cart line (compact)</p>
    <div style="display:flex;align-items:center;justify-content:space-between;gap:.75rem">
      <span style="font-weight:500">Stoneware mug</span>
      <mv-quantity value="2" max="10" data-size="sm" data-variant="ghost" caption="none" aria-label="Quantity, Stoneware mug"></mv-quantity>
    </div>
    <div style="display:flex;align-items:center;justify-content:space-between;gap:.75rem">
      <span style="font-weight:500">Fig candle</span>
      <mv-quantity value="1" max="10" data-size="sm" data-variant="ghost" caption="none" aria-label="Quantity, Fig candle"></mv-quantity>
    </div>
  </div>
</div>
<script type="module">
  const root = document.getElementById("quantity-demo");
  root.querySelector("#quantity-demo-restock").addEventListener("click", (e) => {
    const q = root.querySelector('mv-quantity[name="quantity-3"]');
    q.stock = (q.stock ?? 0) + 12;
    e.currentTarget.disabled = true;
  });
</script>

API

Attributes

NameTipoPredeterminadoDescripción
value / name / labelnumber / stringSame as <mv-number-field> (submits an integer value).
minnumber1Minimum quantity.
maxnumberCommercial cap (e.g. 10 per order); combined with stock, the smaller one wins.
stocknumberAvailable stock: caps the value and drives the caption; 0 = out of stock (disabled).
low-stocknumber5Threshold for the “Only n left in stock” caption.
captionauto | none | textautoAutomatic caption, none, or free text.
data-sizesm | mdHeight (lg by default, sized to match an “Add to cart” button).
data-variantpill | ghostRounded pill, or muted background without a border.
disabled / readonly / requiredbooleanForm states.

Properties

NameTipoDescripción
valuenumber | nullQuantity.
stocknumberStock (assignable: restock).
inStockbooleanRead-only.
stringsPartial<Record<string, string | { one, other }>>Overrides for the default text (en-US): quantity (default accessible name), inStock, outOfStock, lastOne (stock of 1), onlyLeft (low stock, {n}, { one, other }), maxAvailable (shown at the stock limit, {n}, { one, other }), plus the number-field keys decrease, increase and valueMissing. App-wide translations: setStrings() from core/i18n.js, under the key "quantity". Can be set before the element is defined.

Methods

NameDescripción
stepUp(n) / stepDown(n) / focus()Inherited from <mv-number-field>.

Events

NameDescripción
mv-changedetail: { value, formatted } (inherited).

CSS classes

NameDescripción
mv-quantity-captionStock caption; data-tone = success | warning | danger.
data-stockOn the host: none | in | low | out.

CSS variables

NamePredeterminadoDescripción
--mv-quantity-width8.25remWidth.

Accessibility

Inherits the APG Spinbutton pattern from <mv-number-field> (arrows, Page↑/↓, Home/End, “Decrease” / “Increase” buttons outside the tab order). Default name “Quantity”. The stock caption is linked via aria-describedby; the “Maximum quantity” message is announced (aria-live polite) when trying to exceed the stock. When out of stock, the field is disabled and empty (dash).

Esta página se tradujo con IA. Informar de un problema de traducción