Price
A locale-aware price display component for e-commerce and SaaS interfaces. Supports currency formatting, strike-through compare-at prices (RRP / UVP / MSRP), unit prices (Grundpreis) for EU price-marking compliance, delta indicators, and size variants.
Basic Usage
Compare-At Price (RRP / UVP / MSRP)
Show the previous or recommended retail price as a strike-through alongside the current price. The strike-through value answers the question "what was this before?":
- RRP — Recommended Retail Price (UK)
- UVP — Unverbindliche Preisempfehlung (Germany)
- MSRP — Manufacturer's Suggested Retail Price (US)
The base prop carries this comparison value. It does not mean "base price" in the unit-price sense — see Unit Price (Grundpreis) below for that.
From Price
A product whose variants cost different amounts shows the lowest of them, and without a word that amount reads as the price of the product. from writes "from" before the amount, in the application's language: "from €19.99", and "ab 19,99 €" on a German page. It is visible text, and a screen reader reads it with the amount. Beside a compare-at price the struck amount comes first, so the pair reads "Previous price €24.99, from €19.99".
Unit Price (Grundpreis)
For pre-packaged goods sold by weight, volume, length, or area, EU and UK price-marking law requires the per-unit price to be displayed alongside the selling price. In Germany this is the Grundpreis per PAngV § 4; in the UK it is the unit price per the Price Marking Order 2004; the EU baseline is Directive 98/6/EC.
Pass unitPrice (numeric, same currency as amount) and unitMeasure (the reference unit label) — the component renders them as (€8.99 / L) next to the main price, in the same currency, in the same field of vision.
Reference units are jurisdiction-dependent. Germany: per kg, L, m, m² or m³; loose goods sold by weight or volume may use 100g / 100ml where that is the custom (PAngV § 5). The EU directive names the same five units and lets a member state keep a unit it customarily uses for a product. Great Britain uses the same five units, or the price per item for goods sold by number, under the Price Marking Order 2004 as amended in 2024. The US has no federal unit-price law; several states and the District of Columbia require unit pricing in retail, New York and Massachusetts among them, and NIST's uniform unit-pricing regulation allows metric and US units (oz, lb, fl oz) alike. The component does not validate the unit string — pass whatever your jurisdiction requires.
More Decimals Than the Currency
A price per piece can be smaller than the currency's smallest unit: a screw at 0.045 € each, a price list kept to four decimals. max-precision shows up to that many decimals, never fewer than the currency's own, and drops trailing zeros back to them. The previous price and the unit price beside the amount take the same digits.
A currency without minor units, such as the yen, shows decimals only where the amount has some. Without the prop a price shows its currency's digits.
Every amount is rounded half away from zero, the way a till and an invoice round: 0.125 in euros reads 0,13 € and -0.125 reads -0,13 €.
Delta Indicator
Attach a percentage or absolute change indicator:
The delta is written the way the active locale writes numbers, like the amount beside it: -12,5 % in German and -12.5% in English. An absolute delta is a plain number in the same notation, without a currency.
Size Variants
Fitting a Narrow Column
A long amount in a narrow column, a cart's total or a price in a currency with many digits, can shrink to fit its line with fit instead of breaking or running out. The struck price, the word "from" and the amount shrink together and keep one size; the change, the suffix and the unit price beside them keep theirs. fit alone uses the --text-wk-fit-floor token, three quarters of the price's size, and a length such as fit="0.5rem" sets a floor of its own. Below the floor the price runs past its column rather than break. How the fitting works and what it costs is on the Fit Text page.
Minor Units (Cents)
Pass amounts in minor units (cents) and let the component convert:
With Suffix Slot
Add recurring interval text or other context:
Full Sale Example
Props
| Prop | Type | Default | Description |
|---|---|---|---|
amount |
int|float|string |
null |
The price amount to display: a number, or a numeric string such as "19.99" as a decimal cast stores it. Without one, null or an empty string, nothing is drawn |
currency |
string |
'USD' |
ISO 4217 currency code |
locale |
string |
app()->getLocale() |
Locale for number formatting |
base |
int|float|string |
null |
Compare-at / RRP / UVP / MSRP price (shown as strike-through) |
unitPrice |
int|float|string |
null |
Per-unit price (Grundpreis) — required by EU / UK price-marking law for goods sold by weight / volume / length / area |
unitMeasure |
string |
null |
Reference unit label paired with unitPrice (e.g. L, kg, 100g, 100ml, m²) |
delta |
int|float|string |
null |
Change indicator value |
delta-format |
string |
'percent' |
Delta format: percent or absolute |
size |
string |
'md' |
Size variant: xs, sm, md, lg, xl |
minor-units |
bool |
false |
When true, divides amount / base / unitPrice by 100 |
from |
bool |
false |
The amount is the lowest of several, the cheapest variant's: writes "from" before it, in the application's language — see From Price |
max-precision |
int|null |
null |
The most decimals to show, for a price that has more than its currency, such as a price per piece. Never fewer than the currency's own, and trailing zeros drop back to them — see More Decimals Than the Currency |
fit |
bool|string|null |
null |
Shrinks the price down to a floor so it fits its line; the struck price, "from" and the amount shrink together. true for the --text-wk-fit-floor token, or a length such as 0.5rem — see Fitting a Narrow Column |
scope |
string|null | null |
Scoped personalization name |
Slots
| Slot | Description |
|---|---|
suffix |
Text after the price (e.g. "/ month") |
Accessibility
- Every part is read from the content itself — the root
<span>carries noaria-label. ARIA prohibitsaria-labelon an element with no role, so a name placed there is not required to reach assistive technology at all - Strike-through compare-at price uses
<del>element for semantic meaning, prefixed with a visually-hidden "Previous price" —<del>maps torole="deletion", which screen readers do not announce by default, so without the prefix the two amounts read as unrelated <bdi>wraps formatted values for correct RTL rendering- The word
fromwrites is visible text before the amount, read with it, not a label on the wrapper - Unit price is read out like any other visible text; it is deliberately not
aria-hidden, because it is the figure EU / UK price-marking law requires the reader to get
Keyboard Interaction
This component is purely presentational and does not respond to keyboard input.
Pitfalls
- Pass the raw number, never an already-formatted string. Pass
:amount="19.99", and the component formats it with the active locale's decimal and thousand separators. A string that is no number,"19,99"with a decimal comma,"1.234,56"or a word such as"on request", is refused while you develop, and in production the price is left out rather than shown as a wrong amount, since PHP would read"19,99"as 19 and a word as 0. A refusedbase,unitPriceordeltaleaves out only itself. One spelling cannot be caught:"1.234", a thousand in German writing, is a number to PHP and reads as 1.234. Convert a localized figure to a number before you pass it. - No amount draws no price, and a zero draws 0.00.
nullor an empty string, a price on request for example, renders nothing rather than a 0 nobody gave, and it is not reported, because a catalog has such products. Pass0for something that is free. - Without PHP's
intlextension, an amount carries the currency code instead of a symbol. WireKit does not require the extension. Without it, the amount is written with English separators and the ISO code after it,1,234.56 EUR, and the delta the same way, because the symbols, where they go and each language's separators come from the extension. Installintlto render1.234,56 €in German.
Design Tokens
| Token | Used for |
|---|---|
--font-wk-sans |
Price font family |
--font-wk-heading-weight |
Amount + currency weight |
--text-wk-xs / --text-wk-sm / --text-wk-md / --text-wk-lg / --text-wk-xl |
Font size per size prop |
--color-wk-text |
Amount + currency color |
--color-wk-text-muted |
Strike-through base price + suffix |
--color-wk-success-text |
Negative-direction delta (savings) |
--color-wk-danger-text |
Positive-direction delta (price increase) |
--text-wk-fit-floor |
The floor of a price with fit and no floor of its own, 0.75em |