Skip to main content

Overview

This example demonstrates how to build a comprehensive analytics dashboard using Magary components. The dashboard includes KPI summary cards, tabbed data sections, hierarchical organization charts, and drill-down capabilities.
Time to integrate: Less than 1 dayThis recipe shows you how to combine multiple Magary components to create a production-ready analytics interface.

Key Features

  • KPI cards with trend indicators
  • Tabbed navigation for different data views
  • Interactive data tables
  • Tree and organization chart visualizations
  • Overlay panels for quick drill-down details
  • Filter controls with selects

Components Used

MagaryCard

Container for KPI metrics

MagaryTabs

Organize data into logical sections

MagaryTable

Display tabular data

MagaryTree

Show hierarchical data structures

MagaryOrganizationChart

Visualize organizational hierarchies

MagaryOverlayPanel

Quick detail views

Project Structure

Organize your dashboard feature with this recommended structure:
src/app/dashboard/
  dashboard.page.ts
  dashboard.page.html
  dashboard.page.scss
  dashboard.models.ts
  dashboard.repository.ts

Data Models

Define your domain models for type safety:
dashboard.models.ts
export interface Kpi {
  id: string;
  label: string;
  value: number;
  delta: number;
  trend: 'UP' | 'DOWN' | 'STABLE';
}

export interface DashboardRow {
  name: string;
  owner: string;
  status: 'OK' | 'WARN' | 'CRITICAL';
  updatedAt: string;
}

export interface OrgNode {
  label: string;
  type: string;
  styleClass: string;
  expanded: boolean;
  data: { name: string; avatar: string };
  children?: OrgNode[];
}

Component Implementation

import { ChangeDetectionStrategy, Component, signal } from '@angular/core';
import { CommonModule } from '@angular/common';
import {
  MagaryCard,
  MagaryTabs,
  MagaryTab,
  MagaryTable,
  MagaryTree,
  MagaryOrganizationChart,
  MagaryOverlayPanel,
  MagarySelect,
  MagaryButton,
} from 'ng-magary';
import { Kpi, DashboardRow, OrgNode } from './dashboard.models';

