How to Add shadcn Charts to a Next.js App Without Writing Recharts Boilerplate — Opportunihub
Course Remote

How to Add shadcn Charts to a Next.js App Without Writing Recharts Boilerplate

Ash · Remote

At a glance

Type
Course
Organisation
Ash
Location
Remote
Work mode
Remote
Deadline
Rolling / not stated
Posted
2 Oct 2026

About this course

<p>Charts look like a small task on a ticket. Then you open the Recharts docs and remember how much setup every chart needs: a config object for labels and colors, axes, a tooltip, a legend, colors that work in dark mode, and a container that resizes properly. Most of us copy all of that from the last project and rename the keys.</p> <p>The shadcn/ui chart component removes part of this work. It wraps Recharts with theme-aware colors and tooltips. But you still write every chart by hand.</p> <p>So I built ChartCN, a free and open-source <a href="https://www.shadcndeck.com/chartcn">shadcn chart generator</a>. You paste your data, pick a chart, and copy one TSX file that depends only on the shadcn/ui chart component and Recharts. It's MIT licensed, and there's no account or extra package.</p> <p>In this tutorial, you'll learn how to add a revenue-versus-expenses bar chart to a fresh Next.js app. We'll walk through what each part of the generated code does, and then connect the chart to data loaded in a Server Component. The tool saves you the typing, but Steps 5 and 6 apply to any shadcn/ui chart, whether you generate it or write it yourself.</p> <p><strong>Prerequisites:</strong> You should be comfortable with React and have Node.js installed. Basic familiarity with the Next.js App Router helps, but every step is explained.</p> <h2 id="heading-table-of-contents">Table of Contents</h2> <ul> <li><p><a href="#heading-what-youll-build">What You'll Build</a></p> </li> <li><p><a href="#heading-step-1-create-a-nextjs-app-and-initialize-shadcnui">Step 1: Create a Next.js App and Initialize shadcn/ui</a></p> </li> <li><p><a href="#heading-step-2-add-the-shadcnui-chart-component">Step 2: Add the shadcn/ui Chart Component</a></p> </li> <li><p><a href="#heading-step-3-generate-the-chart-component-in-chartcn">Step 3: Generate the Chart Component in ChartCN</a></p> </li> <li><p><a href="#heading-step-4-add-the-chart-to-your-page">Step 4: Add the Chart to Your Page</a></p> </li> <li><p><a href="#heading-step-5-understand-the-generated-code">Step 5: Understand the Generated Code</a></p> </li> <li><p><a href="#heading-step-6-pass-live-data-as-a-prop">Step 6: Pass Live Data as a Prop</a></p> </li> <li><p><a href="#heading-common-issues-and-how-to-fix-them">Common Issues and How to Fix Them</a></p> </li> <li><p><a href="#heading-summary">Summary</a></p> </li> </ul> <h2 id="heading-what-youll-build">What You'll Build</h2> <p>By the end, you'll have two pages:</p> <ul> <li><p><code>/</code> shows a grouped bar chart with the data written directly in the component. This is the fastest way to get a chart on screen.</p> </li> <li><p><code>/live</code> shows the same chart, but the data comes from an async function running on the server. This is the version you'd use with a real database or API.</p> </li> </ul> <img src="https://cdn.hashnode.com/uploads/covers/6a4ea012258c41204fefcf8b/546e7105-3d43-4bd0-a064-a877fffe930a.png" alt="Shadcn Charts - Finished Bar Chart" style="display: block;" width="600" height="400" loading="lazy"> <p>The chart has gradient bars, compact axis labels (40K instead of 40000), a legend, and a tooltip that shows the month's total and each series' share of it.</p> <h2 id="heading-step-1-create-a-nextjs-app-and-initialize-shadcnui">Step 1: Create a Next.js App and Initialize shadcn/ui</h2> <p>Create a new app and move into it:</p> <pre><code class="language-bash">npx create-next-app@latest my-charts-app cd my-charts-app </code></pre> <p>Accept the recommended defaults. You need TypeScript, Tailwind CSS, and the App Router.</p> <p>Next, initialize shadcn/ui:</p> <pre><code class="language-bash">npx shadcn@latest init </code></pre> <p>This command does three things you'll rely on later:</p> <ol> <li><p>It creates <code>components.json</code>, which tells the shadcn/ui CLI where to put components.</p> </li> <li><p>It adds <code>lib/utils.ts</code> with the <code>cn()</code> class-merging helper.</p> </li> <li><p>It writes theme variables into <code>app/globals.css</code>, including five chart colors: <code>--chart-1</code> through <code>--chart-5</code>, with separate values for light and dark mode.</p> </li> </ol> <p>Those five chart variables matter. Every generated chart uses them, so changing a chart color across your whole app means editing one line of CSS.</p> <h2 id="heading-step-2-add-the-shadcnui-chart-component">Step 2: Add the shadcn/ui Chart Component</h2> <p>Now add the chart component:</p> <pre><code class="language-bash">npx shadcn@latest add chart </code></pre> <p>This installs <code>recharts</code> and creates <code>components/ui/chart.tsx</code>. That file exports the building blocks you'll see in the generated code:</p> <ul> <li><p><code>ChartContainer</code> wraps Recharts' <code>ResponsiveContainer</code>, so the chart fills its parent.</p> </li> <li><p><code>ChartConfig</code> is the type for the object that maps each data key to a label and a color.</p> </li> <li><p><code>ChartTooltip</code>, <code>ChartTooltipContent</code>, <code>ChartLegend</code>, and <code>ChartLegendContent</code> are styled versions of the Recharts tooltip and legend.</p> </li> </ul> <p>Before moving on, check which Recharts version was installed:</p> <pre><code class="language-bash">npm ls recharts </code></pre> <p>The code ChartCN generates targets <strong>Recharts 3</strong>. If you see a 2.x version, upgrade it:</p> <pre><code class="language-bash">npm install recharts@latest </code></pre> <p><strong>Takeaway:</strong> the shadcn/ui chart component is a thin layer over Recharts. It doesn't replace Recharts. It gives Recharts your theme.</p> <h2 id="heading-step-3-generate-the-chart-component-in-chartcn">Step 3: Generate the Chart Component in ChartCN</h2> <p>Open the <a href="https://www.shadcndeck.com/chartcn/charts/bar">ChartCN bar chart page</a>. The data panel has three tabs: <strong>Paste data</strong>, <strong>Upload file</strong>, and <strong>Edit table</strong>. Paste this CSV into the <strong>Paste data</strong> tab:</p> <pre><code class="language-plaintext">Month,Revenue,Expenses Jan,42000,31000 Feb,58000,34000 Mar,51000,29000 Apr,67000,38000 May,72000,41000 Jun,69000,37000 </code></pre> <p>ChartCN treats the first column as the category axis (the x-axis for a bar chart) and every other column as a numeric series. JSON, TSV, and Markdown tables also work, and the format is detected automatically.</p> <img src="https://cdn.hashnode.com/uploads/covers/6a4ea012258c41204fefcf8b/997a85da-f44d-4e88-8ffe-120ea66b8884.png" alt="Shadcn Charts - Bar Chart" style="display: block;" width="600" height="400" loading="lazy"> <p>Above the preview, set these options:</p> <ul> <li><p><strong>Layout:</strong> Grouped</p> </li> <li><p><strong>Tooltip:</strong> Breakdown</p> </li> <li><p><strong>Code:</strong> Inline data</p> </li> </ul> <p>Then click <strong>Copy component</strong> in the <code>chart.tsx</code> panel below the preview.</p> <img src="https://cdn.hashnode.com/uploads/covers/6a4ea012258c41204fefcf8b/3317c6c9-e4f4-4b59-ad19-2076728048cd.png" alt="Shadcn Charts - ChartCn Copy component" style="display: block;" width="600" height="400" loading="lazy"> <h2 id="heading-step-4-add-the-chart-to-your-page">Step 4: Add the Chart to Your Page</h2> <p>Create a new file at <code>components/revenue-chart.tsx</code> and paste the copied code into it.</p> <p>Don't save it as <code>components/ui/chart.tsx</code>. ChartCN labels its output <code>chart.tsx</code>, but that path already holds the <a href="https://www.shadcndeck.com/blog/shadcn-components">shadcn component</a> from Step 2, and overwriting it breaks every chart in your app.</p> <p>The generated component is always exported as <code>Chart</code>, so give it a clearer name when you import it. Replace <code>app/page.tsx</code> with this:</p> <pre><code class="language-tsx">// app/page.tsx import { Chart as RevenueChart } from "@/components/revenue-chart" export default function Home() { return ( &lt;main className="mx-auto max-w-3xl p-8"&gt; &lt;h1 className="mb-6 text-2xl font-semibold"&gt;Revenue vs. expenses&lt;/h1&gt; &lt;RevenueChart /&gt; &lt;/main&gt; ) } </code></pre> <p>Run <code>npm run dev</code> and open <code>http://localhost:3000</code>. You should see the chart.</p> <p><strong>Takeaway:</strong> a generated chart is just a component in your project. There's nothing to configure and no package to keep in sync.</p> <h2 id="heading-step-5-understand-the-generated-code">Step 5: Understand the Generated Code</h2> <p>You own this file now, so it's worth knowing what each part does. Here are the important pieces, trimmed for length.</p> <p>The file starts with a directive and its imports:</p> <pre><code class="language-tsx">// components/revenue-chart.tsx "use client" import { useId } from "react" import { Bar, BarChart, CartesianGrid, Rectangle, XAxis, YAxis } from "recharts" import { type ChartConfig, ChartContainer, ChartLegend, ChartLegendContent, ChartTooltip, } from "@/components/ui/chart" </code></pre> <p>Recharts measures the DOM and handles mouse events, so the chart must be a Client Component. <code>app/page.tsx</code> can stay a Server Component because it only renders the chart.</p> <p>Next come the data and the config:</p> <pre><code class="language-tsx">const data = [ { Month: "Jan", Revenue: 42000, Expenses: 31000 }, { Month: "Feb", Revenue: 58000, Expenses: 34000 }, // ... ] const chartConfig = { Revenue: { label: "Revenue", color: "var(--chart-1)" }, Expenses: { label: "Expenses", color: "var(--chart-2)" }, } satisfies ChartConfig </code></pre> <p>The keys in <code>chartConfig</code> must match the keys in your data. <code>ChartContainer</code> reads this config and creates a CSS variable for each key, scoped to this chart: <code>--color-Revenue</code> and <code>--color-Expenses</code>. Each one points at a theme color, so the chart switches colors in dark mode on its own.</p> <p>The chart itself uses those variables:</p> <pre><code class="language-tsx">&lt;ChartContainer config={chartConfig} className="aspect-auto h-[350px] w-full"&gt; &lt;BarChart accessibilityLayer data={data} barCategoryGap="30%" barGap={4}&gt; {/* ...gradient &lt;defs&gt;, grid, axes, tooltip, legend... */} &lt;Bar dataKey="Revenue" fill="var(--color-Revenue)" shape={(props) =&gt; &lt;Rectangle {...props} fill={`url(#${uid}-fill-0)`} /&gt;} radius={[6, 6, 0, 0]} maxBarSize={36} /&gt; &lt;/BarChart&gt; &lt;/ChartContainer&gt; </code></pre> <p>A few details are worth knowing:</p> <ul> <li><p><strong>Height</strong> is set by <code>h-[350px]</code> on <code>ChartContainer</code>. Change it there.</p> </li> <li><p><strong>The gradient</strong> is drawn by the <code>shape</code> prop, while <code>fill</code> stays a solid color. That's why the legend and tooltip dots show a clean color instead of a gradient.</p> </li> <li><p><code>uid</code> comes from <code>useId()</code>, so the gradient IDs stay unique if you render two charts on the same page.</p> </li> </ul> <p>The file also includes a <code>ChartBreakdownTooltip</code> component, about 70 lines, that shows the total and each series' percentage. If you'd rather use the standard <a href="https://www.shadcndeck.com/blog/shadcn-tooltip-component">shadcn tooltip</a>, pick <strong>Tooltip: Simple</strong> in ChartCN before copying. The whole file then drops from about 120 lines to about 50.</p> <p><strong>Takeaway:</strong> in shadcn/ui charts, colors flow from theme variables through <code>chartConfig</code> into <code>--color-&lt;key&gt;</code> variables. Once you understand that path, you can edit any chart by hand.</p> <h2 id="heading-step-6-pass-live-data-as-a-prop">Step 6: Pass Live Data as a Prop</h2> <p>Hardcoded data is fine for a demo. For real data, go back to ChartCN, switch <strong>Code</strong> to <strong>Data as prop</strong>, and copy again. Save this version as <code>components/revenue-chart-live.tsx</code>.</p> <p>The chart markup is identical. Only the top of the file changes: the <code>data</code> array is replaced by a type, and the component accepts <code>data</code> as a prop:</p> <pre><code class="language-tsx">// components/revenue-chart-live.tsx export type ChartRow = { Month: string; Revenue: number | null; Expenses: number | null } export interface ChartProps { data: ChartRow[] } // ...chartConfig is unchanged... export function Chart({ data }: ChartProps) { // ...same JSX as before } </code></pre> <p>The series are typed as <code>number | null</code> because real data has gaps. A <code>null</code> value renders as a missing bar, not as a bar of zero.</p> <p>Now create a function that loads the data on the server:</p> <pre><code class="language-ts">// lib/get-revenue.ts import type { ChartRow } from "@/components/revenue-chart-live" export async function getRevenue(): Promise&lt;ChartRow[]&gt; { // Replace this with your database query or API call. // For example: const res = await fetch("https://api.example.com/revenue") return [ { Month: "Jan", Revenue: 42000, Expenses: 31000 }, { Month: "Feb", Revenue: 58000, Expenses: 34000 }, { Month: "Mar", Revenue: 51000, Expenses: 29000 }, { Month: "Apr", Revenue: 67000, Expenses: 38000 }, { Month: "May", Revenue: 72000, Expenses: null }, ] } </code></pre> <p>Then call it from a Server Component page:</p> <pre><code class="language-tsx">// app/live/page.tsx import { Chart as RevenueChart } from "@/components/revenue-chart-live" import { getRevenue } from "@/lib/get-revenue" export default async function LivePage() { const data = await getRevenue() return ( &lt;main className="mx-auto max-w-3xl p-8"&gt; &lt;h1 className="mb-6 text-2xl font-semibold"&gt;Revenue vs. expenses&lt;/h1&gt; &lt;RevenueChart data={data} /&gt; &lt;/main&gt; ) } </code></pre> <p>Open <code>http://localhost:3000/live</code>. May shows a Revenue bar with no Expenses bar next to it, because that value is <code>null</code>.</p> <p>The page fetches on the server and sends only the rows to the client component. Your database credentials and API keys stay on the server. When you swap in a real <code>fetch</code> or database call, check the <a href="https://nextjs.org/docs/app/getting-started/fetching-data">Next.js data fetching docs</a> to control how often the data refreshes.</p> <p><strong>Takeaway:</strong> keep data loading in a Server Component and rendering in a Client Component. The exported <code>ChartRow</code> type makes TypeScript check that your data matches what the chart expects.</p> <h2 id="heading-common-issues-and-how-to-fix-them">Common Issues and How to Fix Them</h2> <p><strong>Type errors such as "Property 'itemSorter' does not exist".</strong> Your project has Recharts 2 installed. Run <code>npm install recharts@latest</code> to upgrade to Recharts 3.</p> <p><strong>The bars are black and the legend dots are missing.</strong> Your <code>app/globals.css</code> doesn't define <code>--chart-1</code> through <code>--chart-5</code>. Run <code>npx shadcn@latest init</code> again, or copy the chart variables from the shadcn/ui theming docs.</p> <p><strong>Every chart stopped working after you pasted one.</strong> You probably saved the generated file over <code>components/ui/chart.tsx</code>. Restore it with <code>npx shadcn@latest add chart --overwrite</code> and save your chart under a different name.</p> <p><strong>Two charts on one page have the same name.</strong> Every generated component is exported as <code>Chart</code>. Rename it when you import it, for example <code>import { Chart as SignupsChart } from "@/components/signups-chart"</code>.</p> <h2 id="heading-summary">Summary</h2> <ol> <li><p><strong>The shadcn/ui chart component themes Recharts.</strong> It doesn't replace it, and ChartCN's output requires Recharts 3.</p> </li> <li><p><strong>Colors flow from CSS variables.</strong> <code>--chart-1</code> becomes <code>--color-Revenue</code> through <code>chartConfig</code>, so dark mode works without extra code.</p> </li> <li><p><strong>Save generated charts under their own names.</strong> <code>components/ui/chart.tsx</code> belongs to shadcn/ui.</p> </li> <li><p><strong>Use Data as prop for real data.</strong> Load it in a Server Component and pass the typed rows to the chart.</p> </li> <li><p><code>null</code> <strong>means "no data".</strong> Gaps render as gaps, not as zeros.</p> </li> </ol> <p>Because ChartCN is a <a href="https://www.shadcndeck.com/chartcn">shadcn chart generator</a> rather than a component library, there is no ChartCN package to install or keep updated. You can browse all 13 <a href="https://www.shadcndeck.com/chartcn/charts">shadcn charts</a> it supports, including line, area, pie, radar, KPI cards, waterfall, and a heatmap. They all follow the same paste, pick, and copy workflow you used here.</p> <p>The source is on <a href="https://github.com/ShadcnDeck/chartcn-shadcn-chart-generator">GitHub</a> under the MIT license. If it's useful, a star helps other developers find it.</p>

How to apply

  1. 1 Read the full details above and confirm you meet the eligibility criteria.
  2. 2 Prepare your documents — an updated CV, and any cover letter, proposal or certificates required.
  3. 3 Click Apply on official site to complete your application on Ash’s official page.
  4. 4 Submit as early as possible — many close once filled.
Apply on official site

Sourced from freecodecamp. Always verify details on the official website. Opportunihub never charges you to apply.

Frequently asked questions

How do I apply for How to Add shadcn Charts to a Next.js App Without Writing Recharts Boilerplate?

Review the full details and eligibility on this page, prepare your documents, then use the “Apply on official site” button to complete your application on Ash’s official page.

Is this opportunity remote or location-based?

This opportunity is remote-friendly and open to applicants who can work from anywhere.

Is How to Add shadcn Charts to a Next.js App Without Writing Recharts Boilerplate free to apply for?

Opportunihub lists this Course for free. Legitimate Courses do not ask for payment to apply — never pay a fee to submit an application.