User
Role
Status
Created
Product
Category
Stock
Price
The rules — the tabbed-data page
- The tab shell is the tabs standard unchanged: pills in the card header, panes as plain card-body content. Putting a lister or a form in a pane changes NOTHING about how it is built — this page exists to show exactly that.
- A pane with a full data list is the data-list composition unchanged — THE STANDARD SHELL (lister.md "Page markup"): the toolbar inside
.lister-mainwith the Filters toggle (icon + word) left and the ONE.btn-primaryright; the collapsiblelister-panelas two cards — Filters (title + thelister-resetReset link + the close button; the search on top, then the filter fields) and Display (order + page size); the list card holding the header and the rows; the count and the pager on the.lister-footerline. SAME filters, SAME search everywhere — every tabbed list in an app reads identically. - The minimal variant is the compact composition: search + order in the toolbar, the list card (the header row + the rows), the footer, no panel — for panes where the list IS the whole story and a filter panel would be noise.
- Rows in a pane are THE STANDARD ROW (lister.md "The standard row"; the reference: the data list): FIT columns (
lister-col-w+lister-col-min, alister-col-priority+lister-col="Label"on each column that may hide — by the LIST's width, so a narrow pane hides them as a phone would),rowClick: 'expand'+lister-more-inset: the card opens the details where the hidden columns land; "Details" (markedlister-expand) rides first in the row's dropdown, or stands as the bare button where it is the row's only action (Products — hidden, its place kept, while nothing hides). No caret at the row end. - Several synced listers, one page: give each its own
urlPrefix(u-/p-here — the prefix is concatenated literally:u-page,p-search) so URL sync never collides. The OPEN TAB itself stays un-synced — the tabs standard: a tab that must deep-link wants to be a page. - Hidden tabs never fetch: a lister outside the active pane gets
autoload: false(here: thelister-autoloadattribute) and loads ONCE on its tab’s firstshown.bs.tab— data the user never opens is never requested. - Side info about the list — pending invitations, hidden-row counts, totals — goes in the lister’s NOTICE STRIP:
[lister-notice]above the rows, a.lister-notice-label+.lister-notice-chipvalues, filled fromlister:loaded. The extras ride the SAME payload as the rows (atypical payloads — never a second fetch), and:emptymeans the strip does not exist — nothing to show needs no page logic. When the info is something AWAITING the user (the pending invitations here), the tab may carry the.badge-countpill from the same payload — the tab-pill law. Page errors/warnings are NOT notices: they stay alerts above the lister. - Form panes follow the settings standard: each pane is its OWN form with its OWN submit — one giant form across tabs stays forbidden. In a real app each form rides former.
- Everything else comes straight from the source patterns when a tabbed list needs it: bulk selection from the data-list page, create/edit in the offcanvas on former (shown here), delete through
g.confirm(shown here).