The top of a newspaper. NewsTopBar: today's date, a weather slot (static data or a loadWeather adapter), utility links, “Sign in / Join” opening AuthDialog, social links. NewsHeader: the wordmark row with an optional leaderboard, then a sticky section bar with mega menus — hover or focus a sub-section in the panel and its latest stories swap in — a “More” menu, inline search and, on narrow screens, the kit MobileNav drawer. AuthDialog: reader sign-in with a password-recovery view in the same dialog.
Independent news from the coast since 1987
Installation
The whole kit as one package — get updates by bumping the version. Add the styles to globals.css: @import "@vamos-ui/react/styles.css";
Usage
import { NewsTopBar, NewsHeader, AuthDialog, AdSlot } from "@vamos-ui/react/blocks";
<NewsTopBar weather={{ temp: 14, place: "Harbourside", condition: "partly-cloudy" }}
loadWeather={() => fetch("/api/weather").then((r) => r.json())}
social={[{ network: "x", href: "https://x.com/example" }]}
auth={{ onSignIn, onRecover, joinHref: "/join" }} />
<NewsHeader brand="The Harbour Ledger" aside={<AdSlot size="leaderboard" />}
nav={[{ label: "City", href: "/city", mega: [{ id: "all", label: "All", href: "/city", posts }] }]}
more={[{ label: "Puzzles", href: "/puzzles" }]} />
// Without JavaScript handlers the forms post to URLs
<AuthDialog trigger={<button>Sign in</button>} signInAction="/login" recoverAction="/reset" />Keyboard: Tab through the bar, Enter or ↓ opens a panel, Tab moves into the sub-section list (focus swaps the stories) and on to the stories, Escape closes.
Examples
Phone width, Turkish
The wordmark row hides under 56rem; the section bar keeps a small wordmark and the drawer lists every section with its sub-sections.
Auth dialog
Errors sit on the fields and focus moves to the first invalid one; a returned string becomes the form error (role=alert); switching view focuses its first field; autocomplete hints for password managers.
API
NewsTopBar
| Prop | Type | Default |
|---|---|---|
date / timeZoneShown date; default today after hydration. | string (ISO) / string | — |
weather / loadWeather{ temp, place, condition?, conditionLabel? }. The adapter runs once on mount. | WeatherData / () => Promise<WeatherData> | — |
links / socialUtility links (hidden on phones) and social icons (named). | { label; href }[] / { network; href }[] | — |
authProps for the dialog behind “Sign in / Join”. | AuthDialogProps | false | — |
NewsHeader
| Prop | Type | Default |
|---|---|---|
brand / brandLabel / homeHref / taglineWordmark (text or inline SVG). | ReactNode / string / string / ReactNode | — |
asideBeside the wordmark on wide screens (a leaderboard AdSlot). | ReactNode | — |
nav{ label, href, mega?: { id, label, href, posts }[], children? }. | NewsNavItem[] | — |
moreA final “More” dropdown. | { label; href }[] | — |
searchGET search form (Escape closes, focus returns). | { action; param? } | false | { action: "/search", param: "q" } |
sticky / currentPath / mobileFooterSticky section bar (default on), aria-current, drawer footer. | boolean / string / ReactNode | — |
AuthDialog
| Prop | Type | Default |
|---|---|---|
trigger / open / defaultOpen / onOpenChangeUncontrolled with a trigger, or controlled. | ReactElement / boolean | — |
defaultViewView on open. | "signIn" | "recover" | "signIn" |
onSignIn / onRecoverReturn a string to show it as the error. | (data) => Promise<void | string> | — |
signInAction / recoverActionPlain form posts when there are no handlers. | string | — |
joinHref / brandRegistration link; publication name above the title. | string / ReactNode | — |