Skip to main content

@ttoss/react-dashboard

About

A comprehensive React dashboard module that provides customizable dashboard functionality with filters, templates, responsive grid layouts, and an edit mode to build and save layouts. This module enables you to create data-rich dashboards with support for multiple card types, filter systems, and template management.

Installation

pnpm add @ttoss/react-dashboard

Getting Started

Provider Setup

If you're using the Dashboard component directly, you don't need to set up the provider separately as it wraps the DashboardProvider internally. However, if you need to use the useDashboard hook in other components, you can wrap your application with the DashboardProvider:

import { DashboardProvider } from '@ttoss/react-dashboard';
import { ThemeProvider } from '@ttoss/ui';
import type {
DashboardTemplate,
DashboardFilter,
} from '@ttoss/react-dashboard';

const templates: DashboardTemplate[] = [];
const filters: DashboardFilter[] = [];
const selectedTemplate: DashboardTemplate | undefined = undefined;

ReactDOM.render(
<React.StrictMode>
<ThemeProvider>
<DashboardProvider
filters={filters}
templates={templates}
selectedTemplate={selectedTemplate}
>
<App />
</DashboardProvider>
</ThemeProvider>
</React.StrictMode>,
document.getElementById('root')
);

Basic Dashboard Usage

import { Dashboard } from '@ttoss/react-dashboard';
import type {
DashboardTemplate,
DashboardFilter,
} from '@ttoss/react-dashboard';
import { DashboardFilterType } from '@ttoss/react-dashboard';

const MyDashboard = () => {
const selectedTemplate: DashboardTemplate = {
id: 'default',
name: 'Default Template',
description: 'My default dashboard layout',
grid: [
{
i: 'card-1',
x: 0,
y: 0,
w: 4,
h: 4,
card: {
title: 'Total Revenue',
numberType: 'currency',
type: 'bigNumber',
sourceType: [{ source: 'api' }],
data: {
api: { total: 150000 },
},
},
},
],
};

const filters: DashboardFilter[] = [
{
key: 'date-range',
type: DashboardFilterType.DATE_RANGE,
label: 'Date Range',
value: { from: new Date(), to: new Date() },
},
];

return (
<Dashboard
selectedTemplate={selectedTemplate}
templates={[]}
filters={filters}
loading={false}
/>
);
};

Editable Dashboard Usage

Use editable mode to let users reorganize cards, remove/add cards from a catalog, save changes to the current template, or save a cloned template.

import { Dashboard, DEFAULT_CARD_CATALOG } from '@ttoss/react-dashboard';
import type {
DashboardTemplate,
CardCatalogItem,
} from '@ttoss/react-dashboard';

const cardCatalog: CardCatalogItem[] = DEFAULT_CARD_CATALOG;

const selectedTemplate: DashboardTemplate = {
id: 'default',
name: 'Performance Dashboard',
editable: true,
grid: [],
};

<Dashboard
selectedTemplate={selectedTemplate}
templates={[selectedTemplate]}
filters={[]}
editable
cardCatalog={cardCatalog}
onSaveLayout={(template) => {
// Persist edited layout for current template
}}
onSaveAsNewTemplate={(template) => {
// Persist cloned template
}}
onCancelEdit={() => {
// Optional callback when user cancels edit mode
}}
/>;

Components

Dashboard

The main dashboard component that orchestrates the entire dashboard experience.

import { Dashboard } from '@ttoss/react-dashboard';

<Dashboard
selectedTemplate={selectedTemplate}
templates={templates}
filters={filters}
loading={false}
headerChildren={<CustomHeaderContent />}
onFiltersChange={(filters) => {
// Handle filter changes
}}
/>;

Props:

PropTypeDefaultDescription
selectedTemplateDashboardTemplate | undefined-The template to display in the dashboard
templatesDashboardTemplate[][]Array of dashboard templates
filtersDashboardFilter[][]Array of dashboard filters
loadingbooleanfalseLoading state for the dashboard
cardCatalogCardCatalogItem[]default catalogCard types available in "Add item" while editing
headerChildrenReact.ReactNode-Additional content to render in the header
onFiltersChange(filters: DashboardFilter[]) => void-Callback when filters change
editablebooleanfalseEnables dashboard edit mode controls
onSaveLayout(template: DashboardTemplate) => void-Called when user saves edits to current template
onSaveAsNewTemplate(template: DashboardTemplate) => void-Called when user saves edited layout as a new template
onCancelEdit() => void-Called when user cancels edit mode

