The rules — the data-list page
- The list page is a FULL-WIDTH lister — no grid, no wrapping card (the lister brings its own frame). The toolbar: filters toggle + selection tools left, the ONE
.btn-primary(New …) right. - Filters live in the collapsible
lister-panel: search on top, then the filter fields, thenhr, then order + page size. Reset clears everything and returns to page 1. - Create/edit opens in an OFFCANVAS (
.offcanvas-end; the form wraps header + body +.offcanvas-footerwith the standard button row) on former — fill, dirty guard, save pipeline,refreshpointed at the lister; former treats the parent offcanvas exactly like a modal. Sizes: default 30rem,.offcanvas-size-sm(20rem),-lg(40rem),-xl(60vw),-full(100vw) — every size clamps to 100vw on mobile. - Delete — single or bulk — stays a MODAL:
g.confirmwithdanger: true, never a hand-built one. - Row markup follows THE COLUMN STANDARD: one flex line (
d-flex align-items-center) holding the data zone.lister-cols— cells sized with thew-*percentage utilities, mobile-first (w-100 w-md-70= stacked on mobile, a 70% column from md; whole columns hide viad-none d-md-block), percentages summing to ≤ 100 per breakpoint. Cells space with padding (pe-3), never flex gap; free text getstext-truncate— a long value truncates, the columns never drift. Cell content is the person-cell pattern (tables) + status badges; secondary fields collapse behindlister-expand. - Buttons get THEIR OWN column:
.lister-actions, fixed width via--lister-actions-won the lister root (size it to the widest action set), present IDENTICALLY on every row — a row without buttons keeps the empty zone, so text never slides under a neighbour's buttons. - Column ALIGNMENT is positional and automatic (from md up): the FIRST column aligns start; BUTTON columns align end (
.lister-actionsright-aligns its content — action buttons and the expand toggle alike); DATA columns CENTER; the LAST data column aligns end ONLY when nothing follows it — with an actions column after (this page), it stays centered; on a list without buttons it right-aligns. The lib detects the actions column from--lister-actions-wby itself — zero authoring. Override per cell with thetext-*utilities only when the page genuinely needs a different alignment. - An OPTIONAL header row (
.lister-headerabove the rows — ONE.lister-colswith the samew-*cells, labels over columns) exists for lists whose cells carry no inline labels; preferable on COMPACT listers (lister shows it), never required. The actions-column width is reserved AUTOMATICALLY from--lister-actions-w— never put a.lister-actionsin the header (double reservation); without the automatic one the last label would right-align at the row edge while its column stops before the buttons. Hide the header below the stacking breakpoint. - Row actions come in THREE shapes (the rows rotate through them here to show all): the inline
.btn-groupof.btn-smicon buttons; the SPLIT dropdown — the primary action + a.dropdown-toggle-splitcaret opening the rest, both.btn-contrast; and the actions-only dropdown — ONE.btn-contrasticon button (ri-more-2-line) opening a menu with ALL the actions. The expand toggle is NEVER part of the group: it is the small round.btn-contrastat the row end (.btn-xs .btn-icon-round— the circle sizes from the size class), separated from the actions. - Keyboard comes free: row shortcuts via
lister-key(e/d/n/f here) and?for the overlay — declare them, do not write key handlers. - Empty, loading and error states are the lister's own — never rebuild them (states).