arukompas/livewire-charts
Livewire Charts is a Laravel package that adds ready-to-use Livewire components for ApexCharts, making it easy to render interactive line, bar, pie, donut, area, and radial charts. Charts update reactively with Livewire data, require minimal Blade markup, and fit neatly into existing Laravel apps.
v3.3.0 is a compatibility-only release: it adds Laravel 13 support and nothing else. There are no breaking changes from v3.2.0 and no API changes. If you are pinned to ^3.2 on Laravel 12, you can upgrade for free; if you are on Laravel 13, this is the minimum version you need.
composer require asantibanez/livewire-charts
Two things to look at first:
</body>:
@livewireChartsScripts
If you skip this, you get an empty <div> and no error — the single most common first-hour bug.Asantibanez\LivewireCharts\Models\* (LineChartModel, ColumnChartModel, PieChartModel, AreaChartModel, MultiLineChartModel, RadialChartModel, …). Each is a fluent builder that serializes to an Apex options array; the matching Blade component (<livewire:livewire-line-chart>, etc.) renders it.Minimal first use case — a monthly revenue line chart inside a Livewire component:
use Asantibanez\LivewireCharts\Models\LineChartModel;
public function revenueChart(): LineChartModel
{
return (new LineChartModel())
->setTitle('Revenue')
->setAnimated(true)
->addPoint('Jan', 1200)
->addPoint('Feb', 1850)
->addPoint('Mar', 2400);
}
<livewire:livewire-line-chart
key="{{ $this->revenueChart()->reactiveKey() }}"
:line-chart-model="$this->revenueChart()"
/>
Build the model in PHP, never in the Blade template — the model is your only clean seam for filtering, formatting and testing.
Model builders as the unit of work. Every chart type follows the same shape: instantiate, chain, pass to the component. Keep model construction in a method, a computed property, or a small App\Charts\* class so the same builder can be reused across dashboard and detail pages.
Reactivity via reactiveKey(). The chart component only redraws when its key changes. reactiveKey() derives a key from the serialized model, so mutating the model and re-rendering is enough to get a fresh chart. If you build the model inside render(), call reactiveKey() on the same instance you pass to the component — building it twice produces two different keys and a double render.
Filtering dashboards. Standard pattern: date range / segment lives in public properties, updatedDateRange() resets the chart, and render() rebuilds the model. Pair with wire:key on the chart component and avoid wire:model.live on inputs that fire on every keystroke — chart rebuilds are cheap in PHP but the Apex re-init is not.
Live/polling data. wire:poll on the wrapper works, but throttle it (wire:poll.10s) and keep the payload small. For streaming metrics, prefer updating a numeric summary and refreshing the chart on an interval rather than pushing every data point.
Point-click events. ->withOnPointClickEvent('onPointClick') emits a browser event from the chart. Listen for it in the component:
protected $listeners = ['onPointClick' => 'handlePointClick'];
Use this to drill down (e.g. click a bar → open an order list). Note the event name is what you pass to withOnPointClickEvent, not a fixed package name.
Customising Apex options. Use the typed helpers first (setColors(), setDataLabelsEnabled(), setHorizontal(), withGrid(), withXAxis(), withYAxis()), then fall back to ->setJsonConfig([...]) for anything the fluent API doesn't cover (tooltips, themes, annotations, stacked totals). This is the package's real extension point — the fluent API is a thin convenience layer over Apex, not a replacement.
Reusable chart builders. For dashboards with 5+ charts, extract each chart into a class with a __invoke(array $filters): LineChartModel signature. It keeps Livewire components thin, makes the charts unit-testable, and centralises colour/label conventions.
Testing. Livewire::test(Dashboard::class)->assertSee('Revenue') covers render, and you can assert on the model directly:
$this->assertSame(3, $this->revenueChart()->getSeries()['data'] ... );
Assert on the model's output rather than the rendered SVG — the DOM is Apex's, not yours.
@livewireChartsScripts fails silently. No console error in many setups, just an empty container. First debugging step, always.reactiveKey() isn't changing or you're reusing a cached model instance. In Livewire 3 also confirm you put wire:key on the component, not just key.wire:keys. Two line charts built from identical models produce identical reactive keys and can collide.'2025-01-01' or 'Jan'). Apex will treat raw Carbon/DateTime objects inconsistently across chart types; format in PHP.setJsonConfig is a merge, not a replace. Your values override defaults at the top level; nested Apex config (e.g. tooltip.x.formatter) may need the whole nested array. Don't assume deep merge for every key.emit; in Livewire 3 you dispatch. The package's point-click behaviour is a browser event — make sure your listener is registered in $listeners and that the name matches exactly.setColors([...]) once in a shared builder and pass Apex theme options through setJsonConfig(['theme' => ['mode' => 'dark']]). Don't hardcode in Blade.addSlice(label, value), while line/column/area use addPoint(label, value). Mixing them up is a common copy-paste error when swapping chart types.setJsonConfig() for raw Apex options, and subclassing the chart Blade component if you need global overrides (e.g. a house style wrapper). Prefer a wrapper Blade component over subclassing unless you need to change the component's PHP behaviour.How can I help you explore Laravel packages today?