Quantity <mv-quantity>

Selector de cantidad de e-commerce, una variante ligera de <mv-number-field>: mínimo 1, limitado automáticamente al stock, una leyenda “In stock” / “Only 3 left in stock” / “Out of stock” vinculada al campo, un mensaje y una sacudida al alcanzar el límite de stock, un estado agotado desactivado que se reactiva al reponer; variantes pill y subtle 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/motion.js, components/quantity/quantity.js, components/quantity/quantity.css, components/number-field/number-field.js, components/number-field/number-field.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

NameTipoDefaultDescription
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

NameTipoDescription
valuenumber | nullQuantity.
stocknumberStock (assignable: restock).
inStockbooleanRead-only.

Methods

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

Events

NameDescription
mv-changedetail: { value, formatted } (inherited).

CSS classes

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

CSS variables

NameDefaultDescription
--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