Laravel + Vue + Chart.js: Build Dashboards That Sell Themselves

Dashboards are the nerve center of modern applications. Whether you’re tracking user growth, revenue, or system metrics, a well‑designed dashboard provides clarity and insight. Laravel gives us the backend power, Chart.js provides sleek visualizations, and Vue.js adds reactivity and modularity. Together, they form a perfect stack for building dynamic dashboards.


🎯 Why This Stack?

  • Laravel: Handles data aggregation, APIs, and authentication.
  • Chart.js: Lightweight, responsive, and supports multiple chart types.
  • Vue.js: Component‑based, reactive, and scales beautifully with complex dashboards.

🛠️ Step 1: Setting Up Laravel + Vue

  1. Create a fresh Laravel project:
    composer create-project laravel/laravel laravel-dashboard cd laravel-dashboard php artisan serve
  2. Install Vue:
    npm install vue@next chart.js
  3. Configure resources/js/app.js:

    import { createApp } from 'vue';
    import UserChart from './components/UserChart.vue';
    import RevenueChart from './components/RevenueChart.vue';
    import CategoryChart from './components/CategoryChart.vue';

    const app = createApp({});
    app.component('user-chart', UserChart);
    app.component('revenue-chart', RevenueChart);
    app.component('category-chart', CategoryChart);
    app.mount('#app');

📊 Step 2: Backend Data Preparation

Example controller (DashboardController.php):

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\User;
use App\Models\Order;

class DashboardController extends Controller
{
    public function index()
    {
        $usersPerMonth = User::selectRaw('MONTH(created_at) as month, COUNT(*) as count')
            ->groupBy('month')
            ->pluck('count', 'month');

        $revenuePerMonth = Order::selectRaw('MONTH(created_at) as month, SUM(amount) as total')
            ->groupBy('month')
            ->pluck('total', 'month');

        $categoryDistribution = Order::selectRaw('category, COUNT(*) as count')
            ->groupBy('category')
            ->pluck('count', 'category');

        return view('dashboard', compact('usersPerMonth', 'revenuePerMonth', 'categoryDistribution'));
    }
}

🎨 Step 3: Blade View with Vue Components

resources/views/dashboard.blade.php:

<!DOCTYPE html>
<html>
<head>
    <title>Laravel Dashboard</title>
    @vite('resources/js/app.js')
</head>
<body>
    <div id="app">
        <h1>Dashboard</h1>
        <user-chart :chart-data='@json($usersPerMonth)'></user-chart>
        <revenue-chart :chart-data='@json($revenuePerMonth)'></revenue-chart>
        <category-chart :chart-data='@json($categoryDistribution)'></category-chart>
    </div>
</body>
</html>

📈 Step 4: Multiple Chart Types with Vue Components

1. Line Chart (User Growth)

resources/js/components/UserChart.vue:

<template>
  <canvas id="userChart"></canvas>
</template>

<script>
import { Chart } from 'chart.js/auto';

export default {
  props: ['chartData'],
  mounted() {
    new Chart(document.getElementById('userChart'), {
      type: 'line',
      data: {
        labels: Object.keys(this.chartData),
        datasets: [{
          label: 'Users Registered',
          data: Object.values(this.chartData),
          borderColor: '#42A5F5',
          backgroundColor: 'rgba(66, 165, 245, 0.2)',
          fill: true,
          tension: 0.3
        }]
      }
    });
  }
}
</script>

2. Bar Chart (Revenue)

resources/js/components/RevenueChart.vue:

<template>
  <canvas id="revenueChart"></canvas>
</template>

<script>
import { Chart } from 'chart.js/auto';

export default {
  props: ['chartData'],
  mounted() {
    new Chart(document.getElementById('revenueChart'), {
      type: 'bar',
      data: {
        labels: Object.keys(this.chartData),
        datasets: [{
          label: 'Revenue ($)',
          data: Object.values(this.chartData),
          backgroundColor: '#4CAF50'
        }]
      }
    });
  }
}
</script>

3. Pie Chart (Category Distribution)

resources/js/components/CategoryChart.vue:

<template>
  <canvas id="categoryChart"></canvas>
</template>

<script>
import { Chart } from 'chart.js/auto';

export default {
  props: ['chartData'],
  mounted() {
    new Chart(document.getElementById('categoryChart'), {
      type: 'pie',
      data: {
        labels: Object.keys(this.chartData),
        datasets: [{
          label: 'Orders by Category',
          data: Object.values(this.chartData),
          backgroundColor: ['#FF6384', '#36A2EB', '#FFCE56', '#4CAF50']
        }]
      }
    });
  }
}
</script>

4. Radar Chart (Performance Metrics)

Optional component for advanced dashboards:

<template>
  <canvas id="performanceChart"></canvas>
</template>

<script>
import { Chart } from 'chart.js/auto';

export default {
  props: ['chartData'],
  mounted() {
    new Chart(document.getElementById('performanceChart'), {
      type: 'radar',
      data: {
        labels: Object.keys(this.chartData),
        datasets: [{
          label: 'Performance',
          data: Object.values(this.chartData),
          backgroundColor: 'rgba(255, 99, 132, 0.2)',
          borderColor: '#FF6384'
        }]
      }
    });
  }
}
</script>

🔧 Step 5: Dynamic API Integration

Instead of embedding data directly, fetch via API:

fetch('/api/revenue-per-month')
  .then(res => res.json())
  .then(data => {
    chart.data.labels = Object.keys(data);
    chart.data.datasets[0].data = Object.values(data);
    chart.update();
  });

🧭 Final Thoughts

By combining Laravel, Vue.js, and Chart.js, you can build dashboards that are:

  • Reactive: Charts update instantly when data changes.
  • Modular: Each chart is a Vue component.
  • Versatile: Line, bar, pie, radar, and more.
  • Scalable: Perfect for SaaS dashboards, admin panels, or analytics platforms.

This stack empowers developers to deliver dashboards that are not only functional but also visually compelling — turning raw data into actionable insights.

Leave a Reply

Your email address will not be published. Required fields are marked *