DashboardProvider

Context provider that manages dashboard state (filters and templates).

import { DashboardProvider } from '@ttoss/react-dashboard';

<DashboardProvider
filters={filters}
templates={templates}
selectedTemplate={selectedTemplate}
onFiltersChange={handleFiltersChange}
>
{children}
</DashboardProvider>;

Props:

PropTypeDefaultDescription
childrenReact.ReactNode-Child components
filtersDashboardFilter[][]Filter state
templatesDashboardTemplate[][]Template state
cardCatalogCardCatalogItem[]default catalogCard types available in edit mode
selectedTemplateDashboardTemplate | undefined-The template to display
onFiltersChange(filters: DashboardFilter[]) => void-Callback when filters change
editablebooleanfalseEnables dashboard edit controls
onSaveLayout(template: DashboardTemplate) => void-Saves edits in current template
onSaveAsNewTemplate(template: DashboardTemplate) => void-Saves edits as a new template
onCancelEdit() => void-Called when editing is canceled

useDashboard Hook

Hook to access and modify dashboard state.

import { useDashboard } from '@ttoss/react-dashboard';

const MyComponent = () => {
const {
filters,
updateFilter,
templates,
selectedTemplate,
editable,
isEditMode,
startEdit,
cancelEdit,
saveEdit,
addCard,
} = useDashboard();

// Use dashboard state
const handleFilterChange = (key: string, value: DashboardFilterValue) => {
updateFilter(key, value);
};

if (editable && !isEditMode) {
startEdit();
}
};

Returns:

PropertyTypeDescription
filtersDashboardFilter[]Current filter state
updateFilter(key: string, value: DashboardFilterValue) => voidUpdates a specific filter by key
templatesDashboardTemplate[]Current template state
selectedTemplateDashboardTemplate | undefinedCurrently selected template
cardCatalogCardCatalogItem[]Card catalog used by add-card drawer
editablebooleanWhether edit controls are enabled
isEditModebooleanWhether dashboard is currently in edit mode
editingGridDashboardGridItem[] | nullTemporary grid while editing
startEdit() => voidStarts edit mode
cancelEdit() => voidCancels edit mode and discards temporary changes
saveEdit() => voidSaves editing grid into current template callback
saveAsNew() => voidOpens save-as-new flow
saveAsNewModalOpenbooleanSave-as-new drawer state
confirmSaveAsNew(title: string) => voidConfirms save-as-new action
cancelSaveAsNew() => voidCancels save-as-new flow
addCard(item: CardCatalogItem) => voidAdds a card to editing grid
removeCard(id: string) => voidRemoves card from editing grid
updateCard(id: string, cardPatch: Record<string, unknown>) => voidPatches a card in editing grid
onLayoutChange(layout: Layout[]) => voidSyncs edited card positions/sizes from grid changes

DashboardCard

Component for rendering individual dashboard cards. Currently supports bigNumber type.

import { DashboardCard } from '@ttoss/react-dashboard';

<DashboardCard
title="Total Revenue"
description="Revenue from all sources"
numberType="currency"
numberDecimalPlaces={2}
type="bigNumber"
sourceType={[{ source: 'api' }]}
data={{
api: { total: 150000 },
}}
trend={{
value: 15.5,
status: 'positive',
}}
/>;

Props:

PropTypeDefaultDescription
idstring-Card identification
titlestring-Card title
descriptionstring-Optional card description
iconstring-Optional icon name
colorstring-Optional color for the card
variantCardVariant-Card variant ('default' | 'dark' | 'light-green')
numberTypeCardNumberType-Number formatting type ('number' | 'percentage' | 'currency')
numberDecimalPlacesnumber2Optional number of decimal places for number formatting (defaults to 2)
typeDashboardCardType-Card type ('bigNumber' | 'pieChart' | 'barChart' | 'lineChart' | 'table' | 'list')
sourceTypeCardSourceType[]-Data source configuration
labelsArray<string | number>-Optional labels for the card
dataDashboardCardData-Card data from various sources
trendTrendIndicator-Optional trend indicator
additionalInfostring-Optional additional information text
statusStatusIndicator-Optional status indicator
suffixstring-Optional text appended after the formatted number (e.g. "kg", "un", "p.p."). Not shown when value is undefined.

