Skip to main content

Design system components

PricingCalculator

Interactive duration × workload pricing calculator for the pricing page.

Status: stable. Group: marketing. Markdown version: /design-system/components/pricing-calculator.md

When to use

PricingCalculator is the custom-engagement estimator on the pricing page: two single-select SelectableCardGroups (duration: 2 weeks to 12 months; workload: 2-5 days/week, or 25/50/75/100% allocations of a 5-day week when the 'Show as percentages' Switch is on; switching views moves the selection to the nearest option, and short 2-week/1-month engagements offer only 4-5 days or 75-100%) recompute total hours, allocation, the effective hourly rate, and the total investment on every change. Partnership selections add a note under the total: '1 day per week is free' in the days view, '25% off the standard rate' in the percentage view. Only the 6/12-month partnership tiers at a workload of at least 75% of a week (4+ days, or 75%/100%) earn the 90 EUR/h partnership rate; those selections carry Partnership badges and a distinct discounted price-card treatment. A 'Custom duration and pace' Switch replaces both groups with two text fields, months (0.5 or more, no upper limit) and days a week (1 to 5), each accepting any decimal in range and a decimal comma; switching on carries the preset over, switching off lands on the nearest preset. A custom term earns the partnership rate from 6 months at 4+ days a week, past 12 months too, and its note always reads '25% off the standard rate'. An optional Budget field below them fits the months to the budget at the current pace; while it is set, changing the days recomputes the months and changing the months recomputes the days (1 to 5), rounded down so the price stays within the budget, and the total card says how much of the budget the term uses (or how far a clamp pushes it over). A budget that reaches 6+ months at 4+ days is fitted at the partnership rate. Out-of-range values show an error after blur and keep the last valid price. It complements the fixed packages; it does not replace them.

When not to use

  • Do not use for fixed-scope package pricing (packages section owns that)
  • Do not duplicate the pricing model outside pricingMath.ts.
  • Don't use it for fixed-scope package pricing; that's the packages section of PricingPageContent.

Look-alikes

The contract names no look-alike with a deciding condition.

Props

PricingCalculator props
PropTypeDefaultDescriptionRequired
classNamestringnoneOptional wrapper class.No
selectionFromUrlbooleanfalseStart from the ?duration=6m&days=4 selection in the page URL (the same parameters the calculator's own CTA emits), so a link can arrive with a tier already chosen; ?duration=custom&months=3.5&days=2.5 opens the custom term, and &budget=40000 adds the budget it was fitted to. Defaults to false. A missing or unknown duration keeps the defaults; with a valid preset duration, a days value that matches neither view falls back to the heaviest day option for that duration.No

Variants

No variant dimensions and no props with a fixed set of values.

Invalid combinations

The contract records no invalid combinations.

Keyboard

PricingCalculator keyboard behaviour
KeyBehaviour
TabMoves focus to the control and on to the next focusable element. (standard)
Arrow keysNamed in the contract without a description.
SpaceActivates or toggles the focused control. (standard)
EnterActivates the focused control. (standard)

Rows marked (standard) name a key the contract lists without a description; the behaviour shown is the usual one for that key.

Rules

Every item under When not to use is a MUST NOT. MUST and SHOULD follow RFC 2119.

PricingCalculator rules
LevelRuleHow it is checked
MUSTARIA: Section labelled by the calculator title.Not yet verified: no evidence record. WCAG 4.1.2.
MUSTARIA: Native fieldset/legend + radio semantics from SelectableCardGroup.Not yet verified: no evidence record. WCAG 4.1.2.
MUSTARIA: CTA is a real link to /contact.Not yet verified: no evidence record. WCAG 4.1.2.
MUSTARIA: Visually hidden role=status region restates the selection after each change in the view the reader sees (days per week in the days view, allocation percentage in the percentage view) plus the same partnership note as the visible total card; when a duration change clamps the workload it starts with the new workload.Not yet verified: no evidence record. WCAG 4.1.2.
MUSTARIA: The "Show as percentages" Switch swaps the workload radios between days and percentage allocations.Not yet verified: no evidence record. WCAG 4.1.2.
MUSTARIA: Workload radios are added/removed on duration change; selection is clamped programmatically and focus is restored if the focused radio unmounts.Not yet verified: no evidence record. WCAG 4.1.2.
MUSTARIA: The "Custom duration and pace" Switch swaps both radio groups for two labelled text inputs (inputmode decimal) with helper text naming the range; an invalid value sets aria-invalid and an error message after blur, and the status region keeps announcing the last valid term; the optional Budget field is a labelled text input (inputmode numeric) whose changes rewrite the months or days fields, and the status region adds the budget line.Not yet verified: no evidence record. WCAG 4.1.2.
MUSTRequired stories produce no axe violations at the configured severity.Automated by npm run test:stories:matrix:ci. WCAG 2.5.8.
MUSTThe accessibility tree (role, name, state) matches the committed snapshot for every required story.Automated by npm run test:stories:matrix:ci. WCAG 1.3.1, 4.1.2.
MUSTThe component remains legible and operable under a real browser forced-colors: active pass.Automated by npm run test:stories:hc.
MUSTEvery documented keyboard interaction works as specified.Not yet verified: no evidence record. WCAG 2.1.1, 2.1.2.
MUSTA human completed an end-to-end accessibility review of this component.Manual review, last on 2026-11-04.
SHOULDKeep the pricing model in pricingMath.ts as the single source of truth; the component only renders its output.Not stated in the contract.
SHOULD NOTDon't hardcode currency formatting; totals format via Intl.NumberFormat on the active language.Not stated in the contract.

Install and import

  • In-repo only. PricingCalculator is not exported from @digitaltableteur/react, so there is no public import path.