Recharts + Next.js App Router : construire des tableaux de bord interactifs de visualisation de données

Les données racontent une histoire — les graphiques la rendent inoubliable. Recharts est la bibliothèque de graphiques React-native la plus populaire, construite sur des composants composables et alimentée par D3 en arrière-plan. Dans ce tutoriel, vous construirez un tableau de bord complet d'analyse des ventes avec Next.js 15 App Router, couvrant chaque type de graphique et chaque pattern nécessaire en production.
Ce que vous allez apprendre
À la fin de ce tutoriel, vous saurez :
- Configurer Recharts dans un projet Next.js 15 App Router avec TypeScript
- Construire des graphiques en barres, en lignes, en aires et circulaires de zéro
- Créer des infobulles personnalisées et des légendes interactives
- Rendre les graphiques entièrement responsives avec
ResponsiveContainer - Récupérer et afficher des données dynamiques depuis des routes API
- Ajouter des animations fluides et des interactions au survol
- Prendre en charge le mode sombre avec des couleurs de graphiques adaptatives
- Organiser le tout dans une mise en page de tableau de bord prête pour la production
Prérequis
Avant de commencer, assurez-vous de disposer de :
- Node.js 20+ installé (
node --version) - Une expérience en TypeScript (types, interfaces, génériques)
- Une familiarité avec les bases de Next.js App Router (layouts, pages, composants client/serveur)
- Une compréhension basique de Tailwind CSS pour la mise en page
Pourquoi Recharts en 2026 ?
En matière de graphiques en React, plusieurs bibliothèques se disputent la première place. Voici pourquoi Recharts reste le meilleur choix :
| Fonctionnalité | Recharts | Chart.js (react-chartjs-2) | Nivo | Victory |
|---|---|---|---|---|
| Composants React natifs | Oui | Wrapper | Oui | Oui |
| Taille du bundle | ~45 KB | ~60 KB | ~50 KB | ~55 KB |
| Composabilité | Excellente | Limitée | Bonne | Bonne |
| Support TypeScript | Intégré | Partiel | Intégré | Intégré |
| Compatibilité SSR | Oui | Canvas (limité) | Oui | Oui |
| Personnalisation | Au niveau composant | Objet de config | Props | Props |
| Courbe d'apprentissage | Faible | Faible | Modérée | Modérée |
Recharts se distingue parce que chaque élément — axes, grilles, infobulles, légendes — est un composant React que vous pouvez composer, styliser et étendre. Si vous connaissez React, vous savez déjà utiliser Recharts.
Étape 1 : configuration du projet
Créez un nouveau projet Next.js 15 avec TypeScript et Tailwind CSS :
npx create-next-app@latest sales-dashboard --typescript --tailwind --app --src-dir
cd sales-dashboardInstallez Recharts :
npm install rechartsVotre structure de projet devrait ressembler à ceci :
sales-dashboard/
├── src/
│ ├── app/
│ │ ├── layout.tsx
│ │ ├── page.tsx
│ │ └── api/
│ │ └── sales/
│ │ └── route.ts
│ ├── components/
│ │ └── charts/
│ │ ├── BarChartCard.tsx
│ │ ├── LineChartCard.tsx
│ │ ├── AreaChartCard.tsx
│ │ ├── PieChartCard.tsx
│ │ └── CustomTooltip.tsx
│ └── lib/
│ └── data.ts
├── package.json
└── tsconfig.json
Étape 2 : définir la couche de données
Créez src/lib/data.ts avec des données typées pour votre tableau de bord :
export interface MonthlySales {
month: string;
revenue: number;
orders: number;
customers: number;
}
export interface ProductSales {
name: string;
value: number;
color: string;
}
export const monthlySalesData: MonthlySales[] = [
{ month: "Jan", revenue: 4200, orders: 180, customers: 120 },
{ month: "Fév", revenue: 5100, orders: 210, customers: 145 },
{ month: "Mar", revenue: 4800, orders: 195, customers: 130 },
{ month: "Avr", revenue: 6300, orders: 270, customers: 180 },
{ month: "Mai", revenue: 5900, orders: 250, customers: 165 },
{ month: "Juin", revenue: 7200, orders: 310, customers: 210 },
{ month: "Juil", revenue: 6800, orders: 290, customers: 195 },
{ month: "Août", revenue: 7500, orders: 320, customers: 225 },
{ month: "Sep", revenue: 8100, orders: 350, customers: 240 },
{ month: "Oct", revenue: 7800, orders: 335, customers: 230 },
{ month: "Nov", revenue: 9200, orders: 400, customers: 280 },
{ month: "Déc", revenue: 10500, orders: 450, customers: 320 },
];
export const productSalesData: ProductSales[] = [
{ name: "Électronique", value: 35, color: "#6366f1" },
{ name: "Vêtements", value: 25, color: "#8b5cf6" },
{ name: "Maison & Jardin", value: 20, color: "#a78bfa" },
{ name: "Sport", value: 12, color: "#c4b5fd" },
{ name: "Livres", value: 8, color: "#ddd6fe" },
];Cela vous donne deux jeux de données : des ventes mensuelles en série temporelle et une répartition par catégorie de produits. Les deux sont entièrement typés pour la sécurité TypeScript.
Étape 3 : construire un graphique en barres
Créez src/components/charts/BarChartCard.tsx. Le graphique en barres affichera le chiffre d'affaires mensuel :
"use client";
import {
BarChart,
Bar,
XAxis,
YAxis,
CartesianGrid,
Tooltip,
ResponsiveContainer,
} from "recharts";
import { MonthlySales } from "@/lib/data";
interface BarChartCardProps {
data: MonthlySales[];
}
export default function BarChartCard({ data }: BarChartCardProps) {
return (
<div className="rounded-xl border bg-white p-6 shadow-sm dark:bg-gray-900 dark:border-gray-800">
<h3 className="mb-4 text-lg font-semibold text-gray-900 dark:text-white">
Chiffre d'affaires mensuel
</h3>
<ResponsiveContainer width="100%" height={300}>
<BarChart data={data} margin={{ top: 5, right: 20, left: 10, bottom: 5 }}>
<CartesianGrid strokeDasharray="3 3" stroke="#e5e7eb" />
<XAxis
dataKey="month"
tick={{ fontSize: 12, fill: "#6b7280" }}
axisLine={{ stroke: "#d1d5db" }}
/>
<YAxis
tick={{ fontSize: 12, fill: "#6b7280" }}
axisLine={{ stroke: "#d1d5db" }}
tickFormatter={(value) => `${value / 1000}k$`}
/>
<Tooltip
formatter={(value: number) => [`${value.toLocaleString()}$`, "CA"]}
contentStyle={{
backgroundColor: "#1f2937",
border: "none",
borderRadius: "8px",
color: "#f9fafb",
}}
/>
<Bar
dataKey="revenue"
fill="#6366f1"
radius={[4, 4, 0, 0]}
animationDuration={800}
/>
</BarChart>
</ResponsiveContainer>
</div>
);
}Points clés :
ResponsiveContainerenveloppe chaque graphique pour le rendre responsive. Définissez toujourswidth="100%"et une hauteur fixe.CartesianGridavecstrokeDasharraycrée des lignes de grille en pointillés subtils.radiussurBararrondit les coins supérieurs pour un look moderne.tickFormattersurYAxisformate les grands nombres en4k$,8k$, etc.
Étape 4 : construire un graphique en lignes
Créez src/components/charts/LineChartCard.tsx pour visualiser les tendances dans le temps :
"use client";
import {
LineChart,
Line,
XAxis,
YAxis,
CartesianGrid,
Tooltip,
Legend,
ResponsiveContainer,
} from "recharts";
import { MonthlySales } from "@/lib/data";
interface LineChartCardProps {
data: MonthlySales[];
}
export default function LineChartCard({ data }: LineChartCardProps) {
return (
<div className="rounded-xl border bg-white p-6 shadow-sm dark:bg-gray-900 dark:border-gray-800">
<h3 className="mb-4 text-lg font-semibold text-gray-900 dark:text-white">
Commandes vs Clients
</h3>
<ResponsiveContainer width="100%" height={300}>
<LineChart data={data} margin={{ top: 5, right: 20, left: 10, bottom: 5 }}>
<CartesianGrid strokeDasharray="3 3" stroke="#e5e7eb" />
<XAxis
dataKey="month"
tick={{ fontSize: 12, fill: "#6b7280" }}
/>
<YAxis tick={{ fontSize: 12, fill: "#6b7280" }} />
<Tooltip
contentStyle={{
backgroundColor: "#1f2937",
border: "none",
borderRadius: "8px",
color: "#f9fafb",
}}
/>
<Legend
wrapperStyle={{ paddingTop: "12px" }}
iconType="circle"
/>
<Line
type="monotone"
dataKey="orders"
stroke="#6366f1"
strokeWidth={2}
dot={{ fill: "#6366f1", r: 4 }}
activeDot={{ r: 6, stroke: "#6366f1", strokeWidth: 2 }}
animationDuration={1000}
name="Commandes"
/>
<Line
type="monotone"
dataKey="customers"
stroke="#10b981"
strokeWidth={2}
dot={{ fill: "#10b981", r: 4 }}
activeDot={{ r: 6, stroke: "#10b981", strokeWidth: 2 }}
animationDuration={1200}
name="Clients"
/>
</LineChart>
</ResponsiveContainer>
</div>
);
}Remarquez comment vous pouvez superposer plusieurs composants Line sur le même graphique. Chacun reçoit sa propre couleur, et le composant Legend récupère automatiquement les noms des dataKey. La propriété type="monotone" crée des courbes lisses au lieu d'angles aigus.
Étape 5 : construire un graphique en aires avec dégradés
Créez src/components/charts/AreaChartCard.tsx. Les graphiques en aires sont parfaits pour afficher le volume au fil du temps :
"use client";
import {
AreaChart,
Area,
XAxis,
YAxis,
CartesianGrid,
Tooltip,
ResponsiveContainer,
} from "recharts";
import { MonthlySales } from "@/lib/data";
interface AreaChartCardProps {
data: MonthlySales[];
}
export default function AreaChartCard({ data }: AreaChartCardProps) {
return (
<div className="rounded-xl border bg-white p-6 shadow-sm dark:bg-gray-900 dark:border-gray-800">
<h3 className="mb-4 text-lg font-semibold text-gray-900 dark:text-white">
Tendance du chiffre d'affaires
</h3>
<ResponsiveContainer width="100%" height={300}>
<AreaChart data={data} margin={{ top: 5, right: 20, left: 10, bottom: 5 }}>
<defs>
<linearGradient id="revenueGradient" x1="0" y1="0" x2="0" y2="1">
<stop offset="5%" stopColor="#6366f1" stopOpacity={0.3} />
<stop offset="95%" stopColor="#6366f1" stopOpacity={0} />
</linearGradient>
</defs>
<CartesianGrid strokeDasharray="3 3" stroke="#e5e7eb" />
<XAxis
dataKey="month"
tick={{ fontSize: 12, fill: "#6b7280" }}
/>
<YAxis
tick={{ fontSize: 12, fill: "#6b7280" }}
tickFormatter={(value) => `${value / 1000}k$`}
/>
<Tooltip
formatter={(value: number) => [`${value.toLocaleString()}$`, "CA"]}
contentStyle={{
backgroundColor: "#1f2937",
border: "none",
borderRadius: "8px",
color: "#f9fafb",
}}
/>
<Area
type="monotone"
dataKey="revenue"
stroke="#6366f1"
strokeWidth={2}
fill="url(#revenueGradient)"
animationDuration={1000}
/>
</AreaChart>
</ResponsiveContainer>
</div>
);
}Le secret réside dans les dégradés SVG. Le bloc defs définit un linearGradient qui passe de 30% d'opacité en haut à totalement transparent en bas. Le composant Area référence ce dégradé via fill="url(#revenueGradient)". Cela crée un look professionnel et soigné que les remplissages plats ne peuvent pas atteindre.
Étape 6 : construire un graphique circulaire
Créez src/components/charts/PieChartCard.tsx pour les données catégorielles :
"use client";
import { PieChart, Pie, Cell, Tooltip, ResponsiveContainer, Legend } from "recharts";
import { ProductSales } from "@/lib/data";
interface PieChartCardProps {
data: ProductSales[];
}
export default function PieChartCard({ data }: PieChartCardProps) {
return (
<div className="rounded-xl border bg-white p-6 shadow-sm dark:bg-gray-900 dark:border-gray-800">
<h3 className="mb-4 text-lg font-semibold text-gray-900 dark:text-white">
Ventes par catégorie
</h3>
<ResponsiveContainer width="100%" height={300}>
<PieChart>
<Pie
data={data}
cx="50%"
cy="50%"
innerRadius={60}
outerRadius={100}
paddingAngle={3}
dataKey="value"
animationDuration={800}
label={({ name, percent }) =>
`${name} ${(percent * 100).toFixed(0)}%`
}
labelLine={{ stroke: "#6b7280" }}
>
{data.map((entry, index) => (
<Cell key={`cell-${index}`} fill={entry.color} />
))}
</Pie>
<Tooltip
formatter={(value: number) => [`${value}%`, "Part"]}
contentStyle={{
backgroundColor: "#1f2937",
border: "none",
borderRadius: "8px",
color: "#f9fafb",
}}
/>
<Legend iconType="circle" />
</PieChart>
</ResponsiveContainer>
</div>
);
}Définir innerRadius crée un graphique en anneau au lieu d'un camembert plein. Le paddingAngle ajoute des espaces subtils entre les tranches. Chaque composant Cell vous permet d'attribuer des couleurs individuelles à partir de vos données.
Étape 7 : construire une infobulle personnalisée
Les infobulles par défaut fonctionnent bien, mais les infobulles personnalisées vous donnent un contrôle total sur le design. Créez src/components/charts/CustomTooltip.tsx :
"use client";
interface CustomTooltipProps {
active?: boolean;
payload?: Array<{
name: string;
value: number;
color: string;
}>;
label?: string;
}
export default function CustomTooltip({
active,
payload,
label,
}: CustomTooltipProps) {
if (!active || !payload || payload.length === 0) {
return null;
}
return (
<div className="rounded-lg border border-gray-200 bg-white px-4 py-3 shadow-lg dark:border-gray-700 dark:bg-gray-800">
<p className="mb-2 text-sm font-medium text-gray-900 dark:text-white">
{label}
</p>
{payload.map((item, index) => (
<div key={index} className="flex items-center gap-2 text-sm">
<span
className="inline-block h-3 w-3 rounded-full"
style={{ backgroundColor: item.color }}
/>
<span className="text-gray-600 dark:text-gray-400">{item.name} :</span>
<span className="font-semibold text-gray-900 dark:text-white">
{typeof item.value === "number"
? item.value.toLocaleString()
: item.value}
</span>
</div>
))}
</div>
);
}Utilisez-la dans n'importe quel graphique en remplaçant le Tooltip intégré par :
<Tooltip content={<CustomTooltip />} />L'infobulle personnalisée reçoit active, payload et label comme props de Recharts. Vous rendez le JSX que vous voulez — classes Tailwind, icônes, sparklines, tout ce que React peut rendre.
Étape 8 : créer une route API pour les données dynamiques
Dans un vrai tableau de bord, les données proviennent d'une API. Créez src/app/api/sales/route.ts :
import { NextResponse } from "next/server";
import { monthlySalesData, productSalesData } from "@/lib/data";
export async function GET() {
// Simuler un délai API
await new Promise((resolve) => setTimeout(resolve, 300));
return NextResponse.json({
monthly: monthlySalesData,
products: productSalesData,
summary: {
totalRevenue: monthlySalesData.reduce((sum, m) => sum + m.revenue, 0),
totalOrders: monthlySalesData.reduce((sum, m) => sum + m.orders, 0),
totalCustomers: monthlySalesData.reduce((sum, m) => sum + m.customers, 0),
avgOrderValue: Math.round(
monthlySalesData.reduce((sum, m) => sum + m.revenue, 0) /
monthlySalesData.reduce((sum, m) => sum + m.orders, 0)
),
},
});
}Cette route API retourne toutes les données du tableau de bord en une seule requête. En production, vous remplaceriez les données statiques par des requêtes de base de données ou des appels API externes.
Étape 9 : assembler la page du tableau de bord
Maintenant, rassemblez tout dans src/app/page.tsx :
"use client";
import { useEffect, useState } from "react";
import BarChartCard from "@/components/charts/BarChartCard";
import LineChartCard from "@/components/charts/LineChartCard";
import AreaChartCard from "@/components/charts/AreaChartCard";
import PieChartCard from "@/components/charts/PieChartCard";
import { MonthlySales, ProductSales } from "@/lib/data";
interface DashboardData {
monthly: MonthlySales[];
products: ProductSales[];
summary: {
totalRevenue: number;
totalOrders: number;
totalCustomers: number;
avgOrderValue: number;
};
}
export default function DashboardPage() {
const [data, setData] = useState<DashboardData | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch("/api/sales")
.then((res) => res.json())
.then((json) => {
setData(json);
setLoading(false);
});
}, []);
if (loading || !data) {
return (
<div className="flex min-h-screen items-center justify-center">
<div className="h-8 w-8 animate-spin rounded-full border-4 border-indigo-500 border-t-transparent" />
</div>
);
}
const stats = [
{ label: "CA Total", value: `${data.summary.totalRevenue.toLocaleString()}$` },
{ label: "Commandes", value: data.summary.totalOrders.toLocaleString() },
{ label: "Clients", value: data.summary.totalCustomers.toLocaleString() },
{ label: "Panier moyen", value: `${data.summary.avgOrderValue}$` },
];
return (
<main className="min-h-screen bg-gray-50 p-6 dark:bg-gray-950">
<div className="mx-auto max-w-7xl">
<h1 className="mb-8 text-3xl font-bold text-gray-900 dark:text-white">
Tableau de bord des ventes
</h1>
{/* Cartes de résumé */}
<div className="mb-8 grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4">
{stats.map((stat) => (
<div
key={stat.label}
className="rounded-xl border bg-white p-6 shadow-sm dark:bg-gray-900 dark:border-gray-800"
>
<p className="text-sm text-gray-500 dark:text-gray-400">
{stat.label}
</p>
<p className="mt-1 text-2xl font-bold text-gray-900 dark:text-white">
{stat.value}
</p>
</div>
))}
</div>
{/* Grille de graphiques */}
<div className="grid grid-cols-1 gap-6 lg:grid-cols-2">
<BarChartCard data={data.monthly} />
<LineChartCard data={data.monthly} />
<AreaChartCard data={data.monthly} />
<PieChartCard data={data.products} />
</div>
</div>
</main>
);
}Cette page récupère les données depuis l'API, affiche des statistiques de synthèse dans la rangée supérieure, et rend les quatre types de graphiques dans une grille responsive à 2 colonnes. Sur mobile, les graphiques se superposent verticalement grâce au breakpoint lg:grid-cols-2.
Étape 10 : ajouter le support du mode sombre
Recharts n'a pas de mode sombre intégré, mais vous pouvez le rendre adaptatif au thème en utilisant des variables CSS ou un contexte React. Voici une approche légère avec un hook personnalisé :
// src/lib/useChartTheme.ts
"use client";
import { useEffect, useState } from "react";
export interface ChartTheme {
gridColor: string;
tickColor: string;
tooltipBg: string;
tooltipText: string;
}
const lightTheme: ChartTheme = {
gridColor: "#e5e7eb",
tickColor: "#6b7280",
tooltipBg: "#1f2937",
tooltipText: "#f9fafb",
};
const darkTheme: ChartTheme = {
gridColor: "#374151",
tickColor: "#9ca3af",
tooltipBg: "#f9fafb",
tooltipText: "#1f2937",
};
export function useChartTheme(): ChartTheme {
const [isDark, setIsDark] = useState(false);
useEffect(() => {
const mq = window.matchMedia("(prefers-color-scheme: dark)");
setIsDark(mq.matches);
const handler = (e: MediaQueryListEvent) => setIsDark(e.matches);
mq.addEventListener("change", handler);
return () => mq.removeEventListener("change", handler);
}, []);
return isDark ? darkTheme : lightTheme;
}Puis utilisez le thème dans vos composants de graphiques :
import { useChartTheme } from "@/lib/useChartTheme";
export default function BarChartCard({ data }: BarChartCardProps) {
const theme = useChartTheme();
return (
<ResponsiveContainer width="100%" height={300}>
<BarChart data={data}>
<CartesianGrid strokeDasharray="3 3" stroke={theme.gridColor} />
<XAxis tick={{ fill: theme.tickColor }} />
<YAxis tick={{ fill: theme.tickColor }} />
<Tooltip
contentStyle={{
backgroundColor: theme.tooltipBg,
color: theme.tooltipText,
}}
/>
<Bar dataKey="revenue" fill="#6366f1" />
</BarChart>
</ResponsiveContainer>
);
}Maintenant, vos graphiques s'adaptent automatiquement lorsque l'utilisateur bascule entre le mode clair et le mode sombre.
Étape 11 : optimisation des performances
Lors du rendu de nombreux graphiques sur une seule page, gardez ces conseils en tête :
Chargement différé des graphiques sous la ligne de flottaison
Ne rendez les graphiques que lorsqu'ils entrent dans le viewport :
"use client";
import { useEffect, useRef, useState, ReactNode } from "react";
interface LazyChartProps {
children: ReactNode;
height?: number;
}
export default function LazyChart({ children, height = 400 }: LazyChartProps) {
const ref = useRef<HTMLDivElement>(null);
const [visible, setVisible] = useState(false);
useEffect(() => {
const observer = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting) {
setVisible(true);
observer.disconnect();
}
},
{ rootMargin: "100px" }
);
if (ref.current) observer.observe(ref.current);
return () => observer.disconnect();
}, []);
return (
<div ref={ref} style={{ minHeight: height }}>
{visible ? children : null}
</div>
);
}Enveloppez n'importe quel composant de graphique avec LazyChart pour différer le rendu jusqu'à ce qu'il entre dans le viewport.
Réduire la durée des animations
Pour les tableaux de bord avec plus de 4 graphiques, envisagez de réduire animationDuration à 400ms ou de désactiver complètement les animations avec isAnimationActive={false} pour accélérer le premier affichage.
Mémoïser les données des graphiques
Si vos données sont dérivées de réponses API, enveloppez les transformations dans useMemo pour éviter de recalculer à chaque rendu :
const chartData = useMemo(
() => rawData.map((item) => ({ ...item, revenue: item.revenue / 100 })),
[rawData]
);Dépannage
Les graphiques ne se rendent pas côté serveur
Recharts utilise le DOM du navigateur et ne sera pas rendu pendant le rendu côté serveur. Marquez toujours les composants de graphiques avec "use client" et enveloppez-les dans ResponsiveContainer. Si vous voyez des erreurs d'hydratation, assurez-vous que le composant graphique est uniquement rendu côté client.
ResponsiveContainer a une hauteur de zéro
ResponsiveContainer hérite de ses dimensions de son parent. Si le parent n'a pas de hauteur explicite, le graphique s'effondre. Définissez toujours une prop height sur ResponsiveContainer ou assurez-vous que le conteneur parent a une hauteur définie.
L'infobulle scintille sur mobile
Sur les appareils tactiles, les infobulles peuvent scintiller car les événements tactiles se déclenchent différemment. Définissez allowEscapeViewBox sur le Tooltip pour l'empêcher d'être coupé aux limites du graphique :
<Tooltip allowEscapeViewBox={{ x: true, y: true }} />Prochaines étapes
Maintenant que votre tableau de bord est fonctionnel, envisagez ces améliorations :
- Sélecteur de plage de dates — permettre aux utilisateurs de filtrer les données par périodes personnalisées
- Export en PDF — utilisez
html-to-imageetjsPDFpour exporter le tableau de bord - Mises à jour en temps réel — connectez-vous aux WebSockets ou Server-Sent Events pour des données en direct
- Graphiques en profondeur — cliquez sur une barre pour voir les données détaillées
- Barres empilées et groupées — comparer plusieurs catégories côte à côte
- Composant Brush — ajouter un sélecteur de plage pour zoomer sur des périodes spécifiques
Recharts supporte tout cela nativement avec son modèle de composants composables.
Conclusion
Dans ce tutoriel, vous avez construit un tableau de bord complet d'analyse des ventes avec Recharts et Next.js App Router. Vous avez appris à :
- Créer quatre types de graphiques différents — en barres, en lignes, en aires et circulaires
- Construire des infobulles personnalisées pour une expérience utilisateur soignée
- Rendre les graphiques responsives avec
ResponsiveContainer - Récupérer des données dynamiques depuis des routes API Next.js
- Supporter le mode sombre avec des couleurs de graphiques adaptatives
- Optimiser les performances avec le chargement différé et la mémoïsation
Recharts est un choix puissant parce qu'il traite chaque élément de graphique comme un composant React composable. Vous le stylez, l'étendez et le testez de la même manière que n'importe quel autre composant de votre application. Associez-le à Tailwind CSS pour la mise en page et vous disposez d'une boîte à outils de tableau de bord qui passe du prototype à la production.
Discutez de votre projet avec nous
Nous sommes ici pour vous aider avec vos besoins en développement Web. Planifiez un appel pour discuter de votre projet et comment nous pouvons vous aider.
Trouvons les meilleures solutions pour vos besoins.
Articles connexes

Authentifier votre application Next.js 15 avec Auth.js v5 : Email, OAuth et contrôle des rôles
Apprenez à ajouter une authentification prête pour la production à votre application Next.js 15 avec Auth.js v5. Ce guide complet couvre Google OAuth, les identifiants email/mot de passe, les routes protégées, le middleware et le contrôle d'accès basé sur les rôles.

Construire un Chatbot IA Local avec Ollama et Next.js : Guide Complet
Construisez un chatbot IA privé fonctionnant entièrement sur votre machine locale avec Ollama et Next.js. Ce tutoriel pratique couvre l'installation, le streaming des réponses, la sélection de modèles et le déploiement d'une interface de chat prête pour la production — le tout sans envoyer de données dans le cloud.

Construire un site web axé sur le contenu avec Payload CMS 3 et Next.js
Apprenez à construire un site web complet avec Payload CMS 3, qui fonctionne nativement dans Next.js App Router. Ce tutoriel couvre les collections, le rich text, les uploads, l'authentification et le déploiement en production.