drago-ex/datagrid

A simple datagrid for sorting and filtering data.

Maintainers

Package info

github.com/drago-ex/datagrid

pkg:composer/drago-ex/datagrid

Statistics

Installs: 174

Dependents: 1

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.0 2026-06-07 08:59 UTC

This package is auto-updated.

Last update: 2026-06-07 14:20:44 UTC


README

Drago DataGrid is a Nette component for rendering Bootstrap 5 tables with filtering, sorting, pagination and row actions.

License: MIT PHP version Coding Style

Requirements

  • PHP >= 8.3
  • Nette Framework
  • Dibi
  • Latte
  • Bootstrap 5
  • Naja

Installation

composer require drago-ex/datagrid

Frontend Assets

Add the Composer package as a local npm dependency:

{
  "type": "module",
  "dependencies": {
    "drago-datagrid": "file:vendor/drago-ex/datagrid"
  }
}

Install dependencies:

npm install

Import the assets:

import naja from 'naja';
import DataGrid from 'drago-datagrid';
import 'drago-datagrid/styles/datagrid';

naja.initialize();
new DataGrid().initialize(naja);

Basic Usage

use Dibi\Connection;
use Drago\Datagrid\DataGrid;
use Nette\Application\UI\Presenter;

final class ProductPresenter extends Presenter
{
	public function __construct(
		private readonly Connection $db,
	) {
	}

	protected function createComponentGrid(): DataGrid
	{
		$grid = new DataGrid;
		$grid->setDataSource(
			$this->db->select('*')->from('products')
		);

		$grid->addColumnText('name', 'Name')->setFilterText();
		$grid->addColumnText('status', 'Status')->setFilterSelect([
			'active' => 'Active',
			'inactive' => 'Inactive',
		]);
		$grid->addColumnDate('created_at', 'Created', format: 'd.m.Y')->setFilterDate();

		return $grid;
	}
}

Render the component in Latte:

{control grid}

Data Source

The grid expects a Dibi\Fluent data source. Filtering, sorting and pagination are applied to a cloned query during rendering.

$grid->setDataSource(
	$this->db->select('*')->from('products')->orderBy('id DESC')
);

A default orderBy() can be used for the initial render. When the user clicks a sortable column, the grid replaces the default order with the selected grid sort.

Columns

$grid->addColumnText('name', 'Product Name');
$grid->addColumnText('sku', 'SKU', sortable: false);
$grid->addColumnDate('updated_at', 'Updated', format: 'd.m.Y');

Column arguments:

  • name - database column name
  • label - column label
  • sortable - enables header sorting, default is true
  • formatter - optional callback for rendering cell values

Natural numeric sorting can be enabled on text columns:

$grid->addColumnText('code', 'Code')->setNaturalSort();

Column text alignment can be changed with Bootstrap alignment helpers:

$grid->addColumnText('id', 'ID')->alignRight();
$grid->addColumnText('status', 'Status')->alignCenter();
$grid->addColumnText('name', 'Name')->alignLeft();

Alignment affects only table rendering. It does not validate or convert the column value.

Filters

$grid->addColumnText('name', 'Name')->setFilterText();

$grid->addColumnText('status', 'Status')->setFilterSelect([
	'active' => 'Active',
	'inactive' => 'Inactive',
]);

$grid->addColumnDate('created_at', 'Created')->setFilterDate();

Filter types:

  • setFilterText() - LIKE search
  • setFilterSelect(array $items) - exact match select
  • setFilterDate() - date filter in YYYY-MM-DD format

Date filters also support range values in the form YYYY-MM-DD|YYYY-MM-DD.

Active filters can be cleared individually with the small clear button next to the filter input. The reset button clears all filters at once.

Filter Modes

Filters can be rendered in two modes:

$grid->setFilterMode('top');

top is the default mode. Filters are displayed in a toolbar above the table.

$grid->setFilterMode('inline');

inline displays filters in a second table header row under the related columns.

Both modes use the same filter definitions and AJAX behavior.

Row Actions

Set the primary key before adding actions:

$grid->setPrimaryKey('id');

Add action callbacks:

$grid->addAction('Edit', 'edit!', 'ajax btn btn-sm btn-primary', function (int $id): void {
	$this->redirect('edit', $id);
});

$grid->addAction('Delete', 'delete!', 'ajax btn btn-sm btn-danger', function (int $id): void {
	// Delete row
});

Actions can be shown or hidden per row:

$grid->addAction(
	'Activate',
	'activate!',
	'ajax btn btn-sm btn-success',
	callback: fn(int $id) => $this->activate($id),
	condition: fn(array $row): bool => !$row['active'],
);

The condition callback receives the current row as array<string, mixed>.

Row Click

The whole row can trigger an action:

$grid->setPrimaryKey('id');
$grid->setRowClickAction('edit!');

$grid->addAction('Edit', 'edit!', 'ajax btn btn-sm btn-primary', function (int $id): void {
	$this->redirect('edit', $id);
});

If the action signal matches setRowClickAction(), the action button is hidden and only the row click is used.

Action Display

Show row actions only on hover:

$grid->setAutoHideActions();

Actions with signals edit! and delete! are displayed after other custom actions.

Formatting Values

Simple values are escaped automatically:

$grid->addColumnText('price', 'Price', formatter: function (mixed $value, array $row): string {
	return number_format((float) $value, 2) . ' CZK';
});

Return Nette\Utils\Html when you want to render HTML:

use Nette\Utils\Html;

$grid->addColumnText('status', 'Status', formatter: function (mixed $value, array $row): Html {
	return Html::el('span')
		->class($value === 'active' ? 'badge bg-success' : 'badge bg-secondary')
		->setText((string) $value);
});

Localization

The grid supports Nette\Localization\Translator:

$grid->setTranslator($this->translator);

Translated values include column labels, action labels, filter labels, reset button and pagination text.

AJAX

The grid is built for Naja. Filtering, sorting, pagination, page size changes and row actions are handled through AJAX and keep browser history updated.

Text filters are submitted by pressing Enter. Select and date filters are submitted automatically when their value changes.

Security

  • Cell values are escaped unless a formatter returns Nette\Utils\Html.
  • Filters use parameterized Dibi queries.
  • Sort direction is normalized to ASC or DESC before it is applied to SQL.
  • Empty filter values are removed from persistent parameters.