ComponentsSite blocks

Post tabs

A tabbed category module (“Don’t miss”): the title on a heavy rule, one tab per section at the end, and the tabs that don’t fit folded into a “More” menu — measured against the real width, so it adapts from a wide column to a phone. The selected tab always stays in the row. Panels come from props (server-rendered PostLayout) or from a load callback on first open, cached per tab. WAI-ARIA tabs on the kit Tabs: arrows, Home / End.

Tabs, Dropdown menu blocks/site/post-tabs.tsx, blocks/site/post-modules.tsxtheme · material · accent · density · font

Don’t miss

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 { PostLayout, PostTabs } from "@vamos-ui/react/blocks";

<PostTabs
  title="Don’t miss"
  tabs={sections.map((s) => ({ id: s.id, label: s.label, content: <PostLayout layout="lead-list" posts={s.posts} /> }))}
/>

// Client-side data: panels without content load on first open
<PostTabs title="Lifestyle" tabs={[{ id: "all", label: "All", content: first }, { id: "travel", label: "Travel" }]}
  load={async (id) => <PostLayout layout="lead-list" posts={await fetchSection(id)} />} />

Examples

Lazy panels

The panel shows a card skeleton and aria-busy while load() runs; a failure shows a retry-later line.

Lifestyle

API

PostTabs

PropTypeDefault
title
Module title; names the region and the tab list.
ReactNode—
tabs
content: the panel (usually PostLayout).
{ id; label; content? }[]—
defaultTab / value / onValueChange
Uncontrolled or controlled selection.
string—
load
Loads panels without content, once each.
(id) => Promise<ReactNode>—
maxVisible
Tabs shown before measuring (server render).
number5
loadingFallback
Replaces the card skeleton.
ReactNode—
headingLevel
Title level.
2 | 32
locale / labels
“More”, loading and empty strings (newsLabelsTr).
…—