matheusmarnt/livecharts
LiveCharts is a reactive chart abstraction for Laravel using a pure PHP fluent API. Build 18 chart types and render via a single Livewire component. Supports ApexCharts and Chart.js with pluggable engines, enabling easy updates without JS boilerplate.
Reactive chart abstraction for Laravel — pure PHP API, multi-engine rendering, Livewire delivery.
LiveCharts unifies ApexCharts and Chart.js behind a single fluent PHP API. Define charts in PHP, render them with one Livewire component, and update them reactively from your application state — no JavaScript boilerplate, no engine-specific configuration leaking into your views.
LiveCharts::line()->labels(...)->dataset(...) or class extends ChartLiveCharts::registerEngine() for custom adapters<livewire:livecharts :chart="$chart" /> component handles mount, hydration, and re-renderChart::poll(5000) + wire:poll="refresh" integration with a livecharts:refreshed event for userland data hydrationonDataPointClick, onZoom, onSelection, onScroll map directly to Livewire eventsbroadcastOn() / broadcastAs()TwColor enum (all Tailwind v4 families + 4 extensions × 11 shades) with dark:/light: named-arg API: ->titleColor(dark: TwColor::Amber300, light: TwColor::Amber600). Charts re-color live on dark-mode toggle — no Livewire roundtrip->palette(TwPalette::Vibrant) auto-fills dataset colors from theme-aware preset schemes->titleFont(size: 18, weight: 'bold', family: 'Inter') for title, legend, and tooltipauto, light, or dark modes; JS observer watches <html class="dark"> (or prefers-color-scheme) and re-colors charts liveapexcharts.js, chartjs.js) and Chart.js plugin bundles (treemap/matrix/sankey/financial/luxon/adapter-luxon) ship pre-built in resources/dist; switch between local, cdn, or both via configlivecharts.js + every engine and plugin shim, verified in CIlivecharts:install can publish chart class stubs to stubs/livecharts for project-level customizationphp artisan livecharts:preview launches a gallery of every chart type in your default browseren, pt_BR, and es translationscomposer require matheusmarnt/livecharts
php artisan livecharts:install
This will:
config/livecharts.phppublic/vendor/livecharts/js (local-first delivery with CDN fallback by default — LIVECHARTS_ASSETS_MODE=both)stubs/livechartsNote: The default asset mode is
both(local first, CDN fallback). The files inpublic/vendor/livecharts/js/must exist for this to work. If you skip the install step or need to restore the assets after deployment, run:php artisan vendor:publish --tag=livecharts-assets --forceIf you prefer no local files at all, set
LIVECHARTS_ASSETS_MODE=cdnin.env— no publish step needed.
Then build a chart and render it:
use Matheusmarnt\LiveCharts\Facades\LiveCharts;
$chart = LiveCharts::line()
->title('Monthly Revenue')
->labels(['Jan', 'Feb', 'Mar'])
->dataset('2026', [100, 200, 150])
->colors(['#3B82F6']);
<livewire:livecharts :chart="$chart" />
Place the asset directive once in your layout, before @livewireScripts and before the closing </body> tag (or in the <head> when using a Blade layout with @extends/@section):
{{-- must come BEFORE @livewireScripts — livecharts.js registers Alpine components before Alpine starts --}}
@liveChartsScripts
@livewireScripts
Every method returns $this, so chains read top-down:
LiveCharts::bar()
->title('Sales by Region')
->subtitle('Q1 2026')
->labels(['North', 'South', 'East', 'West'])
->dataset('Sales', [400, 300, 600, 250])
->colors(['#10B981'])
->stacked()
->height(420)
->theme('auto');
Available factories: line, bar, area, pie, donut, radar, scatter, bubble, heatmap, rangeBar, radialBar, polarArea, boxPlot, treemap, candlestick, matrix, sankey, plus make() for the generic factory.
Generate a dedicated class for reusable charts:
php artisan make:chart RevenueChart --type=bar
namespace App\Charts;
use Matheusmarnt\LiveCharts\Charts\Chart;
use Matheusmarnt\LiveCharts\Charts\Dataset;
class RevenueChart extends Chart
{
protected string $type = 'bar';
public function __construct()
{
parent::__construct();
$this
->title('Revenue')
->labels(['Jan', 'Feb', 'Mar'])
->datasets([
Dataset::make('2026')->data([400, 300, 600])->color('#10B981'),
]);
}
}
<livewire:livecharts :chart="new App\Charts\RevenueChart" />
Stubs: running
livecharts:installand accepting the stubs prompt publishes the generator stub tostubs/livecharts/chart.stub. Edit that file to customize the boilerplate emitted bymake:chart.
$chart->poll(5000); // refresh every 5 seconds
The Livewire component subscribes via wire:poll="refresh" and dispatches a browser event on every tick:
window.addEventListener('livecharts:refreshed', (e) => {
// e.detail.id — chart DOM id
})
Hydrate fresh data inside refresh() on a parent Livewire component, or react to the event on the client.
$chart
->onDataPointClick('chart-clicked')
->onZoom('chart-zoomed')
->onSelection('chart-selected');
In the parent component:
use Livewire\Attributes\On;
#[On('chart-clicked')]
public function handle(array $data): void
{
// $data: ['seriesIndex' => 0, 'dataPointIndex' => 2, 'value' => 150, 'label' => 'Mar']
}
$chart->broadcastOn('private-charts.'.$user->id)->broadcastAs('chart.updated');
Subscribe via Laravel Echo and the chart re-renders when the channel fires.
The default engine is apexcharts. Override globally in config/livecharts.php or per chart:
LiveCharts::line()->engine('chartjs')->labels(...)->dataset(...);
Register a custom adapter at runtime:
use App\LiveCharts\Engines\HighchartsAdapter;
use Matheusmarnt\LiveCharts\Facades\LiveCharts;
LiveCharts::registerEngine('highcharts', HighchartsAdapter::class);
Implement Matheusmarnt\LiveCharts\Contracts\EngineAdapter and the engine becomes selectable from any chart.
| Command | Description |
|---|---|
livecharts:install |
Publish config, copy the JS runtime + engine bundles, optionally publish chart stubs |
make:chart {name} {--type=} {--engine=} |
Generate a new chart class under app/Charts; --type/--engine derived from Chart::TYPES and EngineFactory::names() |
livecharts:preview {--no-open} |
Open the gallery of every chart type at /livecharts/preview in your default browser; --no-open only prints the URL |
composer test
Runs the Pest suite (301 tests) against the package's testbench harness — including 17 Pest arch rules, payload + adapter routing for every chart type, Livewire color-roundtrip tests (Bugs 1 & 5), ApexCharts themed-color path tests, script-stack idempotency tests, wire:navigate asset strategy tests, and integration tests for UC-01 dashboard, UC-02 drill-down, UC-03 polling, and UC-04 multi-tenant flows. CI matrix: PHP 8.2-8.5 × Laravel 11/12/13 × Livewire 3/4 × prefer-lowest/stable × Ubuntu/Windows, with a --min=90 coverage gate and PHPStan level 8 enforcement.
See CHANGELOG for release history.
See CONTRIBUTING for details.
If you discover a security vulnerability, please email matheusmarnt@gmail.com instead of opening a public issue.
MIT — see LICENSE.
How can I help you explore Laravel packages today?