DEV Community

Cover image for Real-time Updates with ShadCN UI Charts in Nextjs 15
Derick Zihalirwa
Derick Zihalirwa

Posted on • Edited on

Real-time Updates with ShadCN UI Charts in Nextjs 15

Introduction

In today's trading websites, animated charts displaying real-time data are common. In this tutorial, you'll learn how to implement the same functionality in your React project using ShadCN UI's chart components instead of ApexCharts.

check out: Live Demo

Implementing the Real-time Chart

We'll generate real-time data directly within the React component. Below is the complete implementation using ShadCN UI's chart components:

"use client";

import { useEffect, useState, useRef } from "react";
import { Area, AreaChart, CartesianGrid, Line, LineChart, XAxis, YAxis } from "recharts";
import { ChartContainer, ChartTooltip, ChartTooltipContent } from "@/components/ui/chart";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Switch } from "@/components/ui/switch";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";

// Mock initial data
const initialData = Array.from({ length: 20 }, (_, i) => ({
  time: new Date(Date.now() - (19 - i) * 1000).toISOString(),
  price: 100 + Math.random() * 10,
  isNew: false,
}));

export default function RealTimeChart() {
  const [data, setData] = useState(initialData);
  const [darkMode, setDarkMode] = useState(true);
  const [isRunning, setIsRunning] = useState(true);
  const prevDataRef = useRef([...initialData]);

  useEffect(() => {
    if (!isRunning) return;

    const interval = setInterval(() => {
      setData((currentData) => {
        prevDataRef.current = [...currentData];
        const lastPrice = currentData[currentData.length - 1].price;
        const newPrice = lastPrice + (Math.random() - 0.5) * 2;
        const newDataPoint = {
          time: new Date().toISOString(),
          price: newPrice,
          isNew: true,
        };
        const updatedData = currentData.map((point) => ({ ...point, isNew: false }));
        return [...updatedData.slice(1), newDataPoint];
      });
    }, 1000);

    return () => clearInterval(interval);
  }, [isRunning]);

  const formatTime = (time) => new Date(time).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", second: "2-digit" });

  return (
    <div className={darkMode ? "dark" : ""}>
      <div className="bg-background min-h-screen p-4">
        <Card className="w-full max-w-4xl mx-auto">
          <CardHeader className="flex flex-row items-center justify-between">
            <div>
              <CardTitle>BTC/USD Real-Time Chart</CardTitle>
              <CardDescription>Live price updates every second</CardDescription>
            </div>
            <div className="flex items-center space-x-4">
              <span className="text-sm text-muted-foreground">Dark Mode</span>
              <Switch checked={darkMode} onCheckedChange={() => setDarkMode(!darkMode)} />
              <span className="text-sm text-muted-foreground">Live Updates</span>
              <Switch checked={isRunning} onCheckedChange={() => setIsRunning(!isRunning)} />
            </div>
          </CardHeader>
          <CardContent>
            <Tabs defaultValue="line">
              <TabsList>
                <TabsTrigger value="line">Line</TabsTrigger>
                <TabsTrigger value="area">Area</TabsTrigger>
              </TabsList>
              <TabsContent value="line">
                <ChartContainer config={{ price: { label: "Price", color: "hsl(var(--chart-1))" } }}>
                  <LineChart data={data} margin={{ top: 10, right: 10, left: 10, bottom: 0 }}>
                    <CartesianGrid strokeDasharray="3 3" vertical={false} stroke="var(--border)" />
                    <XAxis dataKey="time" tickFormatter={formatTime} tick={{ fontSize: 12 }} />
                    <YAxis tickFormatter={(value) => `$${value.toFixed(2)}`} />
                    <ChartTooltip content={<ChartTooltipContent formatter={(value) => `$${Number(value).toFixed(2)}`} />} />
                    <Line type="monotone" dataKey="price" stroke="var(--color-price)" strokeWidth={2} />
                  </LineChart>
                </ChartContainer>
              </TabsContent>
              <TabsContent value="area">
                <ChartContainer config={{ price: { label: "Price", color: "hsl(var(--chart-1))" } }}>
                  <AreaChart data={data} margin={{ top: 10, right: 10, left: 10, bottom: 0 }}>
                    <CartesianGrid strokeDasharray="3 3" vertical={false} stroke="var(--border)" />
                    <XAxis dataKey="time" tickFormatter={formatTime} tick={{ fontSize: 12 }} />
                    <YAxis tickFormatter={(value) => `$${value.toFixed(2)}`} />
                    <ChartTooltip content={<ChartTooltipContent formatter={(value) => `$${Number(value).toFixed(2)}`} />} />
                    <Area type="monotone" dataKey="price" stroke="var(--color-price)" fillOpacity={0.2} />
                  </AreaChart>
                </ChartContainer>
              </TabsContent>
            </Tabs>
          </CardContent>
        </Card>
      </div>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Conclusion

With ShadCN UI's chart components, you can easily create a responsive and visually appealing real-time chart

For a live demo, check out: Live Demo.

If you want to customize your chart, check the documentation.
Do you have any questions? Leave a comment below or chat with me on X

Top comments (0)

OSZAR »