# Dashboard Libraries Implementation Guide ## Table of Contents - [Tremor Quick Start](#tremor-quick-start) - [React Grid Layout Setup](#react-grid-layout-setup) - [Combining Libraries](#combining-libraries) - [Migration Strategies](#migration-strategies) - [Advanced Configurations](#advanced-configurations) - [Troubleshooting](#troubleshooting) ## Tremor Quick Start ### Installation & Setup ```bash # Install Tremor with Tailwind CSS npm install @tremor/react tailwindcss @tailwindcss/forms # Initialize Tailwind if not already configured npx tailwindcss init -p ``` ### Tailwind Configuration for Tremor ```javascript // tailwind.config.js module.exports = { content: [ './src/**/*.{js,ts,jsx,tsx}', './node_modules/@tremor/**/*.{js,ts,jsx,tsx}', // Tremor components ], theme: { extend: { colors: { tremor: { brand: { faint: '#eff6ff', muted: '#bfdbfe', subtle: '#60a5fa', DEFAULT: '#3b82f6', emphasis: '#1d4ed8', inverted: '#ffffff', }, background: { muted: '#f9fafb', subtle: '#f3f4f6', DEFAULT: '#ffffff', emphasis: '#374151', }, // Additional Tremor colors... } } } }, plugins: [require('@tailwindcss/forms')] }; ``` ### Basic Tremor Dashboard ```tsx import { Card, Title, Text, Tab, TabList, TabGroup, TabPanel, TabPanels, Grid, Metric, BadgeDelta, Flex, ProgressBar, AreaChart, BarChart, DonutChart, Table, TableHead, TableRow, TableHeaderCell, TableBody, TableCell } from '@tremor/react'; function TremorDashboard() { return (
Analytics Dashboard Track your key metrics and performance indicators {/* KPI Cards Row */}
Revenue $45,231.89
12.5%
New Customers 1,234
-2.3%
Active Users 8,456
5.1%
Retention Rate 92.5%
0.0%
{/* Charts Section */}
Revenue Trend
{/* Table Section */} Recent Transactions Transaction Amount Status {transactions.map(item => ( {item.name} {item.amount} {item.status} ))}
); } ``` ### Advanced Tremor Components #### Multi-Metric Cards ```tsx function MultiMetricCard() { return (
Sales $12,699 from $10,456
Profit $4,034 from $3,210
32% of annual target
); } ``` #### Tabbed Dashboard ```tsx function TabbedDashboard() { return ( Overview Detail Analysis {/* Overview widgets */} {/* Detailed charts */} {/* Analysis tables */} ); } ``` ## React Grid Layout Setup ### Installation ```bash npm install react-grid-layout # Required CSS npm install react-resizable ``` ### Basic Setup ```tsx import GridLayout from 'react-grid-layout'; import 'react-grid-layout/css/styles.css'; import 'react-resizable/css/styles.css'; function BasicGridDashboard() { const layout = [ { i: 'a', x: 0, y: 0, w: 4, h: 2 }, { i: 'b', x: 4, y: 0, w: 4, h: 2 }, { i: 'c', x: 8, y: 0, w: 4, h: 2 }, { i: 'd', x: 0, y: 2, w: 12, h: 4 } ]; return (
); } ``` ### Responsive Grid Layout ```tsx import { Responsive, WidthProvider } from 'react-grid-layout'; const ResponsiveGridLayout = WidthProvider(Responsive); function ResponsiveDashboard() { const [layouts, setLayouts] = useState(getFromLS('layouts') || {}); const handleLayoutChange = (layout, layouts) => { saveToLS('layouts', layouts); setLayouts(layouts); }; return (
Widget 1
Widget 2
Widget 3
); } // Local Storage helpers function getFromLS(key) { let ls = {}; if (global.localStorage) { try { ls = JSON.parse(global.localStorage.getItem('rgl-8')) || {}; } catch (e) {} } return ls[key]; } function saveToLS(key, value) { if (global.localStorage) { global.localStorage.setItem( 'rgl-8', JSON.stringify({ [key]: value }) ); } } ``` ### Advanced Grid Features #### Drag Handle & Resize Restrictions ```tsx function RestrictedGridDashboard() { const layout = [ { i: 'header', x: 0, y: 0, w: 12, h: 1, static: true // Cannot be moved or resized }, { i: 'kpi1', x: 0, y: 1, w: 3, h: 2, minW: 2, maxW: 4, minH: 1, maxH: 3 }, { i: 'chart', x: 3, y: 1, w: 9, h: 4, minW: 6, minH: 3 } ]; return (

Dashboard Header (Static)

