Charts
The Portal uses ApexCharts via CDN
for data visualisation. Charts are initialised with vanilla JavaScript using
data- attributes, not Alpine.js components.
Sparkline charts
Small inline trend lines rendered as SVG polylines inside stat cards on the dashboard.
Each sparkline reads its data from data-sparkline,
colour from data-sparkline-color,
and optional labels from data-sparkline-labels.
These are custom SVG sparklines, not ApexCharts.
<!-- Sparkline container in a stat card -->
<div class="w-14 sm:w-20 h-8 flex-shrink-0"
data-sparkline="[2,5,3,8,6,12,9,15,11,18,14,24]"
data-sparkline-color="#6B7280"
data-sparkline-title="New"
data-sparkline-labels='["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]'>
</div>
<!-- The Layout script reads data-sparkline and renders an SVG polyline -->
<!-- with hover tooltips showing the title + value -->
Area charts (ApexCharts)
Fee breakdown charts on the dashboard and partner detail pages use ApexCharts with the
data-apex-chart attribute.
Chart data is passed via data-chart-data
as a JSON array of objects with label,
totalFees, and
referralFees properties.
Fees
<!-- Razor page -->
<div data-apex-chart
data-chart-data="@Html.Raw(System.Text.Encodings.Web.HtmlEncoder.Default.Encode(
Json.Serialize(Model.ChartData).ToString()!))">
</div>
<!-- ChartData is IReadOnlyList<ChartDataPoint> -->
<!-- Each point has: label (string), totalFees (decimal), referralFees (decimal) -->
<!-- The Layout script reads data-chart-data and creates an ApexCharts area chart -->
<!-- with custom tooltips, crosshair, dark mode support, and responsive tick amounts -->
Chart configuration pattern
Charts are initialised in the Portal's _Layout.cshtml
script block, not in individual pages. The script queries all [data-apex-chart]
elements and creates ApexCharts instances.
<!-- _Layout.cshtml script block -->
<script src="https://cdn.jsdelivr.net/npm/apexcharts"></script>
document.querySelectorAll('[data-apex-chart]').forEach(function (el) {
var raw = el.getAttribute('data-chart-data');
var chartData = JSON.parse(raw);
var isDark = document.documentElement.classList.contains('dark');
var chart = new ApexCharts(el, {
chart: {
type: 'area',
height: 300,
fontFamily: 'Inter, sans-serif',
toolbar: { show: false },
zoom: { enabled: false },
background: 'transparent'
},
series: [
{ name: 'Gross fees', data: chartData.map(p => p.totalFees) },
{ name: 'Referral fees', data: chartData.map(p => p.referralFees) }
],
xaxis: {
categories: chartData.map(p => p.label),
labels: { style: { colors: isDark ? '#9CA3AF' : '#6B7280' } }
},
yaxis: {
labels: {
formatter: val => '\u00A3' + val.toLocaleString('en-GB'),
style: { colors: isDark ? '#9CA3AF' : '#6B7280' }
}
},
colors: ['#6B8E73', '#B8860B'],
fill: { type: 'gradient', gradient: { opacityFrom: 0.55, opacityTo: 0.0 } },
stroke: { curve: 'smooth', width: 3 },
theme: { mode: isDark ? 'dark' : 'light' }
});
chart.render();
});
Dark mode integration
Charts detect dark mode at render time via
document.documentElement.classList.contains('dark').
Key dark mode adjustments:
| Property | Light | Dark |
|---|---|---|
| Axis label colour | #6B7280 (gray-500) |
#9CA3AF (gray-400) |
| Theme mode | 'light' |
'dark' |
| Tooltip background | bg-white |
bg-gray-700 |
| Chart background | transparent (inherits card bg) |
|
Tooltip CSS override
The default ApexCharts tooltip is hidden via CSS in the layout. Custom floating tooltips are rendered as absolutely-positioned DOM elements managed by JavaScript event handlers.
<!-- _Layout.cshtml style block -->
.apexcharts-tooltip {
background: transparent !important;
border: none !important;
box-shadow: none !important;
padding: 0 !important;
}
<!-- Custom tooltips are created as fixed DOM elements -->
<!-- with classes: fixed z-50 px-2.5 py-1.5 text-sm rounded-lg -->
<!-- bg-white dark:bg-gray-700 border border-gray-200 -->
<!-- dark:border-gray-600 shadow-md pointer-events-none -->