Marta Ruiz
Product Designer
Email: marta.ruiz@example.com
Phone: +34 600 111 222
Angular data table and paginated list with server-side pagination, sorting, filtering, selection, templates and CSS variables.
Last updated Aug 24, 2026
Use this Angular data table and paginated list library when you need server-side operations, selection, filtering and reusable list rendering without rebuilding table logic in every project.
npm install ng-hub-ui-paginableng-hub-ui-paginable is aimed at Angular teams building admin panels, search results, CRM screens and management back offices. It combines a reusable table and list layer with the operations that usually matter most in production: pagination, filtering, sorting, selection and custom templates.
Fundamental table rendering and pagination.
Basic Table Usage
ID | Name | Email | Role |
|---|---|---|---|
| 1 | John Doe | john@example.com | Admin |
| 2 | Jane Smith | jane@example.com | Editor |
| 3 | Bob Johnson | bob@example.com | User |
| 4 | Alice Brown | alice@example.com | Editor |
Agnostic Form Controls
ID | Name | Email | Role | Department |
|---|---|---|---|---|
| 1 | John Doe | john.doe@example.com | Admin | IT |
| 2 | Jane Smith | jane.smith@example.com | Editor | Marketing |
| 3 | Bob Johnson | bob.johnson@example.com | User | Sales |
| 4 | Alice Brown | alice.brown@example.com | Editor | IT |
| 5 | Charlie Wilson | charlie.wilson@example.com | User | HR |
Search and rows-per-page are rendered by ng-hub-ui-forms (hub-input / hub-select). Remove the provider and they fall back to native controls.
Table Pagination
ID | Name | Department | Position | Salary | Email |
|---|---|---|---|---|---|
| 1 | John Doe | Engineering | Senior Developer | 85000 | john.doe@company.com |
| 2 | Jane Smith | Marketing | Marketing Manager | 72000 | jane.smith@company.com |
| 3 | Bob Johnson | Engineering | Frontend Developer | 65000 | bob.johnson@company.com |
| 4 | Alice Brown | HR | HR Specialist | 58000 | alice.brown@company.com |
| 5 | Charlie Wilson | Sales | Sales Representative | 55000 | charlie.wilson@company.com |
Table CSS Variables
ID | Name | Email | Role |
|---|---|---|---|
| 1 | John Doe | john@example.com | Admin |
| 2 | Jane Smith | jane@example.com | Editor |
| 3 | Bob Johnson | bob@example.com | User |
| 4 | Alice Brown | alice@example.com | Reviewer |
ID | Name | Email | Role |
|---|---|---|---|
| 1 | John Doe | john@example.com | Admin |
| 2 | Jane Smith | jane@example.com | Editor |
| 3 | Bob Johnson | bob@example.com | User |
| 4 | Alice Brown | alice@example.com | Reviewer |
Sorting, filtering, selection and server-side operations.
Basic Sorting & Filtering
ID | Name | Role | Status |
|---|---|---|---|
| 4 | Alice Brown | Editor | Active |
| 3 | Bob Johnson | User | Pending |
| 5 | Charlie Wilson | User | Deleted |
| 2 | Jane Smith | Editor | Inactive |
| 1 | John Doe | Admin | Active |
Advanced Filtering (Menus & Ranges)
ID | Product | Price ($) | Added Date | Category |
|---|---|---|---|---|
| 1 | Laptop | 1200 | Sun Oct 01 2023 00:00:00 GMT+0000 (Coordinated Universal Time) | Electronics |
| 2 | Mouse | 25 | Wed Nov 15 2023 00:00:00 GMT+0000 (Coordinated Universal Time) | Electronics |
| 3 | Keyboard | 75 | Mon Nov 20 2023 00:00:00 GMT+0000 (Coordinated Universal Time) | Electronics |
| 4 | Desk Lamp | 45 | Tue Dec 05 2023 00:00:00 GMT+0000 (Coordinated Universal Time) | Office |
| 5 | Chair | 250 | Sun Dec 10 2023 00:00:00 GMT+0000 (Coordinated Universal Time) | Office |
Selection & Batch Actions
ID | Name | Email | Role | |
|---|---|---|---|---|
| 1 | John Doe | john@example.com | Admin | |
| 2 | Jane Smith | jane@example.com | Editor | |
| 3 | Bob Johnson | bob@example.com | User | |
| 4 | Alice Brown | alice@example.com | Editor | |
| 5 | Charlie Wilson | charlie@example.com | User |
Batch Actions (batchActions)
ID | Name | Email | Status | |
|---|---|---|---|---|
| 1 | John Doe | john.doe@example.com | Active | |
| 2 | Jane Smith | jane.smith@example.com | Active | |
| 3 | Bob Johnson | bob.johnson@example.com | Inactive | |
| 4 | Alice Brown | alice.brown@example.com | Active | |
| 5 | Charlie Wilson | charlie.wilson@example.com | Inactive |
Server-Side Operations
ID | Name | Email | Role | Status |
|---|---|---|---|---|
| 1 | John Doe | user1@example.com | Admin | Active |
| 2 | Jane Smith | user2@example.com | Editor | Inactive |
| 3 | Bob Johnson | user3@example.com | User | Pending |
| 4 | Alice Brown | user4@example.com | Moderator | Active |
| 5 | Charlie Wilson | user5@example.com | Admin | Inactive |
| 6 | Diana Martinez | user6@example.com | Editor | Pending |
| 7 | Edward Taylor | user7@example.com | User | Active |
| 8 | Fiona Anderson | user8@example.com | Moderator | Inactive |
| 9 | George Lee | user9@example.com | Admin | Pending |
| 10 | Hannah White | user10@example.com | Editor | Active |
Expandable rows, custom templates, responsive layout and dynamic styling.
Expandable Rows & Sticky Columns
ID | Name | Role | Email | Actions | |
|---|---|---|---|---|---|
| 1 | John Doe | Admin | john@example.com | ||
| 2 | Jane Smith | Editor | jane@example.com | ||
| 3 | Bob Johnson | User | bob@example.com | ||
| 4 | Alice Brown | Editor | alice@example.com |
Multiple sticky columns
ID | Full Name | Email Address | Department | Position | Office Location | Salary | Status |
|---|---|---|---|---|---|---|---|
| 1 | John Doe | john.doe@example.com | Engineering | Senior Developer | New York | $120,000 | Active |
| 2 | Jane Smith | jane.smith@example.com | Marketing | Marketing Manager | Los Angeles | $95,000 | Active |
| 3 | Bob Johnson | bob.johnson@example.com | Sales | Sales Representative | Chicago | $75,000 | On leave |
| 4 | Alice Brown | alice.brown@example.com | Engineering | Technical Lead | San Francisco | $140,000 | Active |
| 5 | Charlie Wilson | charlie.wilson@example.com | HR | HR Specialist | Boston | $65,000 | Active |
Themeable header & divider
Invoice | Client | Amount | Status |
|---|---|---|---|
| INV-1001 | Acme Corp | $3,200 | Paid |
| INV-1002 | Globex | $1,750 | Pending |
| INV-1003 | Initech | $980 | Paid |
| INV-1004 | Umbrella | $5,410 | Overdue |
Sticky header on scroll
[stickyHeader] inside a plain scroll div, the second via the built-in options.scrollable frame. [stickyHeader] (any scroll container)ID | Name | Department | Location | Status |
|---|---|---|---|---|
| 1 | Employee 1 | Engineering | New York | On leave |
| 2 | Employee 2 | Marketing | London | Active |
| 3 | Employee 3 | Sales | Berlin | Active |
| 4 | Employee 4 | HR | Tokyo | Active |
| 5 | Employee 5 | Engineering | New York | Active |
| 6 | Employee 6 | Marketing | London | On leave |
| 7 | Employee 7 | Sales | Berlin | Active |
| 8 | Employee 8 | HR | Tokyo | Active |
| 9 | Employee 9 | Engineering | New York | Active |
| 10 | Employee 10 | Marketing | London | Active |
options.scrollable (built-in frame)ID | Name | Department | Location | Status |
|---|---|---|---|---|
| 1 | Employee 1 | Engineering | New York | On leave |
| 2 | Employee 2 | Marketing | London | Active |
| 3 | Employee 3 | Sales | Berlin | Active |
| 4 | Employee 4 | HR | Tokyo | Active |
| 5 | Employee 5 | Engineering | New York | Active |
| 6 | Employee 6 | Marketing | London | On leave |
| 7 | Employee 7 | Sales | Berlin | Active |
| 8 | Employee 8 | HR | Tokyo | Active |
| 9 | Employee 9 | Engineering | New York | Active |
| 10 | Employee 10 | Marketing | London | Active |
Dark re-theming by tag selector
hub-table tag selector — no!important. ID | Name | Email | Role |
|---|---|---|---|
| 1 | John Doe | john@example.com | Admin |
| 2 | Jane Smith | jane@example.com | Editor |
| 3 | Bob Johnson | bob@example.com | User |
| 4 | Alice Brown | alice@example.com | Reviewer |
Overridable expander icons
--hub-table-icon-caret-up / --hub-table-icon-caret-down. Product | SKU | Price | Stock | |
|---|---|---|---|---|
| Wireless Mouse | WM-100 | $24.99 | 132 | |
| Mechanical Keyboard | MK-220 | $89.00 | 47 | |
| USB-C Hub | UH-330 | $39.50 | 88 |
Custom icon set
--hub-table-icon-* variable. One-call theming (mixins)
Code | Name | Owner | |
|---|---|---|---|
| A-01 | Alpha | Ada | |
| B-02 | Bravo | Alan | |
| C-03 | Charlie | Grace |
Template Customization
ID | Name | Role | Status |
|---|---|---|---|
| 1 | John Doe | Admin | Active |
| 2 | Jane Smith | Editor | Active |
| 3 | Bob Johnson | User | Inactive |
Responsive Layout & States
ID | Name | Role |
|---|---|---|
| 1 | John Doe | Admin |
| 2 | Jane Smith | Editor |
Default State Components
ID | Name | Role |
|---|---|---|
| 1 | John Doe | Admin |
| 2 | Jane Smith | Editor |
| 3 | Bob Johnson | User |
Dynamic Row Styles (rowClass)
ID | Name | Email | Role | Status |
|---|---|---|---|---|
| 1 | John Doe | john.doe@example.com | Admin | active |
| 2 | Jane Smith | jane.smith@example.com | Editor | inactive |
| 3 | Bob Johnson | bob.johnson@example.com | User | pending |
| 4 | Alice Brown | alice.brown@example.com | Editor | active |
| 5 | Charlie Wilson | charlie.wilson@example.com | User | deleted |
Master-detail selection (rowClass)
Order | Customer | Total | Status |
|---|---|---|---|
| 1001 | Ada Lovelace | $1,240.00 | Paid |
| 1002 | Alan Turing | $890.50 | Pending |
| 1003 | Grace Hopper | $2,415.00 | Paid |
| 1004 | Katherine Johnson | $540.75 | Refunded |
| 1005 | Edsger Dijkstra | $1,975.20 | Paid |
Click a row to open its detail — the active row shows the tint + accent bar.
Select an order to see its detail.
Internationalization (i18n)
ID | Name | Email | Role |
|---|---|---|---|
| 1 | John Doe | john@example.com | Admin |
| 2 | Jane Smith | jane@example.com | Editor |
| 3 | Bob Johnson | bob@example.com | User |
| 4 | Alice Brown | alice@example.com | Moderator |
| 5 | Charlie Wilson | charlie@example.com | Admin |
| 6 | Diana Martinez | diana@example.com | Editor |
| 7 | Edward Taylor | edward@example.com | User |
| 8 | Fiona Anderson | fiona@example.com | Moderator |
| 9 | George Lee | george@example.com | Admin |
| 10 | Hannah White | hannah@example.com | Editor |
| 11 | Ivan Clark | ivan@example.com | User |
| 12 | Julia Scott | julia@example.com | Moderator |
RTL Layout (right-to-left)
ID | Name | Email | Role | |
|---|---|---|---|---|
| 1 | John Doe | john@example.com | Admin | |
| 2 | Jane Smith | jane@example.com | Editor | |
| 3 | Bob Johnson | bob@example.com | User | |
| 4 | Alice Brown | alice@example.com | Reviewer |
Footer Bar Order (CSS variables)
ID | Name | Role |
|---|---|---|
| 1 | John Doe | Admin |
| 2 | Jane Smith | Editor |
| 3 | Bob Johnson | User |
Flexible list views with the same powerful pagination and selection capabilities.
Pageable & Selectable List
Connected list (timeline)
Selectable list
pointer cursor; tick the checkbox to select. []nullFlush — a list, not a stack of cards
Each row is its own surface. On a page, that is what separates it from the page.
Inside a dialog the frame is already drawn, so the rows only need a rule between them.
Outer border, radius and head rule go; the row divider and the cell padding stay, because those are what keep a table readable across its columns.
Room | Kind | Rate |
|---|---|---|
| Despacho 1 | Office | from 900,00 € / month |
| Sala Timple | Meeting room | from 90,00 € / day |
| Zona compartida | Coworking | from 180,00 € / month |
Editable — controls drawn as a sheet
Product | Quantity | Unit |
|---|---|---|
u. | box | |
u. | box | |
u. | kg |
flushFields — the same controls, read as a sheetProduct | Quantity | Unit |
|---|---|---|
u. | box | |
u. | box | |
u. | kg |
Selecting a tree, and what a click hands over
[](none yet)List CSS Variables
hub-list-theme() mixinCard List
Product Designer
Email: marta.ruiz@example.com
Phone: +34 600 111 222
Frontend Engineer
Email: carlos.vega@example.com
Phone: +34 600 333 444
Engineering Manager
Email: lucia.moreno@example.com
Phone: +34 600 555 666
QA Lead
Email: pablo.serra@example.com
Phone: +34 600 777 888
Nested Lists
List Loading, Error & Empty States
added: flushFields on hub-table: the controls in the cells drawn as a spreadsheet, not as a form. The fields lose their border and surface, a static addon reads as its own content rather than as a chip, and a projected button stops being welded to its neighbour — corners back, a gap, and its own border colour, since two actions in a cell are two things to press. Done by assigning ng-hub-ui-forms tokens to the cells, which is why it reaches your own cell templates; it needs forms 22.21.0 for the seam tokens.
fixed: A group row gets no radio in single selection. The control was drawn on every row, so in a list grouped with `bindChildren` a heading became one of the things to choose — picking a building answered with a building, which nobody can book. Only leaves carry a radio now, which is the single-selection twin of the cascade 22.12.0 gave `multiple`.
changed: BREAKING — `clickFn` hands over the item, not the internal wrapper. `ListClickEvent.item` carried the form group wrapping each row (`{selected, collapsed, data, children}`) while the published type said `item: T`, so a consumer reading `event.item.<field>` by the types got `undefined`: no error, no warning, every guard silently false. It is the item now; `value` reads `bindLabel` from the item rather than from the wrapper, and a new `children: T[]` hands over a group's children as items. Adding an alias and deprecating `item` was rejected: it would leave the library carrying, for ever, a field documented as the item that is not one, to protect code depending on a contradiction between the runtime and the type.
changed: BREAKING — a group row selects its children instead of itself. With `bindChildren`, a group's checkbox put the group's own value into the selection and left its children alone, so ticking a building meant "the building", which nobody can book, and a building with one room chosen looked exactly like one with none. Ticking a group now takes everything under it, a partly-selected group renders indeterminate, and only leaves travel in the value.
fixed: Rebuilding `items` no longer clears the selection, nor claims the user did. The setter emptied the form and published the empty selection through the CVA, so a list that merely re-read its data dropped the choice and told the consumer the user had cleared it, with no way to tell a refresh from an edit. The selection is carried across and matched by `bindValue`, only what the new items no longer offer falls out, and nothing is published unless something really went.
fixed: `setDisabledState` disables. It assigned a flag the template never read, so a disabled list still changed its selection. It now disables the form, reaching every `selected` control however deep — through the form and not a `[disabled]` binding, because Angular ignores that binding on a reactive control: it warns and the box stays live.
fixed: `options.searchable` searches. The component rendered a search box wired to a `filter()` whose body was entirely commented out. It filters now, with a `searchTerm` model and an optional `searchFn` — the same two names `hub-table` uses, so the components do not disagree about what "searchable" means. A group survives while any descendant matches, and submitting returns to the first page.
added: `flush` on `hub-list` and `hub-table`: the collection drawn as a list rather than as a stack of cards. Every row wears its own border, radius and surface by default — right for a collection standing on a page, wrong for a list of choices inside a dialog, where a bordered box per row reads as a region of its own and the surface has already drawn the frame. It had to be an input rather than something CSS can reach, and the reason is a trap the whole token catalogue shares: the defaults are declared on the host, which is the very element a consumer puts a class on, so their assignment ties on specificity and loses on source order — silently, which reads as "the token does nothing". Two tokens come with it, read only under the variant: --hub-list-divider-width and --hub-list-divider-color, the rule that stands in for the gap. It falls between siblings only, a group and the collection it opens keep none, and the cards display gets none at all because a grid separated by rules would draw them across the gaps. On the table the row divider survives on purpose.
fixed: The single-selection radio has a rule. It shipped with the mode in 22.10.0 and had no CSS at all — .hub-list__radio matched nothing in the component — so the control rendered at the browser's own size beside a themed list, visibly not part of it. It now takes --hub-list-radio-size, defaulting to the checkbox's since the two are the same control wearing a different rule about how many may be on, and the list's accent.
fixed: Row-action icons sat low in their buttons. The button took its height from the line box of the glyph, and an icon font glyph is an inline-block resting on the baseline, so a 16px glyph in a 24px line box left the descender gap underneath — 4px above and 8px below on a 28px button. The content row now carries an explicit height and centres the glyph in it: 28px tall, 6/6 exactly. Worth recording that both obvious repairs make it worse — display: flex on the button or the icon host removes the line box that sets the height and collapses it to 20px, and vertical-align: middle overshoots to 7.78/4.22.
changed: Translation lookups now resolve HUBUI.PAGINABLE.* before the legacy flat keys. The table, list and paginator provide the namespace through HUB_TRANSLATION_PREFIX, so an application dictionary can feed them via provideHubTranslationAdapter() without reserving generic top-level keys. Existing flat dictionaries keep working — the bare key is still the fallback.
added: README documentation for the application-wide translation adapter (provideHubTranslationAdapter() from ng-hub-ui-utils).
removed: Removed the @angular/animations peer dependency and the unused table fadeInOut trigger declaration. The package is deprecated upstream and the trigger was never bound in the template. Applications that installed it only for ng-hub-ui-paginable can drop it.
fixed: Documentation links now point at the canonical localized URLs. The README linked to https://hubui.dev/<path> with no locale prefix and no trailing slash, and both forms are 301-redirected, so every reader arriving from npm or GitHub landed on a redirect instead of the canonical page.
added: --hub-table-head-border-width — the header's bottom-border thickness, defaulting to the shared --hub-table-border-width (zero visual change); set it to calc(var(--hub-table-border-width) * 2) for the Bootstrap-style thicker header and it keeps following the base width.
added: --hub-table-head-text-transform (none) and --hub-table-head-letter-spacing (normal) on the header titles — uppercase or tracked column headers without reaching for a th rule.
fixed: Importing the package no longer crashes under SSR: the module-scope navigator access behind DEFAULT_LANGUAGE is now guarded.
removed: Dead internal ViewsService (never exported; its only working method threw 'not developed').
fixed: Table: `[stickyHeader]` now pins the header inside a consumer’s OWN scroll container. The built-in container no longer traps the sticky header (new `--hub-table-container-overflow`, flipped to `visible` when `[stickyHeader]` is set), so a `max-height`/`overflow:auto` box you own keeps the header pinned.
fixed: Table: row/cell background is re-themeable by a plain `hub-table { --hub-table-bg: … }` tag selector (dark mode). The surface tokens are no longer declared on `:host` (which out-ranked the tag rule); each consumption site reads them as `var(--hub-table-bg, <default>)`, so a consumer’s tag rule reaches the cells with NO `!important`, and the sticky header stays opaque via the same fallback.
added: Table: optional selected-row accent bar — `--hub-table-selected-bar-width` (default `0`, no visual change) and `--hub-table-selected-bar-color`. With the `hub-table__row--selected` tint it gives the master-detail “active row” look (tint + leading bar) entirely through tokens and `[rowClass]`. RTL-aware.
added: Table: `[stickyHeader]` input pins the header while the body scrolls, decoupled from the built-in scroll frame — it works inside any consumer `max-height`/`overflow:auto` container. Overridable via `--hub-table-head-position` (default `sticky`).
added: Table: themeable header typography and padding — `--hub-table-head-font-size`, `--hub-table-head-font-weight`, `--hub-table-head-padding-x`, `--hub-table-head-padding-y` (surface/text already existed as `--hub-table-head-bg`/`--hub-table-head-color`). All default to existing values (no visual change).
changed: Table: the selected-row tint now also applies to a consumer-set `hub-table__row--selected` class, so a product can drive the selected look from its own state via `[rowClass]` instead of repainting the row.
added: Table: themeable header, row divider and scroll/sticky-header slots — `--hub-table-head-bg`/`--hub-table-head-color`, `--hub-table-row-divider-color`, and `--hub-table-container-max-block-size`/`--hub-table-head-sticky-top` (a fixed-height scroll body with `options.scrollable` now engages a sticky header). All default to existing values (no visual change).
added: Table: overridable row-expander caret icons via `--hub-table-icon-caret-up`/`--hub-table-icon-caret-down` (same var indirection as the sort icons).
added: List: opt-in item connector (timeline/pipeline) via the `connected` input, themed with `--hub-list-connector-color`/`-width`/`-style`/`-offset`. Default-off, list display only.
fixed: List (cards): long labels no longer overflow their card/grid track — `.hub-list__label` gets `min-width: 0` and wraps unbreakable tokens in cards mode.
added: Table: automatic client-side pagination. With a plain array in `[data]`, `paginate` true and no `totalItems`, the table searches, filters, sorts and slices the data entirely in memory and computes the total itself.
added: App-wide input defaults via `providePaginable({ defaults })` (`PaginableDefaults`): `paginate`, `perPage`, `perPageOptions`, `paginationPosition`, `paginationInfo`, `searchable`, `debounce`. Instance inputs still win; unset keys keep each component default.
changed: Table: the `paginate` input is now functional (previously inert) — it gates the client-side mode. Passing a `PaginationState` or setting `[totalItems]` keeps server mode. Set `[paginate]="false"` to render a full array unpaginated.
added: Agnostic form-controls integration: the table’s search input and rows-per-page select can be rendered by an external library via `provideHubPaginableFormControls()` and the `HUB_PAGINABLE_FORM_CONTROLS` token, with native `<input>` / `<select>` as the zero-dependency fallback.
added: Table: new `[loadingComponent]`, `[errorComponent]` and `[noResultsComponent]` inputs accept a `PaginableStateDefault` (eager component, lazy loader, or descriptor with input factory).
added: List: same `[loadingComponent]`, `[errorComponent]` and `[noResultsComponent]` inputs added to `hub-list`.
added: `providePaginable({ states })` — global app-level defaults for loading, error and no-results states shared across every paginable component.
added: `PaginableStateOutlet` internal outlet renders the resolved state component with the injected context inputs.
added: `PaginableLoadingDirective` (`loadingTpt`) and `PaginableErrorDirective` (`errorTpt`) exported for per-instance template-based state overrides.
changed: List: the BEM block now lives on the host element and the <ul> becomes .hub-list__items; backgrounds are controlled via --hub-list-bg (host) and --hub-list-item-bg (items).
added: List: new --hub-list-gap, --hub-list-items-bg and --hub-list-item-bg CSS variables.
fixed: The list card variables (--hub-list-cards-*) and --hub-paginator-font-size were documented but never applied; they now take effect. CSS variables reference fully synced (EN/ES).
removed: Breaking: renamed list --hub-list-container-* variables and removed the non-functional table --hub-table-breakpoint-* variables.
added: New CSS tokens for cell vertical alignment and icons
changed: Overlay utilities now live in ng-hub-ui-utils for shared dropdown support
fixed: Menu filter match mode labels and null match mode translations
added: Responsive table design for mobile devices
added: Row selection with checkboxes
changed: Performance optimizations for large tables
added: Basic pagination functionality
added: Column sorting capabilities
fixed: Table header alignment issues
ng-hub-ui-paginable is built for server-side data: instead of an array, you give it a function that receives the current page, page size, sort and filters, and returns the matching rows plus the total count. The component keeps the paginator, the sort state and the filters in sync with whatever your API returns.
Mark the columns you want pinned and the header stays visible while the body scrolls. ng-hub-ui-paginable also ships HubStickyColumnsDirective for pinning columns to the start or end of the table, which is what you need for wide tables where the first column identifies the row.
Yes. PaginableTableCellDirective lets you take over the rendering of any column, so a cell can hold badges, buttons, links or a whole component instead of plain text. The column keeps its sorting and filtering behaviour while you control only what is painted.
Declare the filter in the column definition — PaginableTableHeader supports text, dropdown, boolean and range filters per column. The active filters travel to your data source together with the page and sort, so filtering works the same whether the data is local or served by an API.