Components and widgets
The Ui library ships the common building blocks a page needs: tables, cards, tabs, navigation, paging bars and status messages. You compose them the same way as everything else, so a list or a table looks the same in every module and you never rebuild one by hand.
Use the ready-made block, never rebuild it
Before writing markup for a table, a list of cards, or a paging bar, reach for the component that already exists. Each one is a small set of static methods you compose with closures, and each carries the framework's styling, so a component you drop into a new page matches every other page without extra CSS. Reinventing one by hand produces unstyled markup that has to be maintained forever, which is exactly what these blocks exist to avoid.
Tables
UiTable::Header takes the column labels and a closure for the body. Inside
it, UiTable::Row opens a row and the typed cell methods fill it:
UiTable::CellText, UiTable::CellInteger,
UiTable::CellNumber, UiTable::CellBoolean,
UiTable::CellCode and UiTable::CellButton. The typed cells
format their value for you, so a boolean shows as Yes or No and a number is formatted
consistently. If the body adds no rows, the table renders a single "(none)" row on its
own:
UiTable::Header(['Name', 'Price', 'In stock', ''], function() use($products) {
CollectionArray::Each($products, function($product) {
UiTable::Row(function() use($product) {
UiTable::CellText($product->name);
UiTable::CellNumber($product->price);
UiTable::CellBoolean($product->inStock);
UiTable::CellButton($product->editUrl, 'Edit');
});
});
});
Cards
UiCard::List opens a flexible row of cards, and
UiCard::Card renders one from a title, a line of information, a link, and an
optional image URL. The heading level is chosen from the section depth so cards nest
correctly in a page. For a card whose body you want to build yourself,
UiCard::RawCard takes a closure:
UiCard::List(function() use($products) {
CollectionArray::Each($products, function($product) {
UiCard::Card($product->name, $product->summary, $product->url);
});
});
Navigation and tabs
UiNavigation::Menu holds a menu and UiNavigation::Item adds a
navigation item that takes a label, whether it is selected, and its URL. For tabbed
surfaces, UiTabs::Horizontal and UiTabs::Vertical lay out the
tab strip and UiTabs::Tab declares each tab with its label, URL and a
closure for its panel. A tab reads the current URL to know whether it is the selected
one, so you never track selection by hand.
Paging
UiPaging::Bar renders a full paging bar from the current page, the total
number of items, the number per page, and a base URL. It works out the page count,
shows Prev and Next, and collapses a long run of pages with ellipses; if there is only
one page it renders nothing. Because the component owns all of that, a listing page only
has to hand it the counts:
UiPaging::Bar($currentPage, $totalItems, $itemsPerPage, '/shop/products');
Status messages
After a form redirects with a success or error message, StatusUi::Message
renders that message at the top of the page. It reads the outcome from the redirect and
shows a success, error or info banner, and it renders only once per page. Place it near
the top of a page that receives form submissions. How that message is set is covered in
Forms and input.
Where widgets live
These blocks are part of the Ui library because a component used by more than one
module belongs in one shared place, never copied into a leaf module. A dedicated
Widget module exists for larger self-contained widgets built the same way,
for example WidgetSearchUi, WidgetPagingUi and
WidgetTileUi; the rule is identical, compose the provided methods and
extend the library rather than hand-rolling a private copy.
Next: Forms and input.