Price <mv-price>

Intl.NumberFormat で書式設定する EC 向けの価格(デフォルトは en-US / USD):現在の価格、取り消し線付きの比較価格、自動計算される割引バッジ(パーセントまたは金額)、単価、「From」、価格帯、上付きのセント、4 つのサイズ、そしてホバーとフォーカス時に表示される基準通貨での換算額(レートはアプリが提供し、取得はしません)。.mv-price-* クラスを使って静的 HTML としても利用できます。

カテゴリーデータ表示
タイプWeb Component(<mv-price>)
ステータス安定版
Keywordsprice, prix, sale, soldes, compare-at, discount, unit-price, currency, intl, e-commerce, exchange-rate, currency-conversion, reference-currency

When to use

  • A product price must be formatted for a locale and currency, with a struck compare-at price and discount badge
  • A listing shows a price range, a From prefix or a unit price such as per ounce
  • A subscription or quote shows a price with a note like per month or plus tax
  • A store charges in one currency and visitors want an indicative equivalent in their own, at a rate the app provides

Avoid when

  • Several subscription plans must be compared with features and a billing switch → use Pricing instead
  • The figure is a KPI or stat that should animate between values → use Number Ticker instead

インストール

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

Marvelous UI の MCP サーバーを使う AI エージェント:install_components({ slugs: ["price"], target_dir: "<absolute path>/src/marvelous", framework: "react" })。

コピーされるファイル(依存関係を含む):tokens/tokens.css, core/base.css, core/dom.js, core/element.js, core/motion.js, core/position.js, components/price/price.js, components/price/price.css。

使い方

基本となるマークアップです。ここから属性、data-*、CSS 変数でカスタマイズしてください:

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

  <div class="tile" style="grid-column:1/-1">
    <p class="cap">Product page · sale</p>
    <p class="name" style="font-size:1.125rem">Merino crewneck sweater</p>
    <mv-price id="price-demo-pdp" value="89" compare-at="119" note="+ tax" data-size="xl"></mv-price>
    <div style="display:flex;gap:.5rem;flex-wrap:wrap">
      <button class="mv-button" data-variant="outline" data-size="sm" data-price="89" aria-pressed="true">Sand · $89</button>
      <button class="mv-button" data-variant="outline" data-size="sm" data-price="99">Midnight · $99</button>
      <button class="mv-button" data-variant="outline" data-size="sm" data-price="119">Limited edition · $119</button>
    </div>
  </div>

  <div class="tile">
    <p class="cap">Grid thumbnail</p>
    <p class="name">Glazed stoneware mug</p>
    <mv-price value="24.9" compare-at="32" data-size="sm"></mv-price>
  </div>

  <div class="tile">
    <p class="cap">Price per ounce</p>
    <p class="name">Insulated bottle, 25 oz</p>
    <mv-price value="34.5" unit-price="1.38" unit="oz"></mv-price>
  </div>

  <div class="tile">
    <p class="cap">Price range</p>
    <p class="name">Scented candle · 3 sizes</p>
    <mv-price from value="18" max="46"></mv-price>
  </div>

  <div class="tile">
    <p class="cap">Superscript cents</p>
    <p class="name">Wave wireless headphones</p>
    <mv-price value="189.9" compare-at="229.9" data-variant="superscript" data-size="lg" discount="amount"></mv-price>
  </div>

  <div class="tile">
    <p class="cap">Other currency · de-DE</p>
    <p class="name">Canvas tote bag</p>
    <mv-price value="42" compare-at="56" currency="EUR" locale="de-DE"></mv-price>
  </div>

  <div class="tile">
    <p class="cap">Reference currency · tooltip</p>
    <p class="name">Leather weekender bag</p>
    <mv-price value="249" compare-at="299" reference-currency="EUR" rate="0.8531" rate-note="Indicative rate, Oct 3" data-size="lg"></mv-price>
  </div>

  <div class="tile">
    <p class="cap">Reference currency · inline</p>
    <p class="name">Linen throw blanket</p>
    <mv-price value="64" currency="GBP" locale="en-GB" reference-currency="USD" rate="1.3412" reference-display="inline"></mv-price>
  </div>

  <div class="tile">
    <p class="cap">Range · equivalent in yen</p>
    <p class="name">Ceramic pour-over set · 3 sizes</p>
    <mv-price from value="38" max="72" reference-currency="JPY" rate="147.32"></mv-price>
  </div>

  <div class="tile">
    <p class="cap">Static HTML (no JS)</p>
    <p class="name">Opaline lamp</p>
    <span class="mv-price" data-sale>
      <span class="mv-price-current"><span class="mv-sr-only">Sale price: </span>$129</span>
      <s class="mv-price-compare"><span class="mv-sr-only">Original price: </span>$159</s>
      <span class="mv-price-discount">−19%</span>
    </span>
  </div>
