# 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 */}
{/* 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 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 (
);
}
```
### 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';
```