DashboardFilters

Component that automatically renders filters based on the dashboard state.

import { DashboardFilters } from '@ttoss/react-dashboard';

// Automatically renders filters from DashboardProvider context
<DashboardFilters />;

This component reads filters from the DashboardProvider context and renders the appropriate filter component for each filter type.

DashboardHeader

Header component that displays filters and optional custom content.

import { DashboardHeader } from '@ttoss/react-dashboard';

<DashboardHeader>
<CustomActionButtons />
</DashboardHeader>;

Props:

PropTypeDescription
childrenReact.ReactNodeOptional content to render in header

DashboardGrid

Responsive grid layout component that displays dashboard cards using react-grid-layout.

import { DashboardGrid } from '@ttoss/react-dashboard';

<DashboardGrid loading={false} />;

Props:

PropTypeDefaultDescription
loadingboolean-Shows loading spinner if true

DashboardSectionDivider

Component that displays a section divider with a title and horizontal line to visually separate sections in the dashboard grid.

import { DashboardSectionDivider } from '@ttoss/react-dashboard';

<DashboardSectionDivider title="Performance Metrics" />;

Props:

PropTypeDefaultDescription
titlestring-The title of the section
typestring-Must be 'sectionDivider'

Usage in Dashboard Grid:

Section dividers can be added to the dashboard grid just like regular cards. They help organize dashboard content into logical sections:

const selectedTemplate: DashboardTemplate = {
id: 'default',
name: 'Default Template',
grid: [
{
i: 'card-1',
x: 0,
y: 0,
w: 4,
h: 4,
card: {
id: 'abc-123',
title: 'Total Revenue',
type: 'bigNumber',
// ... other card properties
},
},
{
i: 'divider-1',
x: 0,
y: 4,
w: 12, // Full width for divider
h: 2, // Smaller height for divider
card: {
type: 'sectionDivider',
title: 'Performance Metrics',
},
},
{
i: 'card-2',
x: 0,
y: 6,
w: 4,
h: 4,
card: {
id: 'def-456',
title: 'ROAS',
type: 'bigNumber',
// ... other card properties
},
},
],
};

Filter Types

Text Filter

A text input filter for string values.

import { DashboardFilterType } from '@ttoss/react-dashboard';

const textFilter: DashboardFilter = {
key: 'search',
type: DashboardFilterType.TEXT,
label: 'Search',
placeholder: 'Enter search term...',
value: '',
onChange: (value) => {
console.log('Search:', value);
},
};

Select Filter

A dropdown select filter for predefined options.

const selectFilter: DashboardFilter = {
key: 'status',
type: DashboardFilterType.SELECT,
label: 'Status',
value: 'active',
options: [
{ label: 'Active', value: 'active' },
{ label: 'Inactive', value: 'inactive' },
],
onChange: (value) => {
console.log('Status:', value);
},
};

Date Range Filter

A date range picker with optional presets.

const dateRangeFilter: DashboardFilter = {
key: 'date-range',
type: DashboardFilterType.DATE_RANGE,
label: 'Date Range',
value: { from: new Date(), to: new Date() },
presets: [
{
label: 'Last 7 days',
getValue: () => ({
from: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000),
to: new Date(),
}),
},
{
label: 'Last 30 days',
getValue: () => ({
from: new Date(Date.now() - 30 * 24 * 60 * 60 * 1000),
to: new Date(),
}),
},
],
onChange: (value) => {
console.log('Date range:', value);
},
};

Types

DashboardTemplate

interface DashboardTemplate {
id: string;
name: string;
description?: string;
grid: DashboardGridItem[];
editable?: boolean;
}

DashboardGridItem

interface DashboardGridItem extends ReactGridLayout.Layout {
card: DashboardCard | SectionDivider;
}

DashboardFilter

interface DashboardFilter {
key: string;
type: DashboardFilterType;
label: string;
placeholder?: string;
value: DashboardFilterValue;
onChange?: (value: DashboardFilterValue) => void;
options?: { label: string; value: string | number | boolean }[];
presets?: { label: string; getValue: () => DateRange }[];
}

DashboardFilterValue

type DashboardFilterValue =
| string
| number
| boolean
| { from: Date; to: Date };

DashboardFilterType