</div>
<script type="module">
  const root = document.getElementById("price-demo");
  const pdp = root.querySelector("#price-demo-pdp");
  root.addEventListener("click", (e) => {
    const btn = e.target.closest("[data-price]");
    if (!btn) return;
    root.querySelectorAll("[data-price]").forEach((b) => b.setAttribute("aria-pressed", String(b === btn)));
    pdp.value = Number(btn.dataset.price);
  });
</script>

API

Attributes

NameタイプDefaultDescription
valuenumberCurrent price (currency units, e.g. 24.9).
compare-atnumberOriginal price; greater than value = on sale (sale color, strikethrough price, badge).
maxnumberUpper bound of a range (“$18 - $46”).
currencystringUSDISO 4217 code.
localestringen-USFormatting locale. auto follows the nearest [lang] (read at render), falling back to en-US.
decimalsauto | 0 | 2autoauto: “$89” but “$24.90”.
discountpercent | amount | nonepercentBadge “−25%”, “−$30” or none.
unit-price / unitnumber / stringUnit price: “$1.38 / oz”.
fromboolean“From” prefix.
notestringNote (“+ tax”, “incl. VAT”, “/ month”).
labelstringPrefix read by screen readers when the price is not on sale.
reference-currencystringISO 4217 code of the equivalent (“≈ €82.40”). Shown only with a valid rate and a currency different from currency.
ratenumberUnits of reference-currency for 1 unit of currency (USD to EUR: 0.9258). Supplied by the application; the component never fetches a rate. Applies to value and max.
rate-notestringExtra line in the tooltip, such as the source or date of the rate (“Indicative rate, Oct 3”).
reference-displaytooltip | inlinetooltiptooltip: the price gets a dotted underline and shows the equivalent and the rate on hover and keyboard focus. inline: muted “≈ €82.40” text after the price, no tab stop (use it inside a link or a button).
data-sizesm | lg | xlSize (md by default).
data-variantsuperscriptSuperscript cents ($189⁹⁰).
data-layoutstacked | inlineStacked, or unit price on the same line.
data-toneneutralKeeps the normal color for a sale price.

Properties

NameタイプDescription
formattedstringFormatted current price (read-only).
equivalentstringFormatted equivalent in the reference currency, a range when max is set; empty without a usable rate (read-only).
stringsPartial<Record<string, string>>Overrides for the default text: from, salePrice, originalPrice, discount, approx (“≈ {amount}”, visible), approxLabel (“(about {amount})”, read by screen readers), rate (“1 {from} = {rate} {to}”). English defaults. Can be set before the element is defined.

Methods

NameDescription
formatMoney(value, { currency, locale, decimals })Module export, reused by the other e-commerce components.
moneyFormatter(options) / formatPercent(value, locale)Exports: cached Intl formatter, signed percentage.
formatEquivalent(value, { rate, currency, locale }) / convertMoney(value, rate) / isCurrency(code)Exports: equivalent rounded to the digits of the target currency (none for JPY), empty string when the rate or code is not usable; raw conversion (NaN if unusable); ISO 4217 check.

CSS classes

NameDescription
mv-priceContainer; data-sale when on sale (set automatically by <mv-price>).
mv-price-current / -compare / -discount / -unit / -from / -note / -fractionParts (generated or hand-written).
mv-price-equivalentInline equivalent (reference-display="inline").
mv-price-tip / -tip-amount / -tip-rate / -tip-noteTooltip bubble (top layer, Popover API) and its lines.

CSS variables

NameDefaultDescription
--mv-price-sale-colorsoftened dangerSale price color.
--mv-price-tip-bg / --mv-price-tip-fginverted grayTooltip colors.

Accessibility

The strikethrough price is an <s> prefixed with hidden “Original price:” text, the current price is prefixed with “Sale price:” when discounted, and the badge with “Discount:”. Screen readers never have to interpret a visual strikethrough. Reference currency: the equivalent is always in the accessibility tree as hidden text inside the price (“(about €82.40)”), so it is read in browse mode without hovering; in tooltip mode the price becomes a tab stop with a dotted underline, the tooltip (role=tooltip, top layer) opens on hover after 200 ms and immediately when the price receives focus (keyboard, or a tap in browsers that focus it), stays open while the pointer moves onto it, closes with Escape, and its rate line is the price's aria-describedby. Its visible amount is aria-hidden to avoid a double reading. Inside a link or a button, use reference-display="inline" to avoid a nested tab stop. Value change (variant): subtle fade, removed with reduced motion.

このページは AI で翻訳されています。翻訳の問題を報告