Retour au catalogue

Pricing Calculator

Calculateur de prix interactif avec sliders (utilisateurs, stockage) qui mettent a jour le prix en temps reel avec transitions fluides.

pricingcomplex Both Responsive a11y
minimalcorporatesaasuniversalcentered
Theme

Créer un calculateur de prix à l'usage en React

Un calculateur de prix à l'usage en React stocke chaque valeur de slider dans un tableau d'état, calcule le total avec useMemo (basePrice + somme de valeur * pricePerUnit) et envoie le résultat à un compteur Framer Motion qui anime le chiffre à chaque changement via useMotionValue et l'API impérative animate().

  • Stack : React 18 + Framer Motion 11 + Tailwind v4 + lucide-react, ~163 lignes au total.
  • Animation du prix : useMotionValue + animate() avec un ease spring-like [0.16, 1, 0.3, 1] sur 500ms.
  • Les sliders sont des <input type='range'> natifs stylés avec un linear-gradient CSS qui suit le pourcentage de remplissage dynamiquement.
  • Accessible : les inputs range natifs sont navigables au clavier et compatibles avec les lecteurs d'écran sans configuration.
  • Supporte EUR et USD ; les sliders, la liste de fonctionnalités et le label du CTA sont entièrement configurables via les props.

Pricing Calculator est une section React où les utilisateurs glissent des sliders pour définir leur usage (postes, stockage, appels API, etc.) et voient le prix mensuel se mettre à jour instantanément, piloté par un compteur animé. Il remplace les tableaux de tarifs statiques par une expérience directe et tactile qui montre le coût de chaque plan avant même que l'utilisateur n'atteigne le CTA.

Anatomie

La section est une colonne centrée max-w-4xl. Un header en fondu contient le badge (icône Calculator + label), le h2 et un sous-titre optionnel. En dessous, une carte arrondie se divise en deux colonnes sur md+ : la colonne gauche empile les sliders configurables (label, valeur courante, input range natif, indications min/max) ; la colonne droite, séparée par une bordure verticale, affiche le prix animé et la période de facturation. Un séparateur horizontal en bas de la carte présente la liste des fonctionnalités incluses sous forme de chips inline avec des icônes Check, et un bouton pill pleine largeur ferme la carte.

Comment ça marche

Le coeur du composant est une chaîne de réactivité en deux parties. D'abord, les gestionnaires onChange des sliders mettent à jour un state number[] plat ; useMemo recalcule le total à chaque changement, ce qui maintient la formule hors du cycle de rendu. Ensuite, un sous-composant AnimatedPrice reçoit la valeur calculée en prop et la passe à un useMotionValue Framer Motion. Dès que la prop change, un useEffect déclenche animate(mv, value, { duration: 0.5, ease }) qui fait évoluer la motion value du nombre actuel au nouveau. Un second useEffect s'abonne à display.on('change') et écrit l'entier arrondi directement dans le textContent d'un span, en court-circuitant totalement le réconciliateur React pour une animation de compteur ultra-fluide sans re-rendus.

Comment le coder en React

  1. Modélise les sliders comme objets de config

    Définis une interface SliderConfig (label, min, max, step, defaultValue, pricePerUnit, unit) et accepte une prop sliders. Initialise l'état depuis les valeurs par défaut pour qu'ajouter ou supprimer un slider ne nécessite jamais de toucher à la logique du composant.

    const [values, setValues] = useState<number[]>(
      () => sliders.map((s) => s.defaultValue)
    );
  2. Dérive le total avec useMemo

    Calcule le prix en dehors du JSX avec useMemo pour que la formule ne soit ré-exécutée que quand values ou les configs de sliders changent. Cela garde la fonction de rendu propre et facilite les tests unitaires de la formule de coût.

    const totalPrice = useMemo(() => {
      return basePrice + sliders.reduce(
        (sum, s, i) => sum + (values[i] ?? s.defaultValue) * s.pricePerUnit,
        0
      );
    }, [basePrice, sliders, values]);
  3. Anime le prix avec un compteur motion value

    Crée AnimatedPrice comme sous-composant autonome. Il contient un useMotionValue(0) et un display = useTransform(mv, Math.round). Quand la prop value change, appelle l'API impérative animate(mv, value, { duration: 0.5, ease }) et écris le résultat directement dans un ref de span, sans state ni re-rendu.

    useEffect(() => {
      const controls = animate(mv, value, {
        duration: 0.5,
        ease: [0.16, 1, 0.3, 1],
      });
      return controls.stop;
    }, [value, mv]);
  4. Style le remplissage du range avec un gradient dynamique

    Les inputs range natifs cachent leur remplissage dans la plupart des navigateurs. Passe un style inline calculé avec un linear-gradient qui passe de la couleur d'accent à la couleur de bordure exactement au pourcentage de remplissage du slider. Dérive ce pourcentage de (value - min) / (max - min) * 100 et insère-le dans la propriété background.

    style={{
      background: `linear-gradient(to right,
        var(--color-accent) ${pct}%,
        var(--color-border) ${pct}%)`,
    }}

