Global Banners
Relevant source files
The following files were used as context for generating this wiki page:The Global Banners feature provides a system for displaying site-wide, dismissible announcements. It is designed to show the oldest, unviewed banner to a user and persist the dismissed state across sessions using the browser's local storage.
The system is composed of a React component, GlobalBanners, and a corresponding hook, useGlobalBanners, which manages the logic for banner visibility and state. It is distinct from other banner types like PriorityBoardingBanner or DeprecationBanner which are embedded directly within MDX content.
Sources: src/components/GlobalBanner.tsx, src/hooks/useGlobalBanners.tsx, src/pages/[...slug].tsx:1,18
Architecture Overview
The feature's architecture revolves around three main parts: the useGlobalBanners hook for logic, the GlobalBanners component for rendering, and the generic Banner component for the UI. State persistence is handled by the use-local-storage-state library.
The following diagram illustrates the component and hook relationships.
Core Logic: useGlobalBanners Hook
The useGlobalBanners hook is the brain of the system. It determines which banner, if any, should be displayed and provides a function to dismiss it.
Sources: src/hooks/useGlobalBanners.tsx
Data Structures
The hook defines the GlobalBanner interface for banner objects.
| Property | Type | Description |
|---|---|---|
id | string | A unique identifier for the banner. |
message | string | React.ReactElement | The content to be displayed within the banner. |
variant | BannerVariant | (Optional) The visual style of the banner. |
Sources: src/hooks/useGlobalBanners.tsx:8-12
Banner Definition
Banners are defined in a static array named allGlobalBanners. This array is the single source of truth for all possible global banners. The system displays banners in the order they appear in this array. As of the current implementation, this array is empty, meaning no global banners will be shown.
Sources: src/hooks/useGlobalBanners.tsx:37-42
State Management and Persistence
The hook uses use-local-storage-state to keep track of which banners a user has dismissed.
- Local Storage Key:
@railway/globalBanners - Data Format: A JSON object where keys are banner
ids and values are booleans (trueif dismissed).Record<string, boolean>
The dismissGlobalBanner function updates this state in local storage by adding the banner's id to the record.
Sources: src/hooks/useGlobalBanners.tsx:31-33, 47-52
Banner Selection Logic
The currentBanner is calculated using useMemo. The logic filters out banners that have already been viewed (i.e., their id exists in local storage) and returns the first banner from the remaining list. If all banners have been viewed, it returns null.
This flow ensures that users see the oldest available banner they haven't dismissed yet.
Sources: src/hooks/useGlobalBanners.tsx:55-65
UI Component: GlobalBanners
This component is responsible for rendering the currently active global banner.
Sources: src/components/GlobalBanner.tsx
Rendering Flow
The GlobalBanners component follows a simple rendering logic:
- It calls the
useGlobalBannershook to get thecurrentBannerand thedismissGlobalBannerfunction. - If
currentBannerisnull, the component renders nothing. - If a banner is available, it renders the generic
Bannercomponent, passing the message and variant. - It adds a dismiss button (
<X>) with anonClickhandler that callsdismissGlobalBannerwith the current banner'sid.
The following sequence diagram shows the interaction when a user dismisses a banner.
Sources: src/components/GlobalBanner.tsx:8-26
Code Snippet: Component Implementation
// src/components/GlobalBanner.tsx
export const GlobalBanners = () => {
const { currentBanner, dismissGlobalBanner } = useGlobalBanners();
if (currentBanner == null) return null;
return (
<Banner
variant={currentBanner.variant}
tw="rounded-none"
textContainerStyles={tw`relative w-full flex justify-center`}
>
<p>{currentBanner.message}</p>
<button
type="button"
title="Dismiss"
css={[
tw`absolute top-3 right-0`,
tw`focus:outline-none text-gray-500 hover:text-gray-700`,
]}
onClick={() => dismissGlobalBanner(currentBanner.id)}
>
<X tw="h-5 w-5" />
</button>
</Banner>
);
};
Sources: src/components/GlobalBanner.tsx:7-27
Other Banner Implementations
It is important to note that the documentation site also uses other banner components, such as Banner, PriorityBoardingBanner, and DeprecationBanner. These are not part of the GlobalBanners system. Instead, they are imported and made available to the MDX renderer, allowing them to be used directly within the content of markdown pages.
Sources: src/pages/dynamic/[...slug].tsx:1,16, src/pages/[...slug].tsx:1,18