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.
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 / EU: per kg, L, m, m². For nominal quantities ≤ 250 g / 250 ml the law allows 100g / 100ml instead. The UK rules mirror this. The US has no federal unit-price law but several states (NY, MA, CA, MI) require unit pricing in retail with their own unit conventions (oz, lb, fl oz). The component does not validate the unit string — pass whatever your jurisdiction requires.
Delta Indicator
Attach a percentage or absolute change indicator:
Size Variants
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 |
null |
The price amount to display |
currency |
string |
'USD' |
ISO 4217 currency code |
locale |
string |
app()->getLocale() |
Locale for number formatting |
base |
int|float |
null |
Compare-at / RRP / UVP / MSRP price (shown as strike-through) |
unitPrice |
int|float |
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 |
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 |
Slots
| Slot | Description |
|---|---|
suffix |
Text after the price (e.g. "/ month") |
Accessibility
- Root
<span>carries anaria-labelcombining all visible parts (amount, compare-at, delta, unit price) - Strike-through compare-at price uses
<del>element for semantic meaning <bdi>wraps formatted values for correct RTL rendering- Unit price suffix carries
aria-hidden="true"so the same information is not read twice — it is already woven into the wrapper'saria-label
Keyboard Interaction
This component is purely presentational and does not respond to keyboard input.
Pitfalls
- Don't pass an unformatted number to
:value. The component formats with the active locale's decimal/thousand separators — passing19.99is correct; passing"19,99"(already formatted) double-formats.
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) |
--color-wk-border |
Optional separator under base/strike row |