@Component({
  selector: 'app-dashboard-page',
  standalone: true,
  imports: [
    CommonModule,
    MagaryCard,
    MagaryTabs,
    MagaryTab,
    MagaryTable,
    MagaryTree,
    MagaryOrganizationChart,
    MagaryOverlayPanel,
    MagarySelect,
    MagaryButton,
  ],
  templateUrl: './dashboard.page.html',
  styleUrls: ['./dashboard.page.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class DashboardPage {
  // KPI metrics
  readonly kpis = signal<Kpi[]>([
    { id: '1', label: 'Revenue', value: 125000, delta: 12.5, trend: 'UP' },
    { id: '2', label: 'Active Users', value: 8432, delta: -3.2, trend: 'DOWN' },
    { id: '3', label: 'Conversion Rate', value: 3.8, delta: 0.5, trend: 'UP' },
    { id: '4', label: 'Avg Session', value: 4.2, delta: 0, trend: 'STABLE' },
  ]);

  // Table data
  readonly dashboardRows = signal<DashboardRow[]>([
    { name: 'Project Alpha', owner: 'John Doe', status: 'OK', updatedAt: '2026-03-04' },
    { name: 'Project Beta', owner: 'Jane Smith', status: 'WARN', updatedAt: '2026-03-03' },
    { name: 'Project Gamma', owner: 'Bob Wilson', status: 'CRITICAL', updatedAt: '2026-03-02' },
  ]);

  // Organization hierarchy
  readonly orgData = signal<OrgNode[]>([
    {
      label: 'CEO',
      type: 'person',
      styleClass: 'p-person',
      expanded: true,
      data: { name: 'Sarah Johnson', avatar: 'assets/avatar-ceo.png' },
      children: [
        {
          label: 'CTO',
          type: 'person',
          styleClass: 'p-person',
          expanded: true,
          data: { name: 'Mike Chen', avatar: 'assets/avatar-cto.png' },
          children: [
            {
              label: 'Engineering',
              type: 'department',
              styleClass: 'p-department',
              expanded: false,
              data: { name: 'Engineering Team', avatar: '' },
            },
          ],
        },
        {
          label: 'CFO',
          type: 'person',
          styleClass: 'p-person',
          expanded: true,
          data: { name: 'Lisa Park', avatar: 'assets/avatar-cfo.png' },
        },
      ],
    },
  ]);

  // Selected filters
  readonly selectedPeriod = signal('month');
  readonly selectedRegion = signal('all');

  // Overlay state
  readonly overlayVisible = signal(false);
  readonly selectedKpi = signal<Kpi | null>(null);

  // Filter options
  readonly periodOptions = [
    { label: 'Last 7 Days', value: 'week' },
    { label: 'Last 30 Days', value: 'month' },
    { label: 'Last Quarter', value: 'quarter' },
    { label: 'Last Year', value: 'year' },
  ];

  readonly regionOptions = [
    { label: 'All Regions', value: 'all' },
    { label: 'North America', value: 'na' },
    { label: 'Europe', value: 'eu' },
    { label: 'Asia Pacific', value: 'apac' },
  ];

  showKpiDetails(kpi: Kpi, event: Event): void {
    this.selectedKpi.set(kpi);
    this.overlayVisible.set(true);
  }

  getTrendIcon(trend: Kpi['trend']): string {
    switch (trend) {
      case 'UP': return 'pi pi-arrow-up';
      case 'DOWN': return 'pi pi-arrow-down';
      case 'STABLE': return 'pi pi-minus';
    }
  }

  getStatusSeverity(status: DashboardRow['status']): string {
    switch (status) {
      case 'OK': return 'success';
      case 'WARN': return 'warning';
      case 'CRITICAL': return 'danger';
    }
  }
}

Layout Diagram

The dashboard follows this visual structure:
┌─────────────────────────────────────────────────────────┐
│ Analytics Dashboard          [Period ▼] [Region ▼]     │
├─────────────────────────────────────────────────────────┤
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐│
│  │ Revenue  │  │  Active  │  │Conversion│  │Avg Session││
│  │ 125,000  │  │  Users   │  │   Rate   │  │   Time   ││
│  │  +12.5%  │  │   8,432  │  │   3.8%   │  │   4.2m   ││
│  └──────────┘  │  -3.2%   │  │  +0.5%   │  │   0.0%   ││
│                 └──────────┘  └──────────┘  └──────────┘│
├─────────────────────────────────────────────────────────┤
│ [Data Table] [Organization] [Hierarchy Tree]            │
│ ┌───────────────────────────────────────────────────┐   │
│ │ Project Name    │ Owner       │ Status │ Updated  │   │
│ ├───────────────────────────────────────────────────┤   │
│ │ Project Alpha   │ John Doe    │ OK     │ 03/04/26 │   │
│ │ Project Beta    │ Jane Smith  │ WARN   │ 03/03/26 │   │
│ │ Project Gamma   │ Bob Wilson  │CRITICAL│ 03/02/26 │   │
│ └───────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────┘

Accessibility Checklist

  • All interactive elements (cards, tabs, table rows) are keyboard accessible
  • Tab/Shift+Tab moves focus between controls
  • Enter/Space activates buttons and toggles
  • Arrow keys navigate within tree and organization chart
  • Tabs follow proper role="tablist" and role="tabpanel" structure
  • Table has proper header associations
  • Overlay panel announces open/close states
  • Status indicators have accessible labels
  • KPI cards announce label, value, and trend
  • Tree nodes announce hierarchy level
  • Table columns have descriptive headers
  • Loading and error states are announced
  • Focus indicators are visible on all interactive elements
  • Status colors meet WCAG contrast requirements
  • Trend indicators use icons in addition to color
  • Empty states provide clear guidance

Best Practices

Performance: Use Angular signals for reactive state management and OnPush change detection to minimize re-renders.
Data Loading: Always implement loading, empty, and error states for tables and charts to provide clear feedback.
Responsiveness: The KPI grid automatically adapts to smaller screens using CSS Grid’s auto-fit and minmax.

Next Steps

Add Charts

Integrate chart components for visual data representation

Real-time Updates

Implement WebSocket connections for live dashboard updates

Export Data

Add CSV/Excel export functionality for tables

Custom Filters

Build advanced filtering with date ranges and multi-select

Build docs developers (and LLMs) love