On this page
Vue Dashboard
Create an admin dashboard that displays KPIs, charts, and a data table. Practice Vue 3 Composition API, routing, centralized state, and data visualization.
Requirements
- Node.js 18+ and npm
- Basic Vue 3 knowledge — components, reactivity, and templates
- Familiarity with REST APIs or mock data
Features
- Sidebar navigation with multiple views
- KPI cards (revenue, users, orders, growth)
- Line and bar charts for trends
- Sortable data table
- Responsive layout
Step 1: Scaffold the Project
npm create vue@latest dashboard -- --typescript --router --pinia
cd dashboard
npm install chart.js vue-chartjs
npm run dev
Step 2: Mock Data
src/data/mock.ts
export const kpis = [
{ label: 'Revenue', value: '$48,290', change: '+12.5%', positive: true },
{ label: 'Users', value: '2,847', change: '+8.2%', positive: true },
{ label: 'Orders', value: '1,203', change: '-3.1%', positive: false },
{ label: 'Growth', value: '24.8%', change: '+4.6%', positive: true },
];
export const salesData = {
labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'],
datasets: [{ label: 'Sales', data: [12, 19, 8, 15, 22, 30], borderColor: '#3b82f6' }],
};
export const orders = [
{ id: 1001, customer: 'Alice Chen', product: 'Pro Plan', amount: 99, status: 'Completed' },
{ id: 1002, customer: 'Bob Smith', product: 'Basic Plan', amount: 29, status: 'Pending' },
{ id: 1003, customer: 'Carol Lee', product: 'Enterprise', amount: 299, status: 'Completed' },
];
Step 3: KPI Card Component
src/components/KpiCard.vue
<script setup lang="ts">
defineProps<{ label: string; value: string; change: string; positive: boolean }>();
</script>
<template>
<div class="kpi-card">
<p class="label">{{ label }}</p>
<p class="value">{{ value }}</p>
<p :class="['change', positive ? 'up' : 'down']">{{ change }}</p>
</div>
</template>
<style scoped>
.kpi-card { background: #fff; border-radius: 8px; padding: 1.5rem; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }
.value { font-size: 1.75rem; font-weight: bold; margin: 0.25rem 0; }
.up { color: #16a34a; } .down { color: #dc2626; }
</style>
Step 4: Chart Component
src/components/SalesChart.vue
<script setup lang="ts">
import { Line } from 'vue-chartjs';
import { Chart as ChartJS, LineElement, PointElement, LinearScale, CategoryScale, Title, Tooltip, Legend } from 'chart.js';
ChartJS.register(LineElement, PointElement, LinearScale, CategoryScale, Title, Tooltip, Legend);
defineProps<{ chartData: object }>();
</script>
<template>
<div class="chart-container">
<Line :data="chartData" :options="{ responsive: true, plugins: { legend: { display: false } } }" />
</div>
</template>
Step 5: Dashboard View
src/views/DashboardView.vue
<script setup lang="ts">
import KpiCard from '@/components/KpiCard.vue';
import SalesChart from '@/components/SalesChart.vue';
import { kpis, salesData } from '@/data/mock';
</script>
<template>
<div class="dashboard">
<h1>Overview</h1>
<div class="kpi-grid">
<KpiCard v-for="kpi in kpis" :key="kpi.label" v-bind="kpi" />
</div>
<div class="chart-section">
<h2>Sales Trend</h2>
<SalesChart :chart-data="salesData" />
</div>
</div>
</template>
<style scoped>
.kpi-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 1rem; margin: 1.5rem 0; }
.chart-section { background: #fff; border-radius: 8px; padding: 1.5rem; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }
</style>
Step 6: Layout and Orders Store
src/App.vue — sidebar with RouterLink to Overview and Orders views. src/stores/orders.ts — Pinia store that holds the mock orders array and a setSort(key) action to toggle ascending/descending column sort.
Extension Ideas
- Live data — fetch KPIs from a REST API with
fetchinonMounted - Date range filter — let users select a time window to update charts
- Dark mode — toggle theme with a Pinia store and CSS variables
- Export CSV — download the orders table as a spreadsheet
- Notifications panel — show recent alerts in a dropdown
- Role-based views — restrict certain pages based on user permissions