rougin / gable
A simple HTML table generator in PHP.
Requires
- php: >=5.3.0
Requires (Dev)
This package is auto-updated.
Last update: 2026-05-16 16:13:19 UTC
README
A simple HTML table generator in PHP.
use Rougin\Gable\Table; $table = new Table; $table->newColumn(); $table->setCell('Name'); $table->setCell('Age'); $table->newRow(); $table->setCell('John Doe'); $table->setCell('30'); $table->newRow(); $table->setCell('Jane Doe'); $table->setCell('28');
Installation
Install the package using Composer:
$ composer require rougin/gable
Basic usage
Use the Table class for generating HTML tables:
// index.php use Rougin\Gable\Table; $table = new Table; // Define the table columns --- $table->newColumn(); $table->setCell('Name'); $table->setCell('Age'); // ---------------------------- // Populate the table with data --- $table->newRow(); $table->setCell('John Doe'); $table->setCell('30'); $table->newRow(); $table->setCell('Jane Doe'); $table->setCell('28'); // -------------------------------- echo $table->__toString();
The code above will generate the following HTML output:
<table> <thead> <tr> <th>Name</th> <th>Age</th> </tr> </thead> <tbody> <tr> <td>John Doe</td> <td>30</td> </tr> <tr> <td>Jane Doe</td> <td>28</td> </tr> </tbody> </table>
Method chaining
Using method chaining is recommended for a fluent and expressive way of building tables:
// index.php use Rougin\Gable\Table; $table = new Table; echo $table->newColumn() ->setCell('Name') ->setCell('Age') ->newRow() ->setCell('John Doe') ->setCell('30') ->newRow() ->setCell('Jane Doe') ->setCell('28');
Customization
The appearance of the table can be customized by adding CSS classes, inline styles, and other attributes to columns, rows, and cells:
// index.php use Rougin\Gable\Table; $table = new Table; // Adds CSS classes to the <table> element --- $table->setClass('table table-striped'); // ------------------------------------------ // Adds a CSS class to the <thead> row --- $table->newColumn('fw-bold'); // -------------------------------------- // Aligns to center then adds a CSS class to the cell --- $table->setCell('Name', 'center', 'text-uppercase'); // ------------------------------------------------------ // Aligns cell to the right ---- $table->setCell('Age', 'right'); // ----------------------------- // Adds a CSS class to the <tr> element --- $table->newRow('table-primary'); // ---------------------------------------- $table->setCell('John Doe'); $table->setCell('30'); $table->newRow(); // Adds a CSS class to the current cell -------- $table->setCell('Jane Doe', null, 'fst-italic'); // --------------------------------------------- $table->setCell('28'); echo $table;
<table class="table table-striped"> <thead> <tr class="fw-bold"> <th align="center" class="text-uppercase">Name</th> <th align="right">Age</th> </tr> </thead> <tbody> <tr class="table-primary"> <td>John Doe</td> <td>30</td> </tr> <tr> <td class="fst-italic">Jane Doe</td> <td>28</td> </tr> </tbody> </table>
Pagination
The Pagee class provides a simple way to generate pagination links for a table:
// index.php use Rougin\Gable\Pagee; $pagee = new Pagee; $pagee->setTotal(100); // Total number of items $pagee->setLimit(10); // Items per page $pagee->setPage(2); // Current page $pagee->setLink('/users'); // Base URL for the links echo $pagee;
<div class="d-inline-block"> <ul class="pagination"> <li class="page-item"> <a class="page-link" href="/users?p=1&l=10"> <span>First</span> </a> </li> <li class="page-item"> <a class="page-link" href="/users?p=1&l=10"> <span>Previous</span> </a> </li> <li class="page-item"> <a class="page-link" href="/users?p=1&l=10"> <span>1</span> </a> </li> <li class="page-item active"> <a class="page-link" href="javascript:void(0)"> <span>2</span> </a> </li> <li class="page-item"> <a class="page-link" href="/users?p=3&l=10"> <span>3</span> </a> </li> <li class="page-item"> <a class="page-link" href="/users?p=4&l=10"> <span>4</span> </a> </li> <li class="page-item"> <a class="page-link" href="/users?p=5&l=10"> <span>5</span> </a> </li> <li class="page-item"> <a class="page-link" href="/users?p=6&l=10"> <span>6</span> </a> </li> <li class="page-item"> <a class="page-link" href="/users?p=7&l=10"> <span>7</span> </a> </li> <li class="page-item"> <a class="page-link" href="/users?p=8&l=10"> <span>8</span> </a> </li> <li class="page-item"> <a class="page-link" href="/users?p=9&l=10"> <span>9</span> </a> </li> <li class="page-item"> <a class="page-link" href="/users?p=10&l=10"> <span>10</span> </a> </li> <li class="page-item"> <a class="page-link" href="/users?p=3&l=10"> <span>Next</span> </a> </li> <li class="page-item"> <a class="page-link" href="/users?p=10&l=10"> <span>Last</span> </a> </li> </ul> </div>
Using alpinejs
For creating dynamic and interactive tables, Gable provides a seamless integration with alpinejs. This allows for features like real-time data updates, loading indicators, and more:
// index.php use Rougin\Gable\Table; $table = new Table; // Sets the table with "users" for "alpinejs" --- $table->withAlpine('users'); // ---------------------------------------------- // Shows a loading indicator while data is being fetched --- $table->withLoading(); // --------------------------------------------------------- $table->newColumn(); $table->setCell('Name')->withName('name'); $table->setCell('Email')->withName('email'); echo $table;
This will generate a table that is bound to an alpinejs component, ready to display dynamic data:
<table> <thead> <tr> <th>Name</th> <th>Email</th> </tr> </thead> <tbody> <template x-if="items.length === 0 && loading"> <template x-data="{ length: items && items.length ? items.length : 5 }" x-for="i in length"> <tr> <td class="align-middle placeholder-glow"><span class="placeholder col-12"></span></td> <td class="align-middle placeholder-glow"><span class="placeholder col-12"></span></td> </tr> </template> </template> <template x-if="items.length === 0 && empty"> <tr> <td colspan="2" class="align-middle text-center"><span>No items found.</span></td> </tr> </template> <template x-if="! loading && loadError"> <tr> <td colspan="2" class="align-middle text-center"><span>An error occured in getting the items.</span></td> </tr> </template> <template x-if="items && items.length > 0"> <template x-for="item in users"> <tr> <td x-text="item.name"></td> <td x-text="item.email"></td> </tr> </template> </template> </tbody> </table>
Actions
Actions can be added to each row, allowing for operations like updating or deleting records. The withUpdateAction and withDeleteAction methods provide a convenient way to add the specified common actions:
// index.php use Rougin\Gable\Table; $table = new Table; $table->newColumn(); $table->setCell('Name'); $table->setCell('Age'); // Adds an "Action" column --- $table->withActions(); // --------------------------- $table->withUpdateAction('https://roug.in/update'); $table->withDeleteAction('https://roug.in/delete'); $table->newRow(); $table->setCell('John Doe'); $table->setCell('30'); $table->newRow(); $table->setCell('Jane Doe'); $table->setCell('28'); echo $table;
<table> <thead> <tr> <th>Name</th> <th>Age</th> <th>Action</th> </tr> </thead> <tbody> <tr> <td>John Doe</td> <td>30</td> <td> <div class="dropdown"> <button class="btn btn-primary btn-sm dropdown-toggle" type="button" data-bs-toggle="dropdown">Action</button> <div class="dropdown-menu dropdown-menu-end"> <div><a class="dropdown-item" href="https://roug.in/update">Update</a></div> <div><hr class="dropdown-divider"></div> <div><a class="dropdown-item text-danger" href="https://roug.in/delete">Delete</a></div> </div> </div> </td> </tr> <tr> <td>Jane Doe</td> <td>28</td> <td> <div class="dropdown"> <button class="btn btn-primary btn-sm dropdown-toggle" type="button" data-bs-toggle="dropdown">Action</button> <div class="dropdown-menu dropdown-menu-end"> <div><a class="dropdown-item" href="https://roug.in/update">Update</a></div> <div><hr class="dropdown-divider"></div> <div><a class="dropdown-item text-danger" href="https://roug.in/delete">Delete</a></div> </div> </div> </td> </tr> </tbody> </table>
If withAlpine is defined, each action is defined by @click attribute instead of href:
// index.php use Rougin\Gable\Table; $table = new Table; // Uses "alpinejs" to the table --- $table->withAlpine(); // -------------------------------- $table->newColumn(); $table->setCell('Name'); $table->setCell('Age'); // Adds an "Action" column --- $table->withActions(); // --------------------------- // Methods will be used instead of links --- $table->withUpdateAction('update(item.id)'); $table->withDeleteAction('delete(item.id)'); // ----------------------------------------- echo $table;
<table> <thead> <tr> <th>Name</th> <th>Age</th> <th>Action</th> </tr> </thead> <tbody> <template x-if="items && items.length > 0"> <template x-for="item in items"> <tr> <td x-text="item.name"></td> <td x-text="item.age"></td> <td> <div class="dropdown"> <button class="btn btn-primary btn-sm dropdown-toggle" type="button" data-bs-toggle="dropdown">Action</button> <div class="dropdown-menu dropdown-menu-end"> <div> <a class="dropdown-item" href="javascript:void(0)" @click="update(item.id)">Update</a> </div> <div> <hr class="dropdown-divider"> </div> <div> <a class="dropdown-item text-danger" href="javascript:void(0)" @click="delete(item.id)">Delete</a> </div> </div> </div> </td> </tr> </template> </template> </tbody> </table>
Badges
Badges can be used to highlight certain information in a cell, such as a record's status:
// index.php use Rougin\Gable\Table; $table = new Table; $table->newColumn(); // Set the entire cell for badges ------ $table->setCell('Status') ->addBadge('Active', 'bg-success') ->addBadge('Inactive', 'bg-danger'); // ------------------------------------- $table->setCell('Name'); $table->setCell('Age'); $table->newRow(); // Specify the name of the badge --- $table->useBadge('Active'); // --------------------------------- $table->setCell('John Doe'); $table->setCell('30'); $table->newRow(); $table->useBadge('Inactive'); $table->setCell('Jane Doe'); $table->setCell('28'); echo $table;
<table> <thead> <tr> <th>Name</th> <th>Age</th> <th>Action</th> </tr> </thead> <tbody> <tr> <td> <span class="badge rounded-pill text-uppercase bg-success">Active</span> </td> <td>John Doe</td> <td>30</td> </tr> <tr> <td> <span class="badge rounded-pill text-uppercase bg-danger">Inactive</span> </td> <td>Jane Doe</td> <td>28</td> </tr> </tbody> </table>
If withAlpine is defined, add a state in each badge in the third argument:
// index.php use Rougin\Gable\Table; $table = new Table; // Requires "alpinejs" to be enabled --- $table->withAlpine(); // ------------------------------------- $table->newColumn(); $table->setCell('Status') ->addBadge('Active', 'bg-success', "item.status === 'active'") ->addBadge('Inactive', 'bg-danger', "item.status === 'inactive'"); $table->setCell('Name'); $table->setCell('Age'); echo $table;
<table> <thead> <tr> <th>Status</th> <th>Name</th> <th>Age</th> </tr> </thead> <tbody> <template x-if="items && items.length > 0"> <template x-for="item in items"> <tr> <td> <template x-if="item.status === \'active\'"> <span class="badge rounded-pill text-uppercase bg-success">Active</span> </template> <template x-if="item.status === \'inactive\'"> <span class="badge rounded-pill text-uppercase bg-danger">Inactive</span> </template> </td> <td x-text="item.name"></td> <td x-text="item.age"></td> </tr> </template> </template> </tbody> </table>
Available methods
The following methods are available in the Table class:
/** * Adds a one-line custom HTML to the last added cell. * * @param string $html * * @return self */ public function addHtml($html)
/** * Adds a new "<tr>" element to the "<thead>". * * @param string|null $class * @param string|null $style * @param integer|null $width * * @return self */ public function newColumn($class = null, $style = null, $width = null)
/** * Adds a new "<tr>" element to the "<tbody>". * * @param string|null $class * @param string|null $style * @param integer|null $width * * @return self */ public function newRow($class = null, $style = null, $width = null)
/** * Adds a new "<td>" element. * * @param mixed|null $value * @param string|null $align * @param string|null $class * @param integer|null $cspan * @param integer|null $rspan * @param string|null $style * @param integer|null $width * * @return self */ public function setCell($value, $align = null, $class = null, $cspan = null, $rspan = null, $style = null, $width = null)
/** * Adds a column for action buttons. * * @param mixed|null $value * @param string|null $align * @param string|null $class * @param integer|null $cspan * @param integer|null $rspan * @param string|null $style * @param integer|null $width * * @return self */ public function withActions($value = 'Action', $align = null, $class = null, $cspan = null, $rspan = null, $style = null, $width = null)
/** * Enables usage of "alpine.js" in the table. * * @param string $name * @param string|null $class * @param string|null $style * @param integer|null $width * * @return self */ public function withAlpine($name = 'items', $class = null, $style = null, $width = null)
/** * Adds a "Delete" action button. * * @param string $action * @param string $name * * @return self */ public function withDeleteAction($action, $name = 'Delete')
/** * Adds a loading indicator to the table. * * @param integer $count * @param string $name * * @return self */ public function withLoading($count = 5, $name = 'loading')
/** * Adds an "Update" action button. * * @param string $action * @param string $name * * @return self */ public function withUpdateAction($action, $name = 'Update')
/** * Sets the text to display when there are no items in the table. * * @param string $text * @param string $key * * @return self */ public function withEmptyText($text, $key = 'empty')
/** * Sets the text to display when an error occurs while loading items. * * @param string $text * @param string $key * * @return self */ public function withErrorText($text, $key = 'loadError')
/** * Sets a name identifier to the last column cell. * * @param string $name * * @return self */ public function withName($name)
Styling per cell
The following fluent methods set attributes on the last added cell. They work for both column headers (<th>) and row cells (<td>):
$table = new Table; $table->newColumn(); $table->setCell('Name') ->withAlign('center') ->withClass('text-uppercase') ->withWidth(30); $table->newRow(); $table->setCell('John Doe') ->withStyle('color: red'); echo $table;
See the following methods that are available for styling:
/** * Sets the alignment of the last cell. * * @param string $align * * @return self */ public function withAlign($align)
/** * Sets the CSS class of the last cell. * * @param string $class * * @return self */ public function withClass($class)
/** * Sets the colspan of the last cell. * * @param integer $cspan * * @return self */ public function withCspan($cspan)
/** * Sets the rowspan of the last cell. * * @param integer $rspan * * @return self */ public function withRspan($rspan)
/** * Sets the inline CSS style of the last cell. * * @param string $style * * @return self */ public function withStyle($style)
/** * Sets the width of the last cell in percentage. * * @param integer $width * * @return self */ public function withWidth($width)
Restyling table
The default styling uses Bootstrap 5 classes. To use a different CSS framework, implement the StyleInterface and pass it to the table or any of its components:
namespace Rougin\Test\Styles; use Rougin\Gable\StyleInterface; class TailwindStyle implements StyleInterface { public function badge() { return 'inline-flex items-center rounded-md px-2 py-1 text-xs font-medium ring-1 ring-inset'; } public function dropdown() { return 'relative inline-block text-left'; } public function dropdownButton() { return 'inline-flex w-full justify-center gap-x-1.5 rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50'; } public function dropdownDanger() { return 'text-red-600'; } public function dropdownDivider() { return 'divide-y divide-gray-100'; } public function dropdownItem() { return 'block px-4 py-2 text-sm text-gray-700'; } public function dropdownMenu() { return 'absolute right-0 z-10 mt-2 w-56 origin-top-right rounded-md bg-white shadow-lg ring-1 ring-black ring-opacity-5'; } public function emptyCell() { return 'px-3 py-4 text-center text-sm text-gray-500'; } public function loadingCell() { return 'px-3 py-4 animate-pulse'; } public function loadingSpan() { return 'block h-4 w-full rounded bg-gray-200'; } public function paginationActive() { return 'bg-indigo-600 text-white'; } public function paginationDisabled() { return 'text-gray-400 cursor-not-allowed'; } public function paginationItem() { return 'relative inline-flex items-center px-4 py-2 text-sm font-semibold text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50'; } public function paginationLink() { return 'block'; } public function paginationList() { return 'isolate inline-flex -space-x-px rounded-md shadow-sm'; } public function paginationWrapper() { return 'flex items-center justify-center'; } }
use Rougin\Gable\Pagee; use Rougin\Gable\Table; use Rougin\Test\Styles\TailwindStyle; $table = new Table; // Apply the custom style to a table --- $table->useStyle(new TailwindStyle); // ------------------------------------- // Or apply to a specified element --- $pagee = new Pagee; $pagee->useStyle(new TailwindStyle); // -----------------------------------
Changelog
Please see CHANGELOG for more recent changes.
Contributing
See CONTRIBUTING on how to contribute.
License
The MIT License (MIT). Please see LICENSE for more information.