Quand l'utiliser

À utiliser sur toute landing SaaS où le tarif évolue à l'usage : postes, appels API, stockage, bande passante. Il supprime l'incertitude des tableaux par paliers et aide les utilisateurs à se qualifier eux-mêmes avant de contacter l'équipe commerciale. À éviter pour les produits à tarif fixe simple ou freemium où une carte pricing classique à 2 colonnes est plus rapide à parcourir. Sur mobile, le composant fonctionne bien avec le glisser-déposer tactile sur les sliders, mais teste sur Safari iOS où le style des ranges diffère.

Utilisé par

  • Vercel, Utilise un slider interactif pour que les utilisateurs estiment les coûts de calcul et de bande passante avant de choisir un plan.
  • Twilio, Toute la section tarification est un calculateur à l'usage ; les utilisateurs saisissent des volumes et voient une estimation de coût en direct.
  • Cloudflare, Les pages de tarification R2 et Workers proposent des estimateurs à plage qui mettent à jour les totaux de coût quand vous ajustez les volumes de requêtes.
  • Lemon Squeezy, Un slider de revenu estime dynamiquement les frais de la plateforme, montrant la part exacte avant l'inscription.

FAQ

Pourquoi useMemo pour le calcul du prix plutôt qu'un calcul dans useEffect ?

useMemo dérive le prix de façon synchrone pendant le rendu pour que le sous-composant AnimatedPrice reçoive toujours la bonne valeur dans le même paint. useEffect s'exécute après le rendu, ce qui causerait un décalage d'une frame où l'ancien prix déclenche l'animation avant que la nouvelle valeur n'arrive.

Comment le compteur animé évite-t-il les re-rendus React à chaque frame ?

AnimatedPrice écrit l'entier arrondi directement dans le textContent d'un span via un abonnement display.on('change'), en court-circuitant totalement le state React. Le noeud DOM se met à jour à 60fps sans déclencher le réconciliateur.

Puis-je ajouter un toggle mensuel/annuel en plus des sliders ?

Oui. Ajoute un state billingCycle ('monthly' | 'annual') et inclus-le dans le tableau de dépendances de useMemo. Multiplie totalPrice par 0,8 (par exemple) quand l'annuel est sélectionné ; le compteur AnimatedPrice animera la transition automatiquement.

Est-ce accessible sans label visible pour chaque valeur de slider ?

La valeur courante est affichée dans un span visible à côté du label du slider, ce qui satisfait l'exigence visuelle. Pour les utilisateurs de lecteurs d'écran, ajoute aria-label et aria-valuetext à chaque <input type='range'> avec la valeur formatée (ex. '5 utilisateurs') pour que la valeur soit annoncée au changement.

"use client";

import { useState, useMemo } from "react";
import { motion, useMotionValue, useTransform, animate } from "framer-motion";
import { Calculator, Check } from "lucide-react";
import { useEffect, useRef } from "react";

interface SliderConfig {
  label: string;
  min: number;
  max: number;
  step: number;
  defaultValue: number;
  pricePerUnit: number;
  unit: string;
}

interface PricingCalculatorProps {
  badge?: string;
  title?: string;
  subtitle?: string;
  basePrice?: number;

Code complet réservé à Pro

Code source intégral, export multi-framework et playground.

Passer en Pro, 9,99€/mois

Avis

Calculateur de prix interactif React avec sliders, Tutoriel