ComponentsSite blocks

News masthead

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.

Navigation menu, Mobile nav, Dialog blocks/site/news-masthead.tsx, blocks/site/auth-dialog.tsx, blocks/site/post-card.tsx, blocks/site/shared/labels-news.tstheme · material · accent · density · font
13° in Harbourside
The Harbour Ledger

Independent news from the coast since 1987

Installation

$ pnpm add @vamos-ui/react

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.

Kıyıkent 14°

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

PropTypeDefault
date / timeZone
Shown date; default today after hydration.
string (ISO) / string—
weather / loadWeather
{ temp, place, condition?, conditionLabel? }. The adapter runs once on mount.
WeatherData / () => Promise<WeatherData>—
links / social
Utility links (hidden on phones) and social icons (named).
{ label; href }[] / { network; href }[]—
auth
Props for the dialog behind “Sign in / Join”.
AuthDialogProps | false—

NewsHeader

PropTypeDefault
brand / brandLabel / homeHref / tagline
Wordmark (text or inline SVG).
ReactNode / string / string / ReactNode—
aside
Beside the wordmark on wide screens (a leaderboard AdSlot).
ReactNode—
nav
{ label, href, mega?: { id, label, href, posts }[], children? }.
NewsNavItem[]—
more
A final “More” dropdown.
{ label; href }[]—
search
GET search form (Escape closes, focus returns).
{ action; param? } | false{ action: "/search", param: "q" }
sticky / currentPath / mobileFooter
Sticky section bar (default on), aria-current, drawer footer.
boolean / string / ReactNode—

AuthDialog

PropTypeDefault
trigger / open / defaultOpen / onOpenChange
Uncontrolled with a trigger, or controlled.
ReactElement / boolean—
defaultView
View on open.
"signIn" | "recover""signIn"
onSignIn / onRecover
Return a string to show it as the error.
(data) => Promise<void | string>—
signInAction / recoverAction
Plain form posts when there are no handlers.
string—
joinHref / brand
Registration link; publication name above the title.
string / ReactNode—