Patterns

Action Bar

AppActionBar — the top toolbar for list pages: two house dividers wrapping a space-between Row of small Create / Refresh / Delete buttons, identical across every module.

Source in the MFEs
AppActionBar.tsx (canonical React)AppActionBar.vue (canonical Vue)rate-fe AppActionBar.tsxadministrator-fe AppActionBar.vuerate-fe Template/index.tsxPolicyManagement.vue

AppActionBar

Component

List-page toolbar — two house dividers wrapping a Create / Refresh / Delete row.

Download .zip
Install tosrc/components/common/Requiresantd
  • TSXAppActionBar.tsx
  • MDREADME.md

Live example

The house toolbar: two dividers frame a space-between Row. Create and Refresh group on the left, Delete sits on the right. Buttons are always size="small".

Preview
// React — Template List Page (rate-fe). Place after AppBreadcrumb, before AppSearchBar.
<Row className="w-100">
  <AppBreadcrumb items={TEMPLATE_BREADCRUMB_ITEMS.management} translate={t} />
  <AppActionBar>
    <Button size="small" onClick={() => navigate(PATH_ROUTER.TEMPLATE_CREATE)} className="btn-none-border d-flex align-items-center gap-2 font-size-13">
      <i className="fa-solid fa-plus fs-5" />
      {t('template.actions.create')}
    </Button>
    <Button size="small" onClick={handleDeleteSelected} disabled={selectedRowKeys.length === 0} className="btn-none-border d-flex align-items-center gap-2 font-size-13">
      <i className="fa-regular fa-trash-can fs-6" />
      {t('template.actions.delete')}
    </Button>
  </AppActionBar>

Component

One tiny component ships identically in every React MFE (rate-fe, reference-fe, racar-fe, report-fe) and as a Vue equivalent in administrator-fe. The two Dividers and the Row are the whole thing — callers only supply buttons.

Preview
import { Divider, Row } from 'antd';
import type { ReactNode } from 'react';

type RowJustify = 'start' | 'end' | 'center' | 'space-around' | 'space-between' | 'space-evenly';

type AppActionBarProps = {
  children: ReactNode;
  /** Row justify. Defaults to the house 'space-between'. */
  justify?: RowJustify;
  /** Horizontal gap between the buttons in the bar. */
  gap?: number | string;
};

const AppActionBar = ({ children, justify = 'space-between', gap = '10px' }: AppActionBarProps) => (
  <>
    <Divider className="mt-0 mb-0" />
    <Row justify={justify} style={{ gap }}>
      {children}
    </Row>
    <Divider className="mt-0 mb-2" />
  </>
);

export default AppActionBar;

Props

NameTypeDefaultDescription
childrenReactNodeReact: the buttons / action elements to display. In the Vue version this is the default <slot />.
justifyRowJustify'space-between'AntD Row justify. Keep the house 'space-between', use 'start' to anchor all buttons left, or wrap groups in Space/div for a left/right split.
gapnumber | string'10px'Horizontal spacing between buttons, set on the Row style. React takes a number or string; the Vue version takes a number and appends px automatically (default 10).

Usage

Place AppActionBar immediately after AppBreadcrumb and before AppSearchBar on a list page. For a left/right split, wrap each button group in its own Space/div — the space-between justify does the rest. To anchor everything left instead, pass justify="start".

Preview
// Left/right split — wrap each group; space-between pushes them apart.
<AppActionBar>
  <Space size={10}>
    <Button size="small" icon={<PlusOutlined />}>Create</Button>
    <Button size="small" icon={<ReloadOutlined />}>Refresh</Button>
  </Space>
  <Button size="small" danger icon={<DeleteOutlined />}>Delete</Button>
</AppActionBar>

// All buttons anchored left — pass justify="start".
<AppActionBar justify="start">
  <Button size="small" icon={<PlusOutlined />}>Create</Button>
  <Button size="small" icon={<ReloadOutlined />}>Refresh</Button>
</AppActionBar>

Rules

Don't double the dividers
AppActionBar already renders a Divider above and below its button row (mt-0 mb-0 on top, mt-0 mb-2 on the bottom). Never add another Divider right before or after it, and never override those margin classes — they are the spacing contract.
Buttons stay small and borderless
Every action uses size="small" with btn-none-border d-flex align-items-center gap-2 font-size-13, so the bar reads the same everywhere. Use danger for Delete.
gap controls spacing, not the split
The gap prop only sets the distance between buttons. To create a left/right split, group the buttons — don’t reach for gap. Never set custom margin or padding on the Row or Dividers.