Components
Breadcrumb
AppBreadcrumb — the AntD breadcrumb trail at the top of every page: prior crumbs link back, the current page renders in primary text, a Divider follows it, and both hide on mobile where the header shows the page name instead.
AppBreadcrumb
ComponentPage breadcrumb with i18n keys, priority ordering, and a mobile page-title broadcast.
src/components/Requiresantdreact-router-domLive example
The trail sits at the very top of the page inside .app-breadcrumb. Prior crumbs are clickable links; the last crumb (the current page) is plain text coloured text-primary. A Divider with mt-1 mb-1 always follows it, separating the trail from the page content.
// Usage in rate-fe/src/pages/Dashboard/index.tsx
<div className="w-100">
<AppBreadcrumb items={breadcrumbItems} translate={t} />
<Divider className="mt-1 mb-1" />
<Space direction="vertical" size={16} style={{ width: '100%' }}>
...content
</Space>
</div>With close button (showBack)
Edit / create / view pages pass showBack — a CloseOutlined icon trails the breadcrumb on the right and calls navigate(-1).
Component
AppBreadcrumb ships per module: rate-fe is the canonical React version; reference-fe and report-fe carry near-identical copies; administrator-fe has the Vue equivalent. Items are sorted by their optional priority, and the last crumb’s label is broadcast on rvn-active-page-title so the header can show it on mobile.
// React: rate-fe/src/components/AppBreadcrumb/index.tsx (canonical)
import { Breadcrumb } from 'antd';
import { CloseOutlined } from '@ant-design/icons';
import { useEffect, useMemo } from 'react';
import { Link, useNavigate } from 'react-router-dom';
import { emitMessage } from '@/hooks/useMessageBus';
interface AppBreadcrumbProps {
items: BreadcrumbItem[];
translate?: (key: string) => string;
showBack?: boolean;
}
const AppBreadcrumb = ({ items, translate, showBack = false }: AppBreadcrumbProps) => {
const navigate = useNavigate();
const orderedItems = useMemo(() => {
return items.map((item, index) => ({ ...item, __index: index })).sort((a, b) => (a.priority ?? a.__index) - (b.priority ?? b.__index));
}, [items]);
const handleBack = () => navigate(-1);
// Broadcast current page name (last crumb) to header, shown on mobile where breadcrumb is hidden
const activeTitle = orderedItems.length ? resolveLabel(orderedItems[orderedItems.length - 1], translate) : '';
useEffect(() => {
emitMessage('rvn-active-page-title', { title: activeTitle });
}, [activeTitle]);
return (
<div className="app-breadcrumb d-flex align-items-center mb-2 w-100">
<Breadcrumb>
{orderedItems.map((item, index) => {
const label = resolveLabel(item, translate);
const isLast = index === orderedItems.length - 1;
return (
<Breadcrumb.Item key={`${label}-${index}`}>
{item.to && !isLast ? (
<Link to={item.to}>{label}</Link>
) : (
<span className={isLast ? 'text-primary' : undefined}>{label}</span>
)}
</Breadcrumb.Item>
);
})}
</Breadcrumb>
{showBack && (
<CloseOutlined
onClick={handleBack}
className="cursor-pointer text-secondary ms-auto fw-bold"
style={{ marginRight: 12, fontWeight: 'bold' }}
/>
)}
</div>
);
};Props
| Name | Type | Default | Description |
|---|---|---|---|
items | BreadcrumbItem[] | — | The crumbs — each has label, labelKey, to and an optional priority used to reorder the trail. Defined per page in each module under constants/breadcrumb.ts. |
translate | (key: string) => string | — | Optional i18n function; labelKey is resolved through it, falling back to the raw label. |
showBack | boolean | false | Shows the CloseOutlined button on the right (edit/create/view pages). Clicking calls navigate(-1). |
app-breadcrumb | class | — | Base class on the wrapper div — the hook for mobile visibility control and the rate-reference-host exception. |
Mobile behaviour
Below md (max-width 767.98px) the breadcrumb is hidden entirely — the header displays the current page name instead, fed by the rvn-active-page-title broadcast. The Divider that follows the breadcrumb must be hidden in the same media query. The one exception is the rate reference-data embedded page: .rate-reference-host .app-breadcrumb stays visible on mobile via a higher-specificity override.
/* rate-fe/src/assets/scss/layout.scss — .app-breadcrumb visibility */
/* Mobile (max-width: 767.98px): hide the breadcrumb — and the Divider
that follows it — together. The header shows the page name instead. */
@media (max-width: 767.98px) {
.app-breadcrumb {
display: none;
}
}
/* Exception: the rate reference-data embedded page keeps it visible on mobile.
The higher-specificity selector beats the @media hide. */
.rate-reference-host .app-breadcrumb {
display: block;
}Notes
<AppBreadcrumb /> and before the page content, and it must be hidden together with the breadcrumb in the mobile media query — forgetting it leaves an orphaned separator at the top of the page on mobile.rvn-active-page-title so header-fe can show the page name on mobile. rate-fe and administrator-fe emit via the useMessageBus hook (emitMessage); reference-fe dispatches a CustomEvent on window.Breadcrumb.tsx that auto-generates the trail from the route. It does not accept a generic items array and does not broadcast the page title — it is not part of the AppBreadcrumb pattern.