enum DashboardFilterType {
TEXT = 'text',
SELECT = 'select',
DATE_RANGE = 'date-range',
NUMBER = 'number',
BOOLEAN = 'boolean',
}

DashboardCard

See DashboardCard section for full interface.

CardCatalogItem

Serializable card catalog item used by edit mode to add new cards to the layout.

type CardCatalogItem = Pick<DashboardGridItem, 'w' | 'h' | 'card'>;

CardNumberType

type CardNumberType = 'number' | 'percentage' | 'currency';

CardSourceType

type CardSourceType = {
source: 'meta' | 'oneclickads' | 'api';
level?: 'adAccount' | 'campaign' | 'adSet' | 'ad';
};

DashboardCardType

type DashboardCardType =
| 'bigNumber'
| 'pieChart'
| 'barChart'
| 'lineChart'
| 'table'
| 'list';

CardVariant

type CardVariant = 'default' | 'dark' | 'light-green';

TrendIndicator

Trend indicator that displays a percentage change with visual indicators.

type TrendIndicator = {
value: number;
status?: 'positive' | 'negative' | 'neutral';
type?: 'higher' | 'lower';
};

Behavior:

  • Positive status: Displays an up arrow icon and the percentage value (e.g., "10.5% vs. anterior")
  • Negative status: Displays a down arrow icon and the percentage value (e.g., "5.2% vs. anterior")
  • Neutral status: Displays no arrow icon, only the percentage value (e.g., "0.0% vs. anterior")
  • The value is always formatted to 1 decimal place followed by "%"
  • Note: Positive values do not include a "+" sign prefix

Example:

trend={{
value: 15.5,
status: 'positive',
type: 'higher', // Optional: indicates if higher/lower is good
}}

StatusIndicator

Status indicator that displays text with an optional icon.

type StatusIndicator = {
text: string;
icon?: string;
};

Example:

status={{
text: 'Active',
icon: 'mdi:check-circle',
}}

SectionDivider

Type for section divider items in the dashboard grid.

type SectionDivider = {
type: 'sectionDivider';
title: string;
};

Example:

{
i: 'divider-1',
x: 0,
y: 4,
w: 12,
h: 2,
card: {
type: 'sectionDivider',
title: 'Performance Metrics',
},
}

Complete Example

import { Dashboard } from '@ttoss/react-dashboard';
import type {
DashboardTemplate,
DashboardFilter,
} from '@ttoss/react-dashboard';
import { DashboardFilterType } from '@ttoss/react-dashboard';

const App = () => {
const selectedTemplate: DashboardTemplate = {
id: 'default',
name: 'Default Dashboard',
grid: [
{
i: 'revenue',
x: 0,
y: 0,
w: 4,
h: 4,
card: {
id: 'abc-123',
title: 'Total Revenue',
numberType: 'currency',
type: 'bigNumber',
sourceType: [{ source: 'api' }],
data: {
api: { total: 150000 },
},
trend: {
value: 15.5,
status: 'positive',
},
},
},
{
i: 'roas',
x: 4,
y: 0,
w: 4,
h: 4,
card: {
id: 'abc-456',
title: 'ROAS',
numberType: 'number',
numberDecimalPlaces: 2,
type: 'bigNumber',
sourceType: [{ source: 'api' }],
data: {
api: { total: 3.5 },
},
variant: 'light-green',
},
},
],
};

// Optional: Keep templates array if you need to switch between templates
const templates: DashboardTemplate[] = [selectedTemplate];

const filters: DashboardFilter[] = [
{
key: 'date-range',
type: DashboardFilterType.DATE_RANGE,
label: 'Date Range',
value: {
from: new Date(Date.now() - 30 * 24 * 60 * 60 * 1000),
to: new Date(),
},
presets: [
{
label: 'Last 7 days',
getValue: () => ({
from: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000),
to: new Date(),
}),
},
{
label: 'Last 30 days',
getValue: () => ({
from: new Date(Date.now() - 30 * 24 * 60 * 60 * 1000),
to: new Date(),
}),
},
],
},
];

const handleFiltersChange = (updatedFilters: DashboardFilter[]) => {
console.log('Filters changed:', updatedFilters);
// Update your data fetching logic here
};

return (
<Dashboard
selectedTemplate={selectedTemplate}
templates={templates}
filters={filters}
loading={false}
onFiltersChange={handleFiltersChange}
/>
);
};

License

MIT