Type to search columns, filters, options, and extensions.

to navigate · Enter to open · Esc to close

Documentation

Quick Start

Create your first DataTable in 5 minutes

Let’s create a simple users table in under 5 minutes.

    1. Create the Table Class

      // src/DataTables/UsersDataTable.php
      namespace App\DataTables;
      
      use Pentiminax\UX\DataTables\Column\NumberColumn;
      use Pentiminax\UX\DataTables\Column\TextColumn;
      use Pentiminax\UX\DataTables\Model\AbstractDataTable;
      use Pentiminax\UX\DataTables\Model\DataTable;
      
      final class UsersDataTable extends AbstractDataTable
      {
          public function configureColumns(): iterable
          {
              yield NumberColumn::new('id', 'ID');
              yield TextColumn::new('firstName', 'First Name');
              yield TextColumn::new('lastName', 'Last Name');
              yield TextColumn::new('email', 'Email');
          }
      
          public function configureDataTable(DataTable $table): DataTable
          {
              return $table
                  ->data([
                      ['id' => 1, 'firstName' => 'John', 'lastName' => 'Doe', 'email' => 'john@example.com'],
                      ['id' => 2, 'firstName' => 'Jane', 'lastName' => 'Smith', 'email' => 'jane@example.com'],
                      ['id' => 3, 'firstName' => 'Bob', 'lastName' => 'Wilson', 'email' => 'bob@example.com'],
                  ])
                  ->pageLength(10)
                  ->searching(true)
                  ->ordering(handler: true, indicators: true);
          }
      }

      Table classes are autoconfigured services, so there is nothing to register manually.

    2. Create the Controller

      // src/Controller/UserController.php
      namespace App\Controller;
      
      use App\DataTables\UsersDataTable;
      use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
      use Symfony\Component\HttpFoundation\Response;
      use Symfony\Component\Routing\Attribute\Route;
      
      class UserController extends AbstractController
      {
          #[Route('/users', name: 'app_users')]
          public function index(UsersDataTable $table): Response
          {
              return $this->render('user/index.html.twig', [
                  'table' => $table,
              ]);
          }
      }
    3. Create the Twig Template

      {# templates/user/index.html.twig #}
      {% extends 'base.html.twig' %}
      
      {% block title %}Users{% endblock %}
      
      {% block body %}
          <div class="container mt-4">
              <h1>Users</h1>
      
              {{ render_datatable(table) }}
      
              {# Or with custom attributes #}
              {{ render_datatable(table, {'class': 'table table-striped'}) }}
          </div>
      {% endblock %}
    4. Visit the Page

      Navigate to /users in your browser. You should see a fully functional DataTable with:

      • Pagination
      • Search box
      • Column sorting
      • Page length selector

Adding More Features

Enable Extensions

use Pentiminax\UX\DataTables\Enum\ButtonType;
use Pentiminax\UX\DataTables\Model\Extensions\ButtonsExtension;
use Pentiminax\UX\DataTables\Model\Extensions\SelectExtension;
use Pentiminax\UX\DataTables\Enum\SelectStyle;

public function configureDataTable(DataTable $table): DataTable
{
    return $table
        ->data([/* ... */])
        ->extensions([
            new ButtonsExtension([
                ButtonType::COPY,
                ButtonType::CSV,
                ButtonType::EXCEL,
            ]),
            new SelectExtension(SelectStyle::SINGLE),
        ]);
}

Load Data via Ajax

public function configureDataTable(DataTable $table): DataTable
{
    return $table
        ->ajax('/api/users')
        ->serverSide()
        ->processing();
}

Customize Column Behavior

use Pentiminax\UX\DataTables\Column\EmailColumn;
use Pentiminax\UX\DataTables\Column\TextColumn;

$nameColumn = TextColumn::new('name', 'Name')
    ->setClassName('fw-bold')
    ->setOrderable(true)
    ->setSearchable(true)
    ->setWidth('200px');

$emailColumn = EmailColumn::new('email', 'Email')
    ->setOrderable(true);

Doctrine-Backed Tables

Add the #[AsDataTable] attribute to let the bundle query your entity and map its rows:

// src/DataTables/UsersDataTable.php
namespace App\DataTables;

use App\Entity\User;
use Pentiminax\UX\DataTables\Attribute\AsDataTable;
use Pentiminax\UX\DataTables\Model\AbstractDataTable;
use Pentiminax\UX\DataTables\Column\TextColumn;
use Pentiminax\UX\DataTables\Column\NumberColumn;

#[AsDataTable(User::class)]
final class UsersDataTable extends AbstractDataTable
{
    public function configureColumns(): iterable
    {
        yield NumberColumn::new('id', 'ID');
        yield TextColumn::new('firstName', 'First Name');
        yield TextColumn::new('lastName', 'Last Name');
        yield TextColumn::new('email', 'Email');
    }

    protected function mapRow(mixed $row): array
    {
        /** @var User $row */
        return [
            'id' => $row->getId(),
            'firstName' => $row->getFirstName(),
            'lastName' => $row->getLastName(),
            'email' => $row->getEmail(),
        ];
    }
}

Then in your controller:

#[Route('/users', name: 'app_users')]
public function index(UsersDataTable $table, Request $request): Response
{
    $table->handleRequest($request);

    if ($table->isRequestHandled()) {
        return $table->getResponse();
    }

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