⋮⋮
⋮⋮
); } ``` #### Widget Catalog with Add/Remove ```tsx function CustomizableDashboard() { const [widgets, setWidgets] = useState([ { id: 'widget-1', type: 'kpi', x: 0, y: 0, w: 3, h: 2 } ]); const widgetCatalog = [ { type: 'kpi', name: 'KPI Card', defaultSize: { w: 3, h: 2 } }, { type: 'chart', name: 'Chart', defaultSize: { w: 6, h: 4 } }, { type: 'table', name: 'Table', defaultSize: { w: 6, h: 3 } } ]; const addWidget = (type) => { const catalogItem = widgetCatalog.find(w => w.type === type); const newWidget = { id: `widget-${Date.now()}`, type, x: 0, y: Infinity, // Will be placed at bottom ...catalogItem.defaultSize }; setWidgets([...widgets, newWidget]); }; const removeWidget = (id) => { setWidgets(widgets.filter(w => w.id !== id)); }; return (
{/* Widget Catalog */}
{widgetCatalog.map(item => ( ))}
{/* Grid Dashboard */} {widgets.map(widget => (
{renderWidget(widget)}
))}
); } ``` ## Combining Libraries ### Tremor Components in Grid Layout ```tsx import { Card, Metric, Text, AreaChart } from '@tremor/react'; import { Responsive, WidthProvider } from 'react-grid-layout'; const ResponsiveGridLayout = WidthProvider(Responsive); function HybridDashboard() { const layouts = { lg: [ { i: 'revenue-kpi', x: 0, y: 0, w: 3, h: 2 }, { i: 'users-kpi', x: 3, y: 0, w: 3, h: 2 }, { i: 'chart', x: 0, y: 2, w: 6, h: 4 }, { i: 'table', x: 6, y: 0, w: 6, h: 6 } ] }; return ( {/* Tremor KPI Card */}
Revenue $45,231
{/* Tremor KPI Card */}
Active Users 1,234
{/* Tremor Chart */}
{/* Custom Table Widget */}
); } ``` ### Custom Widget Wrapper ```tsx function WidgetWrapper({ widget, children }) { const [isLoading, setIsLoading] = useState(true); const [hasError, setHasError] = useState(false); useEffect(() => { // Simulate loading setTimeout(() => setIsLoading(false), 1000); }, []); return ( {/* Widget Header */}
{widget.title}
{/* Widget Content */}
{isLoading ? (
) : hasError ? (
Failed to load widget
) : ( children )}
{/* Resize Handle (for react-grid-layout) */}
); } ``` ## Migration Strategies ### Migrating from Static to Grid Layout ```tsx // Before: Static Dashboard function StaticDashboard() { return (
); } // After: Grid Layout Dashboard function MigratedDashboard() { // Convert static positions to grid layout const staticToGridLayout = () => { return [ { i: 'kpi-1', x: 0, y: 0, w: 4, h: 2 }, { i: 'kpi-2', x: 4, y: 0, w: 4, h: 2 }, { i: 'kpi-3', x: 8, y: 0, w: 4, h: 2 }, { i: 'chart', x: 0, y: 2, w: 6, h: 4 }, { i: 'table', x: 6, y: 2, w: 6, h: 4 } ]; }; const [layout, setLayout] = useState(staticToGridLayout()); const [isCustomizable, setIsCustomizable] = useState(false); return ( <>
); } ``` ## Advanced Configurations ### Dynamic Grid Configuration ```tsx function DynamicGridConfig() { const [config, setConfig] = useState({ cols: 12, rowHeight: 60, compactType: 'vertical', margin: [10, 10] }); const updateConfig = (key, value) => { setConfig({ ...config, [key]: value }); }; return (
{/* Configuration Panel */}
{/* Grid with dynamic config */} {/* Widgets */}
); } ``` ### Theme Integration ```tsx // Tremor with custom theme const customTheme = { dark: { background: '#1a1a1a', card: '#2a2a2a', text: '#ffffff', border: '#3a3a3a' }, light: { background: '#ffffff', card: '#f9fafb', text: '#111827', border: '#e5e7eb' } }; function ThemedDashboard({ theme = 'light' }) { const colors = customTheme[theme]; return (
{widgets.map(widget => (
{renderWidget(widget)}
))}
); } ``` ## Troubleshooting ### Common Issues and Solutions #### 1. Grid Layout CSS Not Loading ```tsx // Ensure CSS imports are correct import 'react-grid-layout/css/styles.css'; import 'react-resizable/css/styles.css'; // Or import in your main CSS file /* styles.css */ @import '~react-grid-layout/css/styles.css'; @import '~react-resizable/css/styles.css'; ``` #### 2. Widgets Overlapping ```tsx // Set preventCollision to true ``` #### 3. Responsive Layout Not Working ```tsx // Must wrap with WidthProvider const ResponsiveGridLayout = WidthProvider(Responsive); // Don't pass width prop when using WidthProvider ``` #### 4. Tremor Components Not Styled ```javascript // Ensure Tailwind processes Tremor files // tailwind.config.js module.exports = { content: [ './src/**/*.{js,jsx,ts,tsx}', './node_modules/@tremor/**/*.{js,ts,jsx,tsx}', // Important! ] }; ``` #### 5. Performance Issues with Many Widgets ```tsx // Use React.memo for widget components const MemoizedWidget = React.memo(({ data }) => { return {/* Widget content */}; }, (prevProps, nextProps) => { // Custom comparison return prevProps.data === nextProps.data; }); // Virtualize if > 50 widgets import { FixedSizeGrid } from 'react-window'; ```