DEV Community

Cover image for UX DataTables, a Symfony bundle integrating the DataTables library in Symfony applications.
Pentiminax
Pentiminax

Posted on

UX DataTables, a Symfony bundle integrating the DataTables library in Symfony applications.

Managing dynamic tables in Symfony applications can be challenging, especially when dealing with large datasets, server-side processing, and rich UI interactions. UX DataTables is a Symfony UX library that seamlessly integrates the popular DataTables.js plugin into your PHP applications, providing a powerful, declarative, and extensible way to build interactive tables.

🧩 What Is UX DataTables?

UX DataTables bridges the gap between Symfony and DataTables.js, allowing developers to define tables, columns, and behaviors entirely in PHP while leveraging Symfony’s templating and Stimulus controllers.

Key Features:
• Fully configurable tables via PHP classes
• Ajax support for dynamic data loading
• Server-side processing for large datasets
• Column-level customization (sorting, searching, visibility)
• Support for DataTables extensions like Buttons and Select
• Integration with Stimulus for frontend customization

🚀 Installation

First, ensure you have Symfony’s StimulusBundle configured.

Install the UX DataTables bundle using Composer:

composer require pentiminax/ux-datatables

If you’re using Webpack Encore, install your assets and start the watcher:

npm install --force
npm run watch

🛠️ Defining a Table in PHP

Creating a table is straightforward.
Inject the DataTableBuilderInterface and define your table:

use Pentiminax\UX\DataTables\Builder\DataTableBuilderInterface;
use Pentiminax\UX\DataTables\Model\Column;

class HomeController extends AbstractController
{
    #[Route('/', name: 'app_homepage')]
    public function index(DataTableBuilderInterface $builder): Response
    {
        $table = $builder
            ->createDataTable('usersTable')
            ->columns([
                Column::new('firstName', 'First Name'),
                Column::new('lastName', 'Last Name'),
            ])
            ->data([
                ['John', 'Doe'],
                ['Jane', 'Smith'],
            ]);

        return $this->render('home/index.html.twig', [
            'table' => $table,
        ]);
    }
}

Then, render the table in your Twig template:

{{ render_datatable(table) }}

🔄 Loading Data via Ajax

For large datasets, you can load data asynchronously using Ajax:

use Pentiminax\UX\DataTables\Model\Options\AjaxOption;

$ajaxOption = new AjaxOption(
    url: '/api/data',
    dataSrc: 'data',
    type: 'POST'
);

$dataTable->ajax($ajaxOption);

Ensure your API returns a JSON response in the following format:

{
    "data": [
        { "id": 1, "name": "Product A", "price": 10.5 },
        { "id": 2, "name": "Product B", "price": 20.0 }
    ],
    "recordsTotal": 100,
    "recordsFiltered": 100
}

To assist with this, use the DataTableResponseBuilder:

use Pentiminax\UX\DataTables\Builder\DataTableResponseBuilder;

$responseBuilder = new DataTableResponseBuilder();

$response = $responseBuilder->buildResponse(
    draw: 1,
    data: $data,
    recordsTotal: $totalRecords,
    recordsFiltered: $filteredRecords
);

return $response;

🧩 Extending with DataTables Extensions

UX DataTables supports various DataTables extensions. For example, to add export buttons:

use Pentiminax\UX\DataTables\Extension\ButtonsExtension;
use Pentiminax\UX\DataTables\Enum\ButtonType;

$buttonsExtension = new ButtonsExtension([
    ButtonType::COPY,
    ButtonType::CSV,
    ButtonType::EXCEL,
    ButtonType::PDF,
    ButtonType::PRINT
]);

$dataTable->addExtension($buttonsExtension);

For row selection capabilities:

use Pentiminax\UX\DataTables\Extension\SelectExtension;
use Pentiminax\UX\DataTables\Enum\SelectStyle;

$selectExtension = new SelectExtension(SelectStyle::MULTI);
$dataTable->extensions([$selectExtension]);

🎛️ Configuring Defaults

Set global defaults in config/packages/datatables.yaml:

data_tables:
  options:
    language: en-GB
    lengthMenu: [10, 25, 50]
    pageLength: 10
  template_parameters:
    class: 'table'
  extensions:
    buttons: [csv, excel, pdf, print]
    select:
      style: single

🎨 Customizing with Stimulus

// mytable_controller.js

import { Controller } from '@hotwired/stimulus';

export default class extends Controller {
    connect() {
        this.element.addEventListener('datatables:pre-connect', this._onPreConnect);
        this.element.addEventListener('datatables:connect', this._onConnect);
    }

    disconnect() {
        // You should always remove listeners when the controller is disconnected to avoid side effects
        this.element.removeEventListener('datatables:pre-connect', this._onPreConnect);
        this.element.removeEventListener('datatables:connect', this._onConnect);
    }

    _onPreConnect(event) {
        // The table is not yet created
        // You can access the config that will be passed to "new DataTable()"
        console.log(event.detail.config);

        // For instance you can define a render callback for a given column
        event.detail.config.columns[0].render = function (data, type, row, meta) {
            return '<a href="' + data + '">Download</a>';
        }
    }

    _onConnect(event) {
        // The table was just created
        console.log(event.detail.table); // You can access the table instance using the event details

        // For instance you can listen to additional events
        event.detail.table.on('init', (event) => {
            /* ... */
        };
        event.detail.table.on('draw', (event) => {
            /* ... */
        };
    }
}

🙌 Thanks for Reading!

Thank you for taking the time to read this article!

UX DataTables is still evolving, and contributions are more than welcome — whether it's fixing bugs, suggesting new features, or simply sharing your feedback.

🔗 Check out the project on GitHub: https://github.com/pentiminax/ux-datatables

If you find the project helpful, consider giving it a ⭐.
Feel free to open an issue or submit a pull request to contribute.

Happy DataTabling with Symfony! 🚀

Top comments (0)