Components
Header
The 40px fixed top app bar from header-fe, exposed as the MFE remote rvn_mfe_header/Header — brand-blue bar with hamburger and app/page title on the left, language selector, notifications and user menu on the right.
Live example
A representative mock of the bar: 40px tall, background hsl(212, 94%, 42%) (#0664d0), white text. Hamburger + grid icon + app title on the left, a reserved centre slot, and the user menu (Avatar + Popover) on the right. In production it is position: fixed with z-index: 1000; here it sits inline so it fits the preview.
<RemoteMicroHeader
title="Raffles Data & Analytics"
user={user}
/>
<!-- In appshell-fe/src/App.tsx: -->
const RemoteMicroHeader = React.lazy(() => import('rvn_mfe_header/Header'));
{isAuthenticated ? (
<>
<Suspense fallback={<Skeleton active />}>
<RemoteMicroHeader title="Raffles Data & Analytics" user={user} />
<div style={{ height: '40px' }}></div> {/* padding for fixed header */}
</Suspense>
<Shell />
</>
) : null}Markup
The real component from header-fe. Three zones: .header-left-group (hamburger, grid icon, title), a flexible centre reserved for search/actions (max-width 500px), and a right Space holding the extra slot, language selector, the Connect-only notification bell and the user menu.
// Header component (lines 41-478 of header-fe/src/components/Header.tsx)
const Header: React.FC<HeaderProps> = ({ className, title = 'Micro Header', extra, user }) => {
const [pageTitle, setPageTitle] = useState('');
useMessageBus<{ title?: string }>(KEY_MESSAGE_BUS.activePageTitle, (payload) =>
setPageTitle(payload?.title ?? '')
);
return (
<div
className={clsx('rvn-header-bg text-white d-flex justify-content-between align-items-center px-2 py-1 fixed-header', className)}
style={{
height: '40px',
position: 'fixed',
zIndex: 1000,
width: '100%',
}}
>
{/* LEFT: hamburger + grid icon + title */}
<div style={{ display: 'flex', alignItems: 'center' }} className="header-left-group">
<Button type="text" className="text-white header-module-menu-toggle"
icon={<MenuOutlined className="text-white" />}
onClick={handleOpenModuleMenu} />
<ProductOutlined className="text-white header-module-menu-toggle-app"
style={{ fontSize: 16, cursor: 'pointer' }}
onClick={handleDispatchEventDrawer} />
<span className="font-size-13 header-app-title" onClick={() =>
emitMessage(KEY_MESSAGE_BUS.navigateHome, {})}>
{title}
</span>
</div>
{/* CENTER: reserved for search/actions */}
<div style={{ flex: 1, maxWidth: 500 }} className="mx-2">
<Flex gap={5}>{/* reserved */}</Flex>
</div>
{/* RIGHT: language, notification, user menu */}
<Space size="middle">
{extra}
<LanguageSelector />
{isConnectPlatform ? <NotificationBell user={user} /> : null}
<Popover content={userMenu} placement="bottomRight" overlayStyle={{ borderRadius: 8 }}>
<Flex style={{ cursor: 'pointer' }}>
<Avatar style={{ backgroundColor: '#1890ff' }}>
{user?.email ? user.email.charAt(0).toUpperCase() : 'R'}
</Avatar>
<div className="d-flex flex-column ms-2 text-white">
<span style={{ fontSize: 12 }}>{user?.email}</span>
<span style={{ fontSize: 10 }}>RAFFLES VN CO. LTD</span>
</div>
</Flex>
</Popover>
</Space>
</div>
);
};SCSS
The bar’s styling lives in header-fe/src/assets/scss/index.scss. Desktop shows the static app title with a 9px left inset; the mobile media query swaps the title for the broadcast page name and reveals the hamburger.
// SCSS (header-fe/src/assets/scss/index.scss)
$banner-rvn-bg: hsl(212, 94%, 42%); // #0664d0
$banner-rvn-fg: hsl(212, 0%, 100%); // white
.fixed-header {
position: fixed !important;
top: 0;
left: 0;
right: 0;
z-index: 1000;
}
.rvn-header-bg {
background-color: $banner-rvn-bg !important;
}
.rvn-header-bg .header-left-group {
padding-left: 9px; // Desktop inset
}
.header-module-menu-toggle,
.header-page-title {
display: none; // Hidden on desktop
}
@media (max-width: 767.98px) {
.header-app-title {
display: none; // Show page title instead
}
.header-module-menu-toggle {
display: inline-flex; // Show hamburger
}
.header-page-title {
display: inline;
}
.rvn-header-bg .header-left-group {
padding-left: 0 !important;
margin-left: -8px !important;
}
}Props
| Name | Type | Default | Description |
|---|---|---|---|
title | string | 'Micro Header' | App name shown on desktop — appshell passes "Raffles Data & Analytics". Clicking it emits KEY_MESSAGE_BUS.navigateHome. On mobile the broadcast page title replaces it. |
user | HeaderUser | — | User object with id, email, username, firstName, lastName, groups. Drives the avatar initial, the email line and the notification bell. |
className | string | — | Optional extra CSS classes merged onto the bar via clsx. |
extra | React.ReactNode | — | Optional content slot rendered in the right group, before the language selector. |
Classes
| Name | Type | Default | Description |
|---|---|---|---|
fixed-header | class | — | position: fixed at the top, full width, z-index 1000. |
rvn-header-bg | class | — | Brand background — $banner-rvn-bg: hsl(212, 94%, 42%) (#0664d0), white foreground. |
header-left-group | class | — | Left zone wrapper. 9px left padding on desktop; the mobile query removes it and pulls the group left by 8px. |
header-app-title | class | — | Static app title, font-size-13. Visible on desktop, hidden below 768px. |
header-page-title | class | — | The active page name (from the rvn-active-page-title broadcast). Hidden on desktop, shown on mobile in place of the app title. |
header-module-menu-toggle | class | — | The hamburger Button. Hidden on desktop, inline-flex below 768px — opens the module menu. |
header-content .page-title | class | — | The page heading rendered in the content area below the bar: 20px, weight 600, colour #323130. |
Mobile behaviour
Below 768px the bar changes role: the static app title (.header-app-title) is hidden and the current page name (.header-page-title) shows instead, fed by the modules’ breadcrumb broadcast on KEY_MESSAGE_BUS.activePageTitle — the in-content breadcrumb is hidden at the same breakpoint. The hamburger (.header-module-menu-toggle) appears to open the module menu. The grid icon (ProductOutlined, 16px) stays visible on all sizes and triggers the app drawer.
rvn-active-page-title contract (see Components → Breadcrumb).Notes
position: fixed and 40px tall. The parent layout must render a <div style={{ height: '40px' }}/> immediately after it (as appshell does) or the page content slides underneath.rvn_mfe_header/Header via Module Federation; appshell-fe consumes it with React.lazy(() => import('rvn_mfe_header/Header')) inside a Suspense boundary.REACT_APP_PLATFORM); HUB builds omit it. The user menu Popover opens bottomRight and currently contains Logout only.z-index: 1000. Drawers, modals and dropdowns from remote modules can collide with it if their z-indexes are not scoped — check stacking when adding overlays near the top of the viewport.