Skip to content

Instantly share code, notes, and snippets.

@ejabu
Created September 16, 2025 19:40
Show Gist options
  • Select an option

  • Save ejabu/68db0a9fee757592e39c41eb9d383cd6 to your computer and use it in GitHub Desktop.

Select an option

Save ejabu/68db0a9fee757592e39c41eb9d383cd6 to your computer and use it in GitHub Desktop.
Bar Chart, Drill Down with Shadcn context menu
import React, { useState } from 'react';
import { BarChart, Bar, XAxis, YAxis, ResponsiveContainer, Cell } from 'recharts';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuSub,
DropdownMenuSubContent,
DropdownMenuSubTrigger,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
const data = [
{ name: 'Jan', value: 400, details: 'Q1 Performance: Strong growth in new markets' },
{ name: 'Feb', value: 300, details: 'Q1 Performance: Seasonal adjustment period' },
{ name: 'Mar', value: 300, details: 'Q1 Performance: Recovery after February dip' },
{ name: 'Apr', value: 200, details: 'Q2 Performance: Market consolidation phase' },
{ name: 'May', value: 278, details: 'Q2 Performance: Mid-quarter improvement' },
{ name: 'Jun', value: 189, details: 'Q2 Performance: End of quarter challenges' },
{ name: 'Jul', value: 349, details: 'Q3 Performance: Summer campaign success' },
{ name: 'Aug', value: 400, details: 'Q3 Performance: Peak season results' },
];
const BarChartWithContextMenu = () => {
const [contextMenu, setContextMenu] = useState(null);
const [hoveredIndex, setHoveredIndex] = useState(null);
const [dropdownOpen, setDropdownOpen] = useState(false);
const handleBarClick = (event, data, index) => {
event.stopPropagation();
setContextMenu({
x: event.clientX,
y: event.clientY,
data: data,
index: index
});
setDropdownOpen(true);
};
const handleContextMenuAction = (action, data) => {
console.log(`${action} clicked for:`, data);
alert(`${action} selected for ${data.name}: ${data.details}`);
setContextMenu(null);
setDropdownOpen(false);
};
const handleClickOutside = () => {
setContextMenu(null);
setDropdownOpen(false);
};
const getBarColor = (index) => {
return hoveredIndex === index ? '#ff6b6b' : '#8884d8';
};
return (
<div
className="w-full h-96 p-4 bg-white relative"
onClick={handleClickOutside}
>
<h2 className="text-2xl font-bold mb-4 text-gray-800">Monthly Performance</h2>
<ResponsiveContainer width="100%" height="100%">
<BarChart data={data} margin={{ top: 20, right: 30, left: 20, bottom: 5 }}>
<XAxis
dataKey="name"
tick={{ fontSize: 12 }}
axisLine={{ stroke: '#e0e0e0' }}
/>
<YAxis
tick={{ fontSize: 12 }}
axisLine={{ stroke: '#e0e0e0' }}
gridline={{ stroke: '#f0f0f0' }}
/>
<Bar
dataKey="value"
radius={[4, 4, 0, 0]}
onMouseEnter={(data, index) => setHoveredIndex(index)}
onMouseLeave={() => setHoveredIndex(null)}
>
{data.map((entry, index) => (
<Cell
key={`cell-${index}`}
fill={getBarColor(index)}
onClick={(event) => handleBarClick(event, entry, index)}
style={{ cursor: 'pointer' }}
/>
))}
</Bar>
</BarChart>
</ResponsiveContainer>
{contextMenu && (
<div
className="fixed z-50"
style={{
left: contextMenu.x,
top: contextMenu.y,
}}
>
<DropdownMenu open={dropdownOpen} onOpenChange={setDropdownOpen}>
<DropdownMenuTrigger asChild>
<div className="w-0 h-0" />
</DropdownMenuTrigger>
<DropdownMenuContent className="w-56">
<DropdownMenuLabel>
{contextMenu.data.name} - {contextMenu.data.value}
</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuItem
onClick={() => handleContextMenuAction('View Details', contextMenu.data)}
>
View Details
</DropdownMenuItem>
<DropdownMenuSub>
<DropdownMenuSubTrigger>
Drill Down
</DropdownMenuSubTrigger>
<DropdownMenuSubContent>
<DropdownMenuItem
onClick={() => handleContextMenuAction('Daily Breakdown', contextMenu.data)}
>
Daily Breakdown
</DropdownMenuItem>
<DropdownMenuItem
onClick={() => handleContextMenuAction('Weekly Analysis', contextMenu.data)}
>
Weekly Analysis
</DropdownMenuItem>
<DropdownMenuItem
onClick={() => handleContextMenuAction('Product Categories', contextMenu.data)}
>
Product Categories
</DropdownMenuItem>
<DropdownMenuItem
onClick={() => handleContextMenuAction('Regional Data', contextMenu.data)}
>
Regional Data
</DropdownMenuItem>
</DropdownMenuSubContent>
</DropdownMenuSub>
<DropdownMenuSub>
<DropdownMenuSubTrigger>
Export Data
</DropdownMenuSubTrigger>
<DropdownMenuSubContent>
<DropdownMenuItem
onClick={() => handleContextMenuAction('Export as CSV', contextMenu.data)}
>
CSV
</DropdownMenuItem>
<DropdownMenuItem
onClick={() => handleContextMenuAction('Export as PDF', contextMenu.data)}
>
PDF
</DropdownMenuItem>
<DropdownMenuItem
onClick={() => handleContextMenuAction('Export as Excel', contextMenu.data)}
>
Excel
</DropdownMenuItem>
<DropdownMenuItem
onClick={() => handleContextMenuAction('Export as JSON', contextMenu.data)}
>
JSON
</DropdownMenuItem>
</DropdownMenuSubContent>
</DropdownMenuSub>
<DropdownMenuSeparator />
<DropdownMenuItem
onClick={() => handleContextMenuAction('Compare', contextMenu.data)}
>
Compare
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>
)}
</div>
);
};
export default BarChartWithContextMenu;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment