What is ApexCharts and Why Use It with CodeIgniter 4 for Dynamic Charts?
ApexCharts is a modern, open-source JavaScript charting library renowned for its stunning visuals, smooth animations, interactivity, and support for over 20 chart types—including bar, line, area, pie, and more. Unlike older libraries, ApexCharts excels at handling dynamic data updates without page reloads, making it perfect for real-time dashboards and analytics applications. When paired with CodeIgniter 4—a lightweight, powerful PHP framework—it allows developers to fetch MySQL data via controllers, process it server-side, and render interactive charts client-side using AJAX. This combination delivers fast, responsive, and filterable visualizations (like year-based monthly user registration bars) that enhance user experience in admin panels or reporting tools.
Why choose this approach? Traditional static charts limit insights, but dynamic filtering lets users drill down into data effortlessly—boosting engagement and decision-making. In this step-by-step CodeIgniter 4 ApexCharts tutorial, you'll learn exactly how to build a fully interactive bar chart: from database setup and AJAX endpoints to frontend integration with real-time updates. Whether you're building an admin dashboard or data-heavy web app, mastering dynamic charts with filter options in ApexCharts using CodeIgniter 4 will elevate your projects significantly.

Table Of Content
1 Prerequisites
- PHP 8.2+
- Composer
- MySQL server
- Basic CodeIgniter 4 knowledge
2 Introduction
In today's data-driven web applications, static charts simply aren't enough. Users expect interactive visualizations that let them explore insights on the fly—without waiting for page reloads. In this comprehensive CodeIgniter 4 tutorial, you'll learn exactly how to create a dynamic bar chart using ApexCharts, one of the most powerful and modern JavaScript charting libraries available today. We'll pull real user registration data from a MySQL database, display it as monthly bars, and add seamless year-based filter options powered by AJAX for instant updates and superior interactivity.
Whether you're building an admin dashboard, analytics panel, or reporting tool, this approach delivers responsive, visually appealing charts that enhance user experience and decision-making. By the end of this step-by-step guide, you'll master integrating ApexCharts with CodeIgniter 4's MVC structure, handling dynamic data via controllers, and implementing client-side filtering—no full page refreshes required. This technique is perfect for any PHP developer looking to level up their data presentation skills in 2026 and beyond.
3 How to Integrate ApexChart with Filter Options in CodeIgniter 4
3.1 Install Codeigniter 4 Project
composer create-project codeigniter4/appstarter ci4-apexcharts-example
Then, navigate to your project directory:
cd ci4-apexcharts-example
3.2 Configure Environment and MySql Database
# CI_ENVIRONMENT = production
CI_ENVIRONMENT = development
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=ci4_charts_db
DB_USERNAME=root
DB_PASSWORD=
Create the database ci4_charts_db in MySQL.
4 Create Migration and Model for Users Table
php spark make:migration CreateUsersTable
Define the table structure and migrate:
<?php
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
class CreateUsersTable extends Migration
{
public function up()
{
$this->forge->addField([
'id' => [
'type' => 'INT',
'constraint' => 5,
'unsigned' => true,
'auto_increment' => true,
],
'name' => [
'type' => 'VARCHAR',
'constraint' => '100',
],
'email' => [
'type' => 'VARCHAR',
'constraint' => '100',
],
'created_at' => [
'type' => 'DATETIME',
'null' => true,
],
'updated_at' => [
'type' => 'DATETIME',
'null' => true,
],
]);
$this->forge->addKey('id', true);
$this->forge->createTable('users');
}
public function down()
{
$this->forge->dropTable('users');
}
}
Run the migration:
php spark migrate
Create a migration for the users table and a model to manage data:
php spark make:model User
Edit app/Models/User.php to configure the model:
<?php
namespace App\Models;
use CodeIgniter\Model;
class User extends Model
{
protected $DBGroup = 'default';
protected $table = 'users';
protected $primaryKey = 'id';
protected $useAutoIncrement = true;
protected $returnType = 'array';
protected $useSoftDeletes = false;
protected $protectFields = true;
protected $allowedFields = ['name', 'email', 'created_at', 'updated_at'];
// Dates
protected $useTimestamps = false;
protected $dateFormat = 'datetime';
protected $createdField = 'created_at';
protected $updatedField = 'updated_at';
}
5 Create Database Seeder
php spark make:seeder UserSeeder
Inside the app/Database/Seeds/UserSeeder.php file, use the Faker library to generate fake data:
<?php
namespace App\Database\Seeds;
use CodeIgniter\Database\Seeder;
use Faker\Factory;
class UserSeeder extends Seeder
{
public function run()
{
$faker = Factory::create();
for ($i = 0; $i < 200; $i++) { // Generate 200 fake users
$createdAt = $faker->dateTimeBetween('-3 years', 'now'); // Dates from 2023-2026
$this->db->table('users')->insert([
'name' => $faker->name(),
'email' => $faker->email(),
'created_at' => $createdAt->format('Y-m-d H:i:s'),
'updated_at' => $createdAt->format('Y-m-d H:i:s'),
]);
}
}
}
Run this below command to insert the data.
php spark db:seed UserSeeder
6 Create New Controller - UserController
php spark make:controller UserController
In app/Controllers/UserController.php, define the index and filterData function:
<?php
namespace App\Controllers;
use App\Models\User;
use CodeIgniter\API\ResponseTrait;
use CodeIgniter\HTTP\RequestInterface;
class UserController extends BaseController
{
use ResponseTrait;
public function index()
{
// Get unique years from database for filter dropdown
$userModel = new User();
$years = $userModel->select('YEAR(created_at) as year')
->distinct()
->orderBy('year', 'DESC')
->findAll();
// Default to current year if no data
$defaultYear = date('Y');
if (empty($years)) {
$years = [['year' => $defaultYear]];
}
// Initial data for current/default year
$initialData = $this->getChartData($defaultYear);
return view('users/index', [
'years' => array_column($years, 'year'),
'initialData' => $initialData
]);
}
public function filterData(RequestInterface $request)
{
$year = $request->getPost('year');
// Validate year (basic check)
if (!is_numeric($year) || strlen($year) !== 4) {
return $this->fail('Invalid year', 400);
}
$data = $this->getChartData($year);
if (empty($data['series'][0]['data'])) {
return $this->fail('No data found for the selected year', 404);
}
return $this->respond($data);
}
private function getChartData($year)
{
$userModel = new User();
$monthlyData = $userModel->select("MONTH(created_at) as month, COUNT(id) as count")
->where('YEAR(created_at)', $year)
->groupBy('month')
->orderBy('month', 'ASC')
->findAll();
// Prepare months (1-12) with 0 if no data
$data = array_fill(1, 12, 0);
foreach ($monthlyData as $row) {
$data[(int)$row['month']] = (int)$row['count'];
}
return [
'categories' => ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
'series' => [
[
'name' => 'User Registrations',
'data' => array_values($data)
]
]
];
}
}
?>
7 Create Views for Dynamic Charts
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dynamic ApexCharts in CodeIgniter 4</title>
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- ApexCharts JS -->
<script src="https://cdn.jsdelivr.net/npm/apexcharts"></script>
<!-- jQuery -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body>
<div class="container mt-5">
<h1 class="text-center mb-4">Monthly User Registrations Chart</h1>
<!-- Filter Dropdown -->
<div class="row justify-content-center mb-4">
<div class="col-md-4">
<select id="yearFilter" class="form-select">
<?php foreach ($years as $year): ?>
<option value="<?= esc($year) ?>" <?= $year == date('Y') ? 'selected' : '' ?>><?= esc($year) ?></option>
<?php endforeach; ?>
</select>
</div>
</div>
<!-- Loading Spinner -->
<div id="loading" class="text-center" style="display: none;">
<div class="spinner-border text-primary" role="status"></div>
<p>Loading data...</p>
</div>
<!-- Chart Container -->
<div id="chart"></div>
</div>
<script>
// Initial data from PHP
var initialData = <?= json_encode($initialData) ?>
// ApexCharts options
var options = {
series: initialData.series,
chart: {
height: 350,
type: 'bar',
events: {
click: function(chart, w, e) {
// Optional: Handle click events
}
}
},
plotOptions: {
bar: {
columnWidth: '45%',
distributed: true,
}
},
dataLabels: {
enabled: false
},
legend: {
show: false
},
xaxis: {
categories: initialData.categories,
labels: {
style: {
fontSize: '12px'
}
}
},
yaxis: {
title: {
text: 'Registrations'
}
}
};
// Initialize chart
var chart = new ApexCharts(document.querySelector("#chart"), options);
chart.render();
// AJAX on filter change
$('#yearFilter').change(function() {
var year = $(this).val();
$('#loading').show();
$('#chart').hide();
$.ajax({
url: '/search',
type: 'POST',
data: { year: year },
dataType: 'json',
success: function(response) {
chart.updateOptions({
xaxis: {
categories: response.categories
}
});
chart.updateSeries(response.series);
$('#loading').hide();
$('#chart').show();
},
error: function(xhr, status, error) {
alert('Error fetching data: ' + error);
$('#loading').hide();
$('#chart').show();
}
});
});
</script>
</body>
</html>
8 Define a Route
use CodeIgniter\Router\RouteCollection;
/**
* @var RouteCollection $routes
*/
$routes->get('/', 'Home::index');
$routes->get('users', 'UserController::index');
$routes->post('search', 'UserController::filterData');
9 Folder Structure
10 Run Web Server to Test the App
php spark serve
Visit: http://localhost:8080/users
- The chart loads with the current year's data.
- Changing the year dropdown triggers AJAX to update the chart.
- If no data for a year, it shows an error (via API response).
- Added accessibility (e.g., esc() for output, ARIA could be added further).
- For production, use local assets instead of CDNs and enable CSRF.
- Extend with more features like multi-series or date pickers.
11 Conclusion
Written by Revathi M
PHP Developer & Technical Writer · 10+ years building web applications with CodeIgniter and Laravel
Revathi specializes in PHP backend development, authentication systems, and REST API design. She writes practical, production-tested tutorials at Get Sample Code to help developers build secure applications faster.
Frequently Asked Questions
You need CodeIgniter 4 installed, a working database (e.g., MySQL), basic knowledge of PHP, JavaScript, and AJAX. ApexCharts library should be included via CDN or downloaded assets.
Filters (e.g., year, month, or category dropdowns) trigger an AJAX request to a controller method, which queries the database, returns JSON data, and updates the chart using ApexCharts' updateSeries() or render() method.
Use chart.updateSeries(newData) or chart.updateOptions(newOptions) after fetching JSON from your CodeIgniter controller. Handle the AJAX success callback to pass the response data.
Create a sample table (e.g., for sales or user data with date/category columns). Use CodeIgniter's Query Builder in the model/controller to fetch filtered data based on user input.
Yes, ApexCharts supports line, bar, pie, area, etc. Configure the chart type in options and reuse the same filtering logic for dynamic updates across different charts.
Common issues: Incorrect AJAX URL/route, CSRF token mismatch in CodeIgniter, or errors in JSON response format. Check browser console for errors and ensure data is properly formatted for series/xaxis.
Limit queries with pagination or aggregation in the controller. Use ApexCharts options like dataLabels or toolbar for better performance on large data.
Yes, it works with current CodeIgniter 4 versions. Adjust routes or config if using newer features like namespaces or Sparks.
Yes, extend the form with date pickers and modify the controller query to use WHERE clauses for date ranges. Update the chart via AJAX as shown in the basic filter example.
