Patterns

List Screen

The management/list page recipe. Every list page stacks the same way: breadcrumb → action bar → search bar → table. Only the buttons, filters and columns differ.

Source in the MFEs
reference-fe pages/index.tsxPolicyManagement.vuerate-fe Template/index.tsx

List Management Screen

Screen

A full list page: breadcrumb → action bar → search bar → table, ready to adapt.

Download .zip
Install tosrc/pages/<Entity>/Requiresantd@ant-design/iconsapp-breadcrumbapp-action-barapp-search-bar
  • TSXListManagementScreen.tsx
  • MDREADME.md

Anatomy

A list screen is always these four bands, in this order:

  1. 1BreadcrumbAppBreadcrumb — where the user is; hidden on mobile (the header shows the page name instead).
  2. 2Action barAppActionBar — Create / Refresh / Delete, wrapped in two house dividers.
  3. 3Search barAppSearchBar — keyword Input + active filter tags + Add-filter dropdown.
  4. 4TableAntD Table — row selection, a status badge column, a right-fixed action dropdown, and pagination with showTotal.

Live example

A working reference-data list. Select rows to enable Delete; the status column uses the badge classes.

Preview
code: USD
CodeNameStatusUpdated
CURRENCY.USDUS DollarACTIVE2026-06-30
CURRENCY.VNDVietnamese DongACTIVE2026-06-28
UNIT.KGKilogramDRAFT2026-06-21
UNIT.LEGACYDeprecated unitREJECTED2026-05-11
  • 1-4 of 4 items
  • 1
// The fixed stack — breadcrumb → action bar → search bar → table.
// AppActionBar and AppSearchBar own the dividers/spacing; only the contents change.
<Row className="w-100">
  <AppBreadcrumb items={TEMPLATE_BREADCRUMB_ITEMS.management} translate={t} />

  <AppActionBar>
    <Button size="small" onClick={handleCreate} disabled={!canCreate}>
      <i className="fa-solid fa-plus" /> {t('actions.create')}
    </Button>
    <Button size="small" onClick={handleRefresh}>
      <i className="fa-solid fa-sync" /> {t('actions.refresh')}
    </Button>
    <Button size="small" onClick={handleDeleteSelected} disabled={selectedRowKeys.length === 0}>
      <i className="fa-regular fa-trash-can" /> {t('actions.delete')}
    </Button>
  </AppActionBar>

  <AppSearchBar>
    <Input placeholder={t('placeholder.code')} prefix={<SearchOutlined />}
      style={{ minWidth: 280, maxWidth: 520 }} allowClear />
    {/* active filter tags + Add-filter dropdown live here */}
  </AppSearchBar>

  <Table
    rowKey="id"
    columns={columns}
    dataSource={rows}
    loading={loading}
    rowSelection={{ selectedRowKeys, onChange: setSelectedRowKeys }}
    onRow={(record) => ({ onDoubleClick: () => canEdit && navigate(`/edit/${record.id}`) })}
    pagination={{
      current: page, pageSize, total,
      showSizeChanger: true,
      showTotal: (total, range) => `${range[0]}-${range[1]} of ${total} items`,
      pageSizeOptions: ['10', '20', '50', '100'],
    }}
  />
</Row>

Composition

The screen is assembled from the shared pieces documented elsewhere in this kit — the Action bar and Search bar patterns, and the Badge component. Two columns carry most of the house conventions:

Preview
ACTIVEDRAFTREJECTED
// Status column → the badge component (Components → Badge)
{
  title: t('label.status'),
  dataIndex: 'status',
  width: 120,
  render: (status: string) => (
    <span className={`${getStatusClass(status)} badge-rvn`}>{status}</span>
  ),
}

// Action column → ONLY a dropdown, fixed right, ~44px wide
{
  key: 'action', title: '', width: 44, fixed: 'right',
  render: (_t, row) => (
    <Dropdown trigger={['click']} menu={{ items: rowMenu(row) }}>
      <Button type="text" size="small"><MoreOutlined style={{ fontSize: 18 }} /></Button>
    </Dropdown>
  ),
}

Rules

Don't double the dividers
AppActionBar already renders a divider above and below its button row. Don’t add another Divider right before or after it.
Action column = dropdown only
The right-fixed action column holds a single Dropdown + MoreOutlined, ~44px wide. Never scatter inline edit/delete icons in the cell.
Double-click to open
Rows navigate to the edit view on double-click via onRow (React) / customRow (Vue) — after checking the edit permission.