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.



Create Dynamic Charts with Filter Options in ApexCharts using CodeIgniter 4

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

Make sure Composer is installed, then run:

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

Rename the env file to .env and set the development mode in the .env file also configure mysql:

# 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

Create a migration file for the 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

For seeding test data in the users table, use the Seeder class:

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

Handle chart logic in 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

Create folder app/Views/users and add index.php:
    
   <!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

In app/Config/Routes.php:


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

Serve the project:

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

You've now built a fully dynamic, filterable chart in CodeIgniter 4 with ApexCharts! Extend it with more chart types, date range pickers, or multiple series.
Revathi M - PHP and CodeIgniter